feat(web): Executions table gets real columns and status icons
No cell stacks two facts on separate lines with <br> any more (Run/Repo, Branch/Commit, Trigger/Actor, Duration/Started, VM/IP-Uptime each get their own column, 8 -> 13 total). The card is already .card--wide with its own .table-wrap, so the extra width scrolls horizontally rather than the page. Status pills carry a check/x/play icon for the three outcomes that are a real verdict or an in-progress state (success/failure/running); queued, cancelled, skipped stay plain text. Every pill in the column -- including the VM-only orphan/running pills on unmatched-VM rows -- is forced to the same width with left-aligned content instead of a ragged column.
This commit is contained in:
@@ -270,6 +270,102 @@ def test_status_badges(
|
||||
assert f">{status}<" in resp.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("status", "icon"),
|
||||
[
|
||||
("success", "i-check"),
|
||||
("failure", "i-x"),
|
||||
],
|
||||
)
|
||||
def test_status_badge_carries_a_check_or_x_icon(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, status: str, icon: str
|
||||
) -> None:
|
||||
"""A pass/fail outcome should read without needing the badge colour."""
|
||||
_stub_view(
|
||||
monkeypatch,
|
||||
ExecutionsView(
|
||||
runs=[_execution(status=status)], unmatched_vms=[], source="admin", error=None
|
||||
),
|
||||
)
|
||||
app = create_app(_make_config(tmp_path))
|
||||
app.dependency_overrides[get_backend] = lambda: _FakeBackend([])
|
||||
client = TestClient(app)
|
||||
|
||||
resp = client.get("/executions")
|
||||
|
||||
assert f'href="#{icon}"' in resp.text
|
||||
|
||||
|
||||
def test_status_badge_carries_a_play_icon_for_running(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""In progress is its own state, not a verdict -- but still not bare text."""
|
||||
_stub_view(
|
||||
monkeypatch,
|
||||
ExecutionsView(
|
||||
runs=[_execution(status="running")], unmatched_vms=[], source="admin", error=None
|
||||
),
|
||||
)
|
||||
app = create_app(_make_config(tmp_path))
|
||||
app.dependency_overrides[get_backend] = lambda: _FakeBackend([])
|
||||
client = TestClient(app)
|
||||
|
||||
resp = client.get("/executions")
|
||||
|
||||
# The card's own header icon is also #i-play -- count, don't just look
|
||||
# for presence, or this assertion is trivially true either way.
|
||||
assert resp.text.count('href="#i-play"') == 2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("status", ["queued", "cancelled", "unknown"])
|
||||
def test_status_badge_has_no_icon_for_non_terminal_states(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, status: str
|
||||
) -> None:
|
||||
"""queued/cancelled/unknown are neither a verdict nor in progress -- plain text."""
|
||||
_stub_view(
|
||||
monkeypatch,
|
||||
ExecutionsView(
|
||||
runs=[_execution(status=status)], unmatched_vms=[], source="admin", error=None
|
||||
),
|
||||
)
|
||||
app = create_app(_make_config(tmp_path))
|
||||
app.dependency_overrides[get_backend] = lambda: _FakeBackend([])
|
||||
client = TestClient(app)
|
||||
|
||||
resp = client.get("/executions")
|
||||
|
||||
assert '<td><span class="badge badge-' in resp.text
|
||||
assert "#i-check" not in resp.text
|
||||
assert "#i-x" not in resp.text
|
||||
assert "#i-x" not in resp.text
|
||||
|
||||
|
||||
def test_no_cell_stacks_two_facts_on_separate_lines(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""Run/Repo, Branch/Commit, Trigger/Actor, Duration/Started and VM/IP each
|
||||
get their own column now -- no cell relies on a <br> to show two facts."""
|
||||
vm = _vm("Clone_412-1_20260725_115000_linux")
|
||||
_stub_view(
|
||||
monkeypatch,
|
||||
ExecutionsView(
|
||||
runs=[_execution(vms=[vm])], unmatched_vms=[], source="admin", error=None
|
||||
),
|
||||
)
|
||||
app = create_app(_make_config(tmp_path))
|
||||
app.dependency_overrides[get_backend] = lambda: _FakeBackend([])
|
||||
client = TestClient(app)
|
||||
|
||||
resp = client.get("/executions")
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert "<br>" not in resp.text
|
||||
for header in ("Repo", "Trigger", "Actor", "Started", "IP / Uptime"):
|
||||
assert f"<th>{header}</th>" in resp.text
|
||||
assert "Simone" in resp.text # actor, now its own column
|
||||
assert vm.ip in resp.text
|
||||
|
||||
|
||||
def test_empty_state_when_no_runs_and_no_vms(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
@@ -305,6 +401,9 @@ def test_unmatched_vm_keeps_its_row_and_remove_button(
|
||||
assert vm.name in resp.text
|
||||
assert "370-1" in resp.text # job id parsed out of the clone name
|
||||
assert "Remove" in resp.text
|
||||
# Same word, same column as a run's "running" status pill -- same icon.
|
||||
# The card's own header icon is also #i-play, hence count == 2 not 1.
|
||||
assert resp.text.count('href="#i-play"') == 2
|
||||
|
||||
|
||||
def test_end_to_end_against_a_stubbed_gitea(
|
||||
|
||||
Reference in New Issue
Block a user