asyncio_mode = auto)mocker fixtureTestClient for FastAPI routes@pinia/testing for store mockstests/ # Backend (pytest)
├── conftest.py
├── conftest_factory.py
├── unit/
│ ├── core/
│ │ ├── test_events.py # 17 tests
│ │ ├── test_context_builder.py
│ │ ├── test_compressor.py
│ │ ├── test_registry.py
│ │ ├── test_planning.py
│ │ ├── test_agent_context_size.py
│ │ └── test_agent_stream_guard.py
│ ├── memory/
│ │ ├── test_store.py
│ │ └── test_extractor.py
│ ├── tools/
│ │ ├── test_filesystem.py
│ │ ├── test_code_exec.py
│ │ └── test_terminal.py
│ ├── profiles/
│ │ └── test_base.py
│ └── config/
│ └── test_settings.py
├── integration/
│ ├── conftest.py
│ ├── test_api_routes.py
│ └── test_websocket.py
└── e2e/
└── test_chat_flow.py
webclient/tests/ # Web client (Vitest)
├── unit/
│ ├── api/
│ │ └── index.test.js # 8 tests — request helper, verbs, errors, FormData
│ ├── stores/
│ │ ├── chat.test.js # 23 tests — buildMessageList, WS handlers, session load
│ │ ├── sessions.test.js # 6 tests — fetch, create, delete, pin sorting
│ │ └── profiles.test.js # 3 tests — fetch, selection, lookup
│ └── composables/
│ └── useWebSocket.test.js # 7 tests — connect, dispatch, reconnect
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)
| Phase | Module | Tests | Status |
|---|---|---|---|
| 1 | navi.core.events |
17 | ✅ Done |
| 1 | navi.core.compressor |
14 | ✅ Done |
| 1 | navi.core.registry |
10 | ✅ Done |
| 1 | navi.core.context_builder |
9 | ✅ Done |
| 1 | navi.profiles.base |
9 | ✅ Done |
| 2 | navi.memory.store |
18 | ✅ Done |
| 2 | navi.memory.extractor |
11 | ✅ Done |
| 3 | navi.api.routes |
19 | ✅ Done |
| 3 | navi.api.websocket |
7 | ✅ Done |
| 4 | navi.core.agent |
9 | ✅ Done |
| 4 | navi.core.planning |
5 | ✅ Done |
| 5 | navi.tools.filesystem |
13 | ✅ Done |
| 5 | navi.tools.code_exec |
5 | ✅ Done |
| 5 | navi.tools.terminal |
4 | ✅ Done |
| 6 | webclient/api |
8 | ✅ Done |
| 6 | webclient/stores/chat |
23 | ✅ Done |
| 6 | webclient/stores/sessions |
6 | ✅ Done |
| 6 | webclient/stores/profiles |
3 | ✅ Done |
| 6 | webclient/composables/useWebSocket |
7 | ✅ Done |
# 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.