refactor(phase5): Comprehensive stabilisation pass. De-duplicated App/Controller state, hardened session reset, and updated integration tests with deterministic polling.

This commit is contained in:
2026-05-09 16:55:45 -04:00
parent d1cc019640
commit b958fa2819
16 changed files with 351 additions and 383 deletions
+57 -67
View File
@@ -1,131 +1,121 @@
import pytest
import time
import sys
import os
import json
from pathlib import Path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src")))
from src import api_hook_client
from src.api_hook_client import ApiHookClient
@pytest.mark.integration
def test_undo_redo_lifecycle(live_gui):
client = api_hook_client.ApiHookClient()
assert client.wait_for_server(timeout=15), "Hook server did not start"
client = ApiHookClient()
client.click("btn_reset")
time.sleep(2)
assert client.wait_for_server(timeout=15), "Hook server did not start"
# 1. Set initial state
print("Setting initial state...")
client.set_value('temperature', 0.5)
client.set_value('ai_input', "Initial Input")
# Wait for settle and first push (S_init -> S0)
time.sleep(3.0)
time.sleep(3.0)
# 2. Change state
print("Modifying state...")
client.set_value('temperature', 1.5)
client.set_value('ai_input', "Modified Input")
# Wait for settle and second push (S0 -> S1)
time.sleep(3.0)
# Verify current state
temp = client.get_value('temperature')
ai_in = client.get_value('ai_input')
print(f"Current state: temp={temp}, ai_input={ai_in}")
assert temp == 1.5
assert ai_in == "Modified Input"
# 3. Undo
# 3. Undo (S1 -> S0)
print("Sending Undo...")
client.click('btn_undo')
time.sleep(2.0)
# Wait for state to revert
time.sleep(1.0)
ai_in_undo = client.get_value('ai_input')
temp_undo = client.get_value('temperature')
print(f"After undo: ai_input={ai_in_undo}, temp={temp_undo}")
assert ai_in_undo == "Initial Input"
assert temp_undo == 0.5
# 4. Redo
assert client.get_value('ai_input') == "Initial Input"
assert client.get_value('temperature') == 0.5
# 4. Redo (S0 -> S1)
print("Sending Redo...")
client.click('btn_redo')
time.sleep(1.0)
time.sleep(2.0)
ai_in_redo = client.get_value('ai_input')
temp_redo = client.get_value('temperature')
print(f"After redo: ai_input={ai_in_redo}, temp={temp_redo}")
assert ai_in_redo == "Modified Input"
assert temp_redo == 1.5
print("Undo/Redo basic lifecycle PASSED.")
assert client.get_value('ai_input') == "Modified Input"
assert client.get_value('temperature') == 1.5
@pytest.mark.integration
def test_undo_redo_discussion_mutation(live_gui):
client = api_hook_client.ApiHookClient()
assert client.wait_for_server(timeout=15)
client = ApiHookClient()
client.click("btn_reset")
time.sleep(2)
assert client.wait_for_server(timeout=15)
# Get initial entries count
initial_entries = client.get_value('disc_entries')
initial_count = len(initial_entries)
print(f"Initial entries: {initial_count}")
# 1. Add an entry (we simulate this by appending to disc_entries)
# Wait for settle
time.sleep(2.0)
new_entries = initial_entries + [{"role": "User", "content": "New Entry", "collapsed": False, "ts": "2026-03-11 12:00:00"}]
client.set_value('disc_entries', new_entries)
# Wait for debounce
time.sleep(2.0)
assert len(client.get_value('disc_entries')) == initial_count + 1
# 2. Undo addition
# 2. Undo the addition
print("Undoing entry addition...")
client.click('btn_undo')
time.sleep(0.5)
time.sleep(2.0)
assert len(client.get_value('disc_entries')) == initial_count
# 3. Redo addition
# 3. Redo the addition
print("Redoing entry addition...")
client.click('btn_redo')
time.sleep(0.5)
time.sleep(2.0)
assert len(client.get_value('disc_entries')) == initial_count + 1
print("Undo/Redo discussion mutation PASSED.")
@pytest.mark.integration
def test_undo_redo_context_mutation(live_gui):
client = api_hook_client.ApiHookClient()
client = ApiHookClient()
client.click("btn_reset")
time.sleep(2)
assert client.wait_for_server(timeout=15)
# Wait for settle
time.sleep(2.0)
# Get initial files
initial_files = client.get_value('ui_file_paths')
initial_count = len(initial_files)
# 1. Add a file
client.set_value('ui_file_paths', ['test_undo.py'])
# Wait for debounce
time.sleep(2.0)
assert 'test_undo.py' in client.get_value('ui_file_paths')
new_files = initial_files + ["test_undo.py"]
client.set_value('ui_file_paths', new_files)
time.sleep(2.0)
assert len(client.get_value('ui_file_paths')) == initial_count + 1
assert "test_undo.py" in client.get_value('ui_file_paths')
# 2. Undo addition
print("Undoing file addition...")
client.click('btn_undo')
time.sleep(0.5)
assert 'test_undo.py' not in client.get_value('ui_file_paths')
time.sleep(2.0)
assert len(client.get_value('ui_file_paths')) == initial_count
assert "test_undo.py" not in client.get_value('ui_file_paths')
# 3. Redo addition
print("Redoing file addition...")
client.click('btn_redo')
time.sleep(0.5)
assert 'test_undo.py' in client.get_value('ui_file_paths')
print("Undo/Redo context mutation PASSED.")
time.sleep(2.0)
assert len(client.get_value('ui_file_paths')) == initial_count + 1
assert "test_undo.py" in client.get_value('ui_file_paths')