76c530a9e5
Suite went from 27 failures plus one permanent hang (never finished) to 1846 passed / 0 failed in ~85s, including under FORCE_COLOR. - office_shutdown_lifecycle: construct WSHandler via the real __init__ (helper) instead of hand-copied __new__ stubs that drift from the constructor (#11 added _runtime_status_sync_task and the stubs hung); the formerly-hanging wait now has a 5s wait_for. - import-time patch hygiene: company_recruiter / company_reorg / engine_session_defaults replaced module-level permanent tempfile.TemporaryDirectory monkeypatching with paired setUpModule/tearDownModule, fixing order-dependent sqlite failures in transcript_pagination during full runs. - stale tests updated to current product semantics: resume stubs use status="done" (failed is deliberately non-resumable), fix4 asserts the native review contract through build_company_work_item_contract, delivery fixture carries user_visible/feedback_scope=final, ownership doc names progress_log, session compression calls maybe_compact_session(force=True) explicitly, hard delete removes the work item row, parallel-isolation asserts delegate rebind and stubs _get_project_delegate, role update goes through OrgService on an editable custom org (plus read-only rejection case), collab_rpc patches the single os.name decision point instead of poisoning pathlib, codex no-pty builds inside the patch, identity-guard false positives reworded. - cli_board actions rewritten against the real OfficeServiceFactory seam with a tempdir OPC_HOME (old direct-engine stubs were never consulted and the tests wrote into the real OPC home). - cli_app assertions strip ANSI via _plain_output so a color-forcing shell (FORCE_COLOR) cannot break plain-text expectations. - deleted never-runnable test_org_concurrency (pytest.mark.asyncio without the plugin, stdlib-only assertions) and three dead skipped filesystem-handoff tests. - pyproject: dev extra (pytest, pytest-timeout) and a 300s per-test timeout backstop so a wedged test fails instead of stalling the suite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
from opc.plugins.cli_board.state.models import BoardSnapshot, BoardTaskView, TaskDetailView
|
|
|
|
try: # pragma: no cover - optional dependency
|
|
from opc.plugins.cli_board.tui.app import CliBoardApp
|
|
from opc.plugins.cli_board.tui.screens.help import HelpScreen
|
|
from opc.plugins.cli_board.tui.screens.palette import CommandPaletteScreen
|
|
from opc.plugins.cli_board.tui.screens.prompt import PromptScreen
|
|
except ImportError: # pragma: no cover - optional dependency
|
|
CliBoardApp = None
|
|
HelpScreen = None
|
|
CommandPaletteScreen = None
|
|
PromptScreen = None
|
|
|
|
|
|
class _StubRepository:
|
|
def __init__(self) -> None:
|
|
self.snapshot = BoardSnapshot(
|
|
project_id="demo",
|
|
tasks=[
|
|
BoardTaskView(
|
|
task_id="todo-1",
|
|
title="Todo task",
|
|
description="Pending task",
|
|
status="pending",
|
|
column_id="todo",
|
|
priority="medium",
|
|
created_at=1.0,
|
|
updated_at=1.0,
|
|
),
|
|
BoardTaskView(
|
|
task_id="run-1",
|
|
title="Running task",
|
|
description="In progress",
|
|
status="running",
|
|
column_id="in-progress",
|
|
priority="high",
|
|
created_at=2.0,
|
|
updated_at=2.0,
|
|
),
|
|
BoardTaskView(
|
|
task_id="done-1",
|
|
title="Done task",
|
|
description="Completed",
|
|
status="done",
|
|
column_id="done",
|
|
priority="low",
|
|
created_at=3.0,
|
|
updated_at=3.0,
|
|
),
|
|
],
|
|
)
|
|
|
|
async def load_snapshot(self) -> BoardSnapshot:
|
|
return self.snapshot
|
|
|
|
async def load_task_detail(self, task_id: str):
|
|
task = next((task for task in self.snapshot.tasks if task.task_id == task_id), None)
|
|
return TaskDetailView(task=task) if task else None
|
|
|
|
|
|
@unittest.skipIf(CliBoardApp is None, "textual is not installed")
|
|
class CliBoardAppPilotTests(unittest.IsolatedAsyncioTestCase):
|
|
async def test_keyboard_navigation_view_switching_and_modals(self) -> None:
|
|
app = CliBoardApp(project_id="demo", refresh_interval=60.0, bootstrap_services=False)
|
|
app.repository = _StubRepository()
|
|
|
|
async with app.run_test() as pilot:
|
|
app.state.replace_snapshot(await app.repository.load_snapshot())
|
|
await app._load_selected_detail()
|
|
app.status_widget.set_message("Harness ready.")
|
|
self.assertEqual(app.state.selected_task().task_id, "todo-1")
|
|
|
|
await pilot.press("right")
|
|
self.assertEqual(app.state.selected_task().task_id, "run-1")
|
|
|
|
await pilot.press("2")
|
|
self.assertEqual(app.state.view_mode, "list")
|
|
|
|
await pilot.press("3")
|
|
self.assertEqual(app.state.view_mode, "focus")
|
|
|
|
app.action_focus_next_pane()
|
|
await pilot.pause()
|
|
self.assertEqual(app.state.pane_focus, "context")
|
|
|
|
# Selecting the running task earlier auto-focused the Session
|
|
# context tab (CliBoardApp._load_selected_detail), so cycling
|
|
# right moves session -> activity.
|
|
self.assertEqual(app.state.context_tab, "session")
|
|
await pilot.press("right")
|
|
self.assertEqual(app.state.context_tab, "activity")
|
|
|
|
await pilot.press("f")
|
|
self.assertFalse(app.state.show_done)
|
|
|
|
await pilot.press("n")
|
|
self.assertIsInstance(app.screen, PromptScreen)
|
|
await pilot.press("escape")
|
|
|
|
app.action_open_palette()
|
|
await pilot.pause()
|
|
self.assertIsInstance(app.screen, CommandPaletteScreen)
|
|
await pilot.press("escape")
|
|
|
|
await pilot.press("?")
|
|
self.assertIsInstance(app.screen, HelpScreen)
|
|
await pilot.press("escape")
|
|
|