test: use real directories in TUI/integration project tests
ProjectService now rejects non-existent paths (path-validation feature), so the TUI and integration tests must seed projects with real tmp_path dirs. Completes the path-validation test updates beyond test_services.py. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -43,11 +43,11 @@ def setup():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_full_lifecycle(setup):
|
async def test_full_lifecycle(setup, tmp_path):
|
||||||
proj_svc, sess_svc, tmux = setup
|
proj_svc, sess_svc, tmux = setup
|
||||||
|
|
||||||
# Create project
|
# Create project
|
||||||
project = proj_svc.create(name="test-proj", path="/tmp/test-proj")
|
project = proj_svc.create(name="test-proj", path=str(tmp_path))
|
||||||
assert project.id == 1
|
assert project.id == 1
|
||||||
|
|
||||||
# Create session
|
# Create session
|
||||||
|
|||||||
+45
-18
@@ -619,12 +619,12 @@ async def test_project_form_add_mode_defaults_name_to_basename():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_project_list_get_selected_project_id():
|
async def test_project_list_get_selected_project_id(tmp_path):
|
||||||
app = HqtApp()
|
app = HqtApp()
|
||||||
async with app.run_test(size=(120, 40)) as pilot:
|
async with app.run_test(size=(120, 40)) as pilot:
|
||||||
from hqt.tui.widgets.project_list import ProjectList
|
from hqt.tui.widgets.project_list import ProjectList
|
||||||
|
|
||||||
p = app._project_service.create("selproj", "/tmp/selproj")
|
p = app._project_service.create("selproj", str(tmp_path))
|
||||||
app._load_projects()
|
app._load_projects()
|
||||||
await app.workers.wait_for_complete()
|
await app.workers.wait_for_complete()
|
||||||
await pilot.pause()
|
await pilot.pause()
|
||||||
@@ -669,14 +669,22 @@ async def test_edit_project_no_selection_warns():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_edit_project_opens_prefilled_form_and_updates():
|
async def test_edit_project_opens_prefilled_form_and_updates(tmp_path):
|
||||||
app = HqtApp()
|
app = HqtApp()
|
||||||
async with app.run_test(size=(120, 40)) as pilot:
|
async with app.run_test(size=(120, 40)) as pilot:
|
||||||
|
from pathlib import Path
|
||||||
from textual.widgets import Input
|
from textual.widgets import Input
|
||||||
from hqt.tui.screens.project_form import ProjectFormScreen
|
from hqt.tui.screens.project_form import ProjectFormScreen
|
||||||
from hqt.tui.widgets.project_list import ProjectList
|
from hqt.tui.widgets.project_list import ProjectList
|
||||||
|
|
||||||
p = app._project_service.create("oldname", "/tmp/oldpath")
|
old_dir = tmp_path / "oldpath"
|
||||||
|
old_dir.mkdir()
|
||||||
|
new_dir = tmp_path / "newpath"
|
||||||
|
new_dir.mkdir()
|
||||||
|
old_path = str(old_dir)
|
||||||
|
new_path = str(new_dir)
|
||||||
|
|
||||||
|
p = app._project_service.create("oldname", old_path)
|
||||||
app._load_projects()
|
app._load_projects()
|
||||||
await app.workers.wait_for_complete()
|
await app.workers.wait_for_complete()
|
||||||
await pilot.pause()
|
await pilot.pause()
|
||||||
@@ -692,25 +700,35 @@ async def test_edit_project_opens_prefilled_form_and_updates():
|
|||||||
|
|
||||||
assert isinstance(app.screen, ProjectFormScreen)
|
assert isinstance(app.screen, ProjectFormScreen)
|
||||||
assert app.screen.query_one("#name-input", Input).value == "oldname"
|
assert app.screen.query_one("#name-input", Input).value == "oldname"
|
||||||
assert app.screen.query_one("#path-input", Input).value == "/tmp/oldpath"
|
assert app.screen.query_one("#path-input", Input).value == str(
|
||||||
|
Path(old_path).resolve()
|
||||||
|
)
|
||||||
|
|
||||||
app.screen.dismiss(("newname", "/tmp/newpath"))
|
app.screen.dismiss(("newname", new_path))
|
||||||
await pilot.pause()
|
await pilot.pause()
|
||||||
|
|
||||||
refreshed = app._project_service.get(p.id)
|
refreshed = app._project_service.get(p.id)
|
||||||
assert refreshed.name == "newname"
|
assert refreshed.name == "newname"
|
||||||
assert refreshed.path == "/tmp/newpath"
|
assert refreshed.path == str(Path(new_path).resolve())
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_edit_project_duplicate_path_notifies_error():
|
async def test_edit_project_duplicate_path_notifies_error(tmp_path):
|
||||||
app = HqtApp()
|
app = HqtApp()
|
||||||
async with app.run_test(size=(120, 40)) as pilot:
|
async with app.run_test(size=(120, 40)) as pilot:
|
||||||
|
from pathlib import Path
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from hqt.tui.widgets.project_list import ProjectList
|
from hqt.tui.widgets.project_list import ProjectList
|
||||||
|
|
||||||
app._project_service.create("first", "/tmp/first")
|
first_dir = tmp_path / "first"
|
||||||
p2 = app._project_service.create("second", "/tmp/second")
|
first_dir.mkdir()
|
||||||
|
second_dir = tmp_path / "second"
|
||||||
|
second_dir.mkdir()
|
||||||
|
first_path = str(first_dir)
|
||||||
|
second_path = str(second_dir)
|
||||||
|
|
||||||
|
app._project_service.create("first", first_path)
|
||||||
|
p2 = app._project_service.create("second", second_path)
|
||||||
app._load_projects()
|
app._load_projects()
|
||||||
await app.workers.wait_for_complete()
|
await app.workers.wait_for_complete()
|
||||||
await pilot.pause()
|
await pilot.pause()
|
||||||
@@ -729,7 +747,8 @@ async def test_edit_project_duplicate_path_notifies_error():
|
|||||||
):
|
):
|
||||||
await app.run_action("edit_project")
|
await app.run_action("edit_project")
|
||||||
await pilot.pause()
|
await pilot.pause()
|
||||||
app.screen.dismiss(("second", "/tmp/first"))
|
# Move "second" onto "first"'s path to trigger the duplicate error.
|
||||||
|
app.screen.dismiss(("second", first_path))
|
||||||
await pilot.pause()
|
await pilot.pause()
|
||||||
|
|
||||||
assert any(
|
assert any(
|
||||||
@@ -737,7 +756,7 @@ async def test_edit_project_duplicate_path_notifies_error():
|
|||||||
for msg, kw in notify_calls
|
for msg, kw in notify_calls
|
||||||
), f"Expected duplicate-path error notification, got: {notify_calls}"
|
), f"Expected duplicate-path error notification, got: {notify_calls}"
|
||||||
# DB unchanged
|
# DB unchanged
|
||||||
assert app._project_service.get(p2.id).path == "/tmp/second"
|
assert app._project_service.get(p2.id).path == str(Path(second_path).resolve())
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -882,14 +901,18 @@ async def test_dialog_button_focus_is_visibly_highlighted():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_first_project_selected_on_load():
|
async def test_first_project_selected_on_load(tmp_path):
|
||||||
"""If a project exists, the first is selected on load with no key press."""
|
"""If a project exists, the first is selected on load with no key press."""
|
||||||
app = HqtApp()
|
app = HqtApp()
|
||||||
async with app.run_test(size=(120, 40)) as pilot:
|
async with app.run_test(size=(120, 40)) as pilot:
|
||||||
from hqt.tui.widgets.project_list import ProjectList
|
from hqt.tui.widgets.project_list import ProjectList
|
||||||
|
|
||||||
app._project_service.create("p1", "/tmp/p1-auto")
|
d1 = tmp_path / "p1-auto"
|
||||||
app._project_service.create("p2", "/tmp/p2-auto")
|
d1.mkdir()
|
||||||
|
d2 = tmp_path / "p2-auto"
|
||||||
|
d2.mkdir()
|
||||||
|
app._project_service.create("p1", str(d1))
|
||||||
|
app._project_service.create("p2", str(d2))
|
||||||
app._load_projects()
|
app._load_projects()
|
||||||
await app.workers.wait_for_complete()
|
await app.workers.wait_for_complete()
|
||||||
await pilot.pause()
|
await pilot.pause()
|
||||||
@@ -1152,14 +1175,18 @@ async def test_rename_session_opens_prefilled_and_updates():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_project_list_jk_navigation():
|
async def test_project_list_jk_navigation(tmp_path):
|
||||||
"""j/k move the highlight down/up in the project list like the arrow keys."""
|
"""j/k move the highlight down/up in the project list like the arrow keys."""
|
||||||
app = HqtApp()
|
app = HqtApp()
|
||||||
async with app.run_test(size=(120, 40)) as pilot:
|
async with app.run_test(size=(120, 40)) as pilot:
|
||||||
from hqt.tui.widgets.project_list import ProjectList
|
from hqt.tui.widgets.project_list import ProjectList
|
||||||
|
|
||||||
p1 = app._project_service.create("first", "/tmp/jk-first")
|
d1 = tmp_path / "jk-first"
|
||||||
p2 = app._project_service.create("second", "/tmp/jk-second")
|
d1.mkdir()
|
||||||
|
d2 = tmp_path / "jk-second"
|
||||||
|
d2.mkdir()
|
||||||
|
p1 = app._project_service.create("first", str(d1))
|
||||||
|
p2 = app._project_service.create("second", str(d2))
|
||||||
app._load_projects()
|
app._load_projects()
|
||||||
await app.workers.wait_for_complete()
|
await app.workers.wait_for_complete()
|
||||||
await pilot.pause()
|
await pilot.pause()
|
||||||
|
|||||||
Reference in New Issue
Block a user