CLI
This commit is contained in:
107
tests/test_tui.py
Normal file
107
tests/test_tui.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""Headless smoke tests for the snotes TUI (Textual pilot)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
textual = pytest.importorskip("textual") # noqa: F841
|
||||
|
||||
|
||||
def _load_cli():
|
||||
path = Path(__file__).parent.parent / "cli" / "snotes.py"
|
||||
spec = importlib.util.spec_from_file_location("snotes_cli", path)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = mod
|
||||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
|
||||
|
||||
cli = _load_cli()
|
||||
|
||||
NOTES = [
|
||||
{"id": "a1", "title": "Shopping list", "updated_at": "2026-09-26 09:00:00", "tags": ["home"]},
|
||||
{
|
||||
"id": "b2",
|
||||
"title": "Journal for 2026-09-26",
|
||||
"updated_at": "2026-09-25 22:00:00",
|
||||
"tags": ["journal"],
|
||||
},
|
||||
]
|
||||
|
||||
BODIES = {
|
||||
"a1": "# Shopping list\n\n- milk\n- eggs\n",
|
||||
"b2": "# Journal for 2026-09-26\n\nA fine day.\n",
|
||||
}
|
||||
|
||||
|
||||
class FakeApi:
|
||||
def __init__(self):
|
||||
self.cfg = cli.Config(url="http://test", user="schmeeve")
|
||||
self.deleted: list[str] = []
|
||||
|
||||
def recent(self, limit: int = 30) -> list[dict]:
|
||||
return NOTES[:limit]
|
||||
|
||||
def search(self, q: str) -> list[dict]:
|
||||
return [n for n in NOTES if q.lower() in n["title"].lower()]
|
||||
|
||||
def get_note(self, note_id: str) -> dict:
|
||||
return {"id": note_id, "title": "t", "body": BODIES[note_id]}
|
||||
|
||||
def create(self, body: str) -> dict: # pragma: no cover - not exercised
|
||||
return {"id": "new", "title": body}
|
||||
|
||||
def update(self, note_id: str, body: str) -> dict: # pragma: no cover
|
||||
return {"id": note_id}
|
||||
|
||||
def delete(self, note_id: str) -> None:
|
||||
self.deleted.append(note_id)
|
||||
|
||||
|
||||
async def test_tui_boots_with_recent_notes():
|
||||
app = cli.make_app(FakeApi(), None)
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.pause()
|
||||
from textual.widgets import ListView
|
||||
|
||||
lv = app.query_one("#notes", ListView)
|
||||
assert len(lv.children) == 2
|
||||
assert app.title == "snotes"
|
||||
|
||||
|
||||
async def test_tui_initial_query_filters():
|
||||
app = cli.make_app(FakeApi(), "journal")
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.pause()
|
||||
await pilot.pause(0.4) # debounce
|
||||
from textual.widgets import Input, ListView
|
||||
|
||||
assert app.query_one("#search", Input).value == "journal"
|
||||
assert len(app.query_one("#notes", ListView).children) == 1
|
||||
|
||||
|
||||
async def test_tui_preview_shows_note_body():
|
||||
app = cli.make_app(FakeApi(), None)
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.pause()
|
||||
from textual.widgets import Markdown
|
||||
|
||||
preview = app.query_one("#preview", Markdown)
|
||||
await pilot.pause(0.2)
|
||||
assert "Shopping list" in preview.source or "milk" in preview.source
|
||||
|
||||
|
||||
async def test_tui_delete_flow():
|
||||
fake = FakeApi()
|
||||
app = cli.make_app(fake, None)
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.pause()
|
||||
await pilot.press("d")
|
||||
await pilot.pause()
|
||||
await pilot.press("y")
|
||||
await pilot.pause(0.3)
|
||||
assert fake.deleted == ["a1"]
|
||||
Reference in New Issue
Block a user