"""Tests for the /export slash command."""
from __future__ import annotations
from pathlib import Path
import pytest
from clients.terminal.tui.tui_app import NaviCodeTui
@pytest.fixture(autouse=True)
def tmp_state_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
"""Override the state dir so tests never touch ~/.navi_code."""
from clients.terminal import config
original = config.settings.state_dir
config.settings.state_dir = tmp_path
import clients.terminal.tui.settings as settings_module
settings_module._tui_settings = None
yield tmp_path
config.settings.state_dir = original
settings_module._tui_settings = None
@pytest.fixture
def fake_session(monkeypatch: pytest.MonkeyPatch) -> dict:
"""Return a fake session payload used to test export."""
session_id = "sess-export-1234"
def fake_get_session(sid: str) -> dict:
if sid != session_id:
raise Exception("not found")
return {
"session_id": session_id,
"profile_id": "navi_code",
"created_at": "2026-06-23T12:00:00",
"messages": [
{"role": "user", "content": "Hello Navi"},
{"role": "assistant", "content": "Hello!"},
],
}
def fake_create_session(profile_id: str | None = None) -> dict:
return {
"session_id": session_id,
"profile_id": profile_id or "navi_code",
}
def fake_list_sessions() -> list[dict]:
return [fake_get_session(session_id)]
monkeypatch.setattr("clients.terminal.api.get_session", fake_get_session)
monkeypatch.setattr("clients.terminal.api.create_session", fake_create_session)
monkeypatch.setattr("clients.terminal.api.list_sessions", fake_list_sessions)
return fake_get_session(session_id)
@pytest.mark.anyio
async def test_export_command_writes_markdown(
tmp_state_dir: Path, fake_session: dict, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Running /export writes a markdown file and opens the editor."""
opened_files: list[str] = []
def fake_open_in_editor(path: str) -> None:
opened_files.append(path)
monkeypatch.setattr(
"clients.terminal.tui.commands.builtin._open_in_editor", fake_open_in_editor
)
async with NaviCodeTui(new_session=True).run_test() as pilot:
await pilot.pause()
input_box = pilot.app.query_one("InputBox")
input_box._input.value = "/export"
await pilot.press("enter")
await pilot.pause()
export_dir = tmp_state_dir / "exports"
assert export_dir.exists()
files = list(export_dir.glob("*.md"))
assert len(files) == 1
content = files[0].read_text(encoding="utf-8")
assert "# Navi Code Export" in content
assert "Hello Navi" in content
assert "Hello!" in content
assert "navi_code" in content
assert opened_files == [str(files[0])]
@pytest.mark.anyio
async def test_export_without_session_shows_error(
tmp_state_dir: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Running /export when there is no active session shows an error."""
def fake_create_session(profile_id: str | None = None) -> dict:
return {"session_id": "", "profile_id": profile_id or "navi_code"}
def fake_get_session(sid: str) -> dict:
raise Exception("not found")
monkeypatch.setattr("clients.terminal.api.create_session", fake_create_session)
monkeypatch.setattr("clients.terminal.api.get_session", fake_get_session)
async with NaviCodeTui(new_session=True).run_test() as pilot:
await pilot.pause()
pilot.app._ctx.session_id = None
input_box = pilot.app.query_one("InputBox")
input_box._input.value = "/export"
await pilot.press("enter")
await pilot.pause()
chat = pilot.app.query_one("ChatPanel")
assert any(item.kind == "error" for item in chat._model.items)