Newer
Older
navi-1 / tests / clients / test_tui_app.py
"""Smoke tests for the Navi Code TUI."""

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.mark.anyio
async def test_tui_mounts_widgets() -> None:
    """The TUI app mounts chat, status, and input widgets."""
    async with NaviCodeTui(new_session=True).run_test() as pilot:
        await pilot.pause()
        assert pilot.app.query_one("ChatPanel") is not None
        assert pilot.app.query_one("StatusPanel") is not None
        assert pilot.app.query_one("InputBox") is not None


@pytest.mark.anyio
async def test_user_message_appears_in_chat() -> None:
    """Typing a message and submitting adds it to the chat panel."""
    async with NaviCodeTui(new_session=True).run_test() as pilot:
        await pilot.pause()
        input_box = pilot.app.query_one("InputBox")
        input_box._input.value = "hello"
        await pilot.press("enter")
        await pilot.pause()
        chat = pilot.app.query_one("ChatPanel")
        assert any(item.kind == "user_message" and item.content == "hello" for item in chat._model.items)


@pytest.mark.anyio
async def test_ws_event_renders_in_chat() -> None:
    """A synthetic WebSocket stream_delta is added to the assistant response."""
    async with NaviCodeTui(new_session=True).run_test() as pilot:
        await pilot.pause()
        chat = pilot.app.query_one("ChatPanel")
        chat.handle_ws_event({"type": "stream_start"})
        chat.handle_ws_event({"type": "stream_delta", "delta": "hi"})
        await pilot.pause()
        assert chat._model._current_assistant is not None
        assert chat._model._current_assistant.content == "hi"


@pytest.mark.anyio
async def test_unknown_slash_command_shows_error() -> None:
    """Unknown slash command produces an error item in chat."""
    async with NaviCodeTui(new_session=True).run_test() as pilot:
        await pilot.pause()
        input_box = pilot.app.query_one("InputBox")
        input_box._input.value = "/notacommand"
        await pilot.press("enter")
        await pilot.pause()
        chat = pilot.app.query_one("ChatPanel")
        assert any(item.kind == "error" for item in chat._model.items)


@pytest.mark.anyio
async def test_status_panel_shows_backend_and_theme() -> None:
    """Status panel displays backend URL and current theme."""
    async with NaviCodeTui(new_session=True).run_test() as pilot:
        await pilot.pause()
        status = pilot.app.query_one("StatusPanel")
        backend_text = str(status._backend.render())
        theme_text = str(status._theme.render())
        assert "Backend:" in backend_text
        assert "Theme: gnexus-dark" in theme_text