asyncio_mode = auto)mocker fixtureTestClient for FastAPI routes@pinia/testing for store mockstests/ # Backend + terminal client (pytest)
├── conftest.py
├── conftest_factory.py
├── unit/
│ ├── api/
│ │ └── test_session_files.py
│ ├── auth/
│ │ ├── test_api_tokens.py
│ │ ├── test_deps.py
│ │ └── test_encrypt.py
│ ├── core/
│ │ ├── test_agent.py
│ │ ├── test_agent_context_size.py
│ │ ├── test_agent_stream_guard.py
│ │ ├── test_anti_stall.py
│ │ ├── test_compressor.py
│ │ ├── test_context_builder.py
│ │ ├── test_events.py
│ │ ├── test_pg_session_store.py
│ │ ├── test_planning.py
│ │ ├── test_registry.py
│ │ ├── test_scheduler.py
│ │ └── test_tool_executor.py
│ ├── llm/
│ │ └── test_ollama.py
│ ├── memory/
│ │ ├── test_extractor.py
│ │ └── test_store.py
│ ├── profiles/
│ │ ├── test_base.py
│ │ └── test_overrides.py
│ ├── store/
│ │ └── test_kv_store.py
│ ├── tools/
│ │ ├── test_code_exec.py
│ │ ├── test_content_publish.py
│ │ ├── test_filesystem.py
│ │ ├── test_image_view.py
│ │ ├── test_memory.py
│ │ ├── test_recall_tools.py
│ │ ├── test_scratchpad.py
│ │ └── ...
│ ├── test_content_store.py
│ ├── test_mcp.py
│ └── test_startup.py
├── integration/
│ ├── conftest.py
│ ├── test_api_routes.py
│ ├── test_auth_disabled.py
│ ├── test_mcp_integration.py
│ ├── test_recall_api.py
│ ├── test_scheduler_loop.py
│ └── test_websocket.py
└── clients/ # Terminal client tests
├── test_terminal_client.py
├── test_terminal_ws.py
├── test_tui_app.py
├── test_tui_export.py
├── test_tui_sessions_panel.py
├── test_tui_settings.py
├── test_tui_themes.py
├── test_permissions.py
├── test_permission_dialog.py
├── test_shell_runner.py
├── test_file_refs.py
└── test_diff_artifact_renderers.py
webclient/tests/ # Web client (Vitest)
├── unit/
│ ├── api/
│ │ └── index.test.js
│ ├── stores/
│ │ ├── chat.test.js
│ │ ├── sessions.test.js
│ │ └── profiles.test.js
│ └── composables/
│ └── useWebSocket.test.js
FakeLLMBackend cycles through a list of pre-defined responses and optionally emits ToolCallRequest objects. This lets us test the agent loop and planning without real Ollama.
from tests.conftest_factory import FakeLLMBackend
backend = FakeLLMBackend(
responses=["Hello", "DIRECT"],
tool_calls=[None, None],
thinking=["Hmm", None],
)
resp = await backend.complete([]) # → LLMResponse(content="Hello")
Unit tests mock asyncpg.Pool via an in-memory FakePool/FakeConnection. Integration tests may use a real Postgres instance via TEST_DATABASE_URL.
from tests.conftest_factory import FakeConnection, FakeRecord, make_store_with_pool conn = FakeConnection() conn.enqueue(42) # fetchval result conn.enqueue([FakeRecord(id="1", key="name", value="Eugene")]) # fetch result store = make_store_with_pool(conn)
The project is covered by backend (pytest), terminal-client (pytest), and web-client (Vitest) tests. Key areas with dedicated tests:
tests/unit/core/test_agent*.py, test_planning.py, test_anti_stall.py.test_compressor.py, test_events.py, test_pg_session_store.py.tests/unit/tools/test_*.py.tests/unit/memory/test_*.py.tests/unit/auth/test_*.py.tests/unit/test_mcp.py, tests/integration/test_mcp_integration.py, test_recall_tools.py, test_scheduler.py.tests/clients/test_*.py.webclient/tests/unit/**/*.test.js.The detailed coverage roadmap lives in the test directories themselves. Add a regression test whenever a real bug is fixed.
# Backend tests pytest # all backend tests pytest tests/unit # unit only pytest -v tests/unit/core # verbose pytest -v tests/unit/core/test_events.py::TestToolStarted::test_to_wire # single test TEST_DATABASE_URL=postgresql://... pytest tests/integration # Web client tests (run from webclient/) cd webclient && npm test # all webclient tests npx vitest run tests/unit/api # single directory npx vitest run -t "buildMessageList" # filter by test name
tests/unit/ or tests/integration/ directory.async def for async tests — pytest-asyncio handles the rest.tests.conftest_factory for fakes.navi.config.settings are reset automatically by the autouse fixture in conftest.py.FakeLLMBackend, DB → FakePool, filesystem → tmp_path.tests/integration/.datetime.now.