Files
manual_slop/tests/test_external_editor_gui.py
T

281 lines
7.8 KiB
Python

"""Integration tests for external editor GUI functionality."""
import pytest
import time
import sys
import os
import tempfile
import subprocess
from pathlib import Path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from src import api_hook_client
def get_vscode_processes():
try:
result = subprocess.run(
["powershell", "-Command", "Get-Process Code* -ErrorAction SilentlyContinue | Format-Table -AutoSize"],
capture_output=True, text=True, timeout=5
)
return result.stdout
except:
return ""
@pytest.fixture
def test_external_editor_config():
return {
"ai": {"provider": "gemini", "model": "gemini-2.5-flash-lite"},
"projects": {"paths": [], "active": ""},
"paths": {"logs_dir": "logs", "scripts_dir": "scripts"},
"tools": {
"text_editors": {
"vscode": {
"path": "C:\\apps\\Microsoft VS Code\\Code.exe",
"diff_args": ["--new-window", "--diff"]
}
},
"default_editor": {"default_editor": "vscode"}
}
}
@pytest.mark.integration
@pytest.mark.timeout(120)
def test_vscode_launches_with_diff_view(live_gui):
"""Test that clicking external editor button launches VSCode."""
proc, _ = live_gui
client = api_hook_client.ApiHookClient()
if not client.wait_for_server(timeout=15):
pytest.skip("GUI server not available")
subprocess.run(
["powershell", "-Command", "Stop-Process -Name 'Code*' -Force -ErrorAction SilentlyContinue"],
timeout=10
)
time.sleep(1)
before = get_vscode_processes()
print(f"\n=== VSCODE LAUNCH TEST ===")
print(f"VSCode before:\n{before if before.strip() else 'not running'}")
sample_patch = """--- a/test.py
+++ b/test.py
@@ -1,2 +1,3 @@
HELLO_WORLD = "original"
-HELLO_WORLD = "modified"
+HELLO_WORLD = "changed"
+NEW_LINE = "added"
def main():
pass"""
client.push_event("show_patch_modal", {
"patch_text": sample_patch,
"file_paths": ["test.py"]
})
time.sleep(2)
state = client.get_gui_state()
print(f"Patch modal visible: {state.get('_show_patch_modal')}")
print("Clicking 'Open in External Editor' button...")
result = client.click("btn_open_external_editor")
print(f"Click API result: {result}")
time.sleep(1)
state_after = client.get_gui_state()
error_msg = state_after.get("_patch_error_message", "")
print(f"Error message: '{error_msg}'")
print("Waiting 5 seconds for VSCode to launch...")
time.sleep(5)
after = get_vscode_processes()
print(f"VSCode after:\n{after if after.strip() else 'not running'}")
client.push_event("hide_patch_modal", {})
time.sleep(1)
@pytest.mark.integration
@pytest.mark.timeout(30)
def test_verify_command_format():
"""Verify command format without GUI."""
from src.external_editor import ExternalEditorLauncher, ExternalEditorConfig, TextEditorConfig
config = ExternalEditorConfig(
editors={
"vscode": TextEditorConfig(
name="vscode",
path="C:\\apps\\Microsoft VS Code\\Code.exe",
diff_args=["--new-window", "--diff"]
)
},
default_editor="vscode"
)
launcher = ExternalEditorLauncher(config)
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False, encoding="utf-8") as f:
f.write("original\n")
orig = f.name
with tempfile.NamedTemporaryFile(mode="w", suffix="_modified.txt", delete=False, encoding="utf-8") as f:
f.write("modified\n")
mod = f.name
try:
cmd = launcher.build_diff_command(
launcher.config.editors["vscode"],
orig,
mod
)
print(f"\nCommand: {cmd}")
assert "--diff" in cmd
assert "--new-window" in cmd
assert "Code.exe" in cmd[0]
print("Format: CORRECT")
finally:
os.unlink(orig)
os.unlink(mod)
@pytest.mark.integration
@pytest.mark.timeout(120)
def test_patch_modal_shows_with_configured_editor(live_gui, monkeypatch):
"""Test that when external editor is configured, the patch modal shows properly."""
proc, _ = live_gui
client = api_hook_client.ApiHookClient()
if not client.wait_for_server(timeout=15):
pytest.skip("GUI server not available")
import src.models as models_module
monkeypatch.setattr(models_module, 'load_config', lambda: test_external_editor_config())
sample_patch = """--- a/test.py
+++ b/test.py
@@ -1,2 +1,3 @@
HELLO_WORLD = "original"
-HELLO_WORLD = "modified"
+HELLO_WORLD = "changed"
+NEW_LINE = "added"
def main():
pass"""
client.push_event("show_patch_modal", {
"patch_text": sample_patch,
"file_paths": ["test.py"]
})
time.sleep(2)
state = client.get_gui_state()
assert state.get("_show_patch_modal") == True
print("\n=== PATCH MODAL TEST ===")
print("Patch modal visible with external editor config")
print("===================")
client.push_event("hide_patch_modal", {})
time.sleep(1)
@pytest.mark.integration
@pytest.mark.timeout(120)
def test_button_click_is_received(live_gui, monkeypatch):
"""Test that btn_open_external_editor button click is received."""
proc, _ = live_gui
client = api_hook_client.ApiHookClient()
if not client.wait_for_server(timeout=15):
pytest.skip("GUI server not available")
import src.models as models_module
monkeypatch.setattr(models_module, 'load_config', lambda: test_external_editor_config())
sample_patch = """--- a/test.py
+++ b/test.py
@@ -1,2 +1,3 @@
HELLO_WORLD = "original"
-HELLO_WORLD = "modified"
+HELLO_WORLD = "changed"
def main():
pass"""
client.push_event("show_patch_modal", {
"patch_text": sample_patch,
"file_paths": ["test.py"]
})
time.sleep(2)
state = client.get_gui_state()
assert state.get("_show_patch_modal") == True
print("\n=== BUTTON CLICK TEST ===")
print("Sending client.click('btn_open_external_editor')...")
client.click("btn_open_external_editor")
time.sleep(2)
state = client.get_gui_state()
error = state.get("_patch_error_message", "")
print(f"Error after click: '{error}'")
print("Button click sent.")
print("===================")
client.push_event("hide_patch_modal", {})
time.sleep(1)
@pytest.mark.integration
@pytest.mark.timeout(30)
def test_verify_vscode_command_format():
"""Direct verification of VSCode command format."""
from src.external_editor import ExternalEditorLauncher, ExternalEditorConfig, TextEditorConfig
config = ExternalEditorConfig(
editors={
"vscode": TextEditorConfig(
name="vscode",
path="C:\\apps\\Microsoft VS Code\\Code.exe",
diff_args=["--new-window", "--diff"]
)
},
default_editor="vscode"
)
launcher = ExternalEditorLauncher(config)
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False, encoding="utf-8") as f:
f.write("original\n")
orig = f.name
with tempfile.NamedTemporaryFile(mode="w", suffix="_modified.txt", delete=False, encoding="utf-8") as f:
f.write("modified\n")
mod = f.name
try:
cmd = launcher.build_diff_command(
launcher.config.editors["vscode"],
orig,
mod
)
print(f"\n=== COMMAND FORMAT ===")
print(f"Launches: {cmd[0]}")
print(f"Args: {cmd[1:]}")
assert "--diff" in cmd
assert "--new-window" in cmd
assert "Code.exe" in cmd[0]
print("Format: CORRECT")
print("==================")
finally:
os.unlink(orig)
os.unlink(mod)
if __name__ == "__main__":
pytest.main([__file__, "-v", "-s"])