Single consolidated commit for four completed, validated phases (77, 78, 79, 80). The pipeline run left all work uncommitted because the harness commits only with PHASE_COMMIT=1 while child executors are forbidden from committing; the phases themselves all passed validation and moved to .agents/phases/complete/. Phase 77 — navbar view refresh - router.js dispatches bor:view-refresh on re-show / active re-click / popstate (gated on wasMounted; first show and boot exempt) - History / RAG / Sources / Tuning re-fetch on refresh (admin branch); Chat deliberately excluded (stream survival) - History "Refresh" button (admin-only, in-flight disable + status line) - New story suite tests/e2e/test_navbar_refresh.py (7 tests) Phase 78 — static background - Removed the animated glow layers; static 44px grid over the flat --bg canvas; default and reduced-motion renders byte-identical - Updated background/theme E2E suites; removed bg-glow test pins Phase 79 — API tokens - api_tokens model + migration 0012; hash-only token service - Admin tokens API + Tokens admin view; POST /api/token-auth; live-revoking require_user on chat / suggestions / document content - Frontend token gate with localStorage cache; anonymous E2E suites migrated to token login - New story suite tests/e2e/test_api_tokens.py (9 tests) Phase 80 — history suggestion chips - last_questions() endpoint with SEED fallback; startNewChat() refetch - Seed-semantics docs (config.py, .env.example, README) - Integration state matrix + E2E suite rewritten to the 4 chip states Also included: phase-76 report artifacts and the repo restore-test-db skill (previously untracked), scripts/* ruff fixes from phase 77. Final gate state (phase 80 final pass, covers everything above): - uv run pytest --cov=app → 1637 passed, 0 failed, app/ coverage 99% - uv run ruff check . && uv run pyright → clean, 0 errors - Per-phase story E2E suites green in isolation
52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
"""Phase 01 smoke E2E: the app boots, serves the local frontend, and a chat
|
|
round-trip never leaves a stale button (answer or error banner, both fine).
|
|
|
|
Run: uv run pytest tests/e2e/test_smoke.py -v
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
from playwright.sync_api import Page, expect
|
|
|
|
from e2e.auth_helpers import login
|
|
|
|
|
|
def test_health_endpoint(app_url: str) -> None:
|
|
r = httpx.get(f"{app_url}/api/health", timeout=5)
|
|
assert r.status_code == 200
|
|
assert r.json()["status"] == "ok"
|
|
|
|
|
|
def test_index_page_loads_locally(page: Page, app_url: str) -> None:
|
|
page.goto(app_url)
|
|
assert page.title() == "Brain of Reese"
|
|
assert page.locator(".brand").is_visible()
|
|
# No external (CDN) resources in the document.
|
|
html = page.content()
|
|
assert 'src="http' not in html
|
|
assert 'href="http' not in html.replace('href="http://www.w3.org', "")
|
|
|
|
|
|
def test_chat_roundtrip_never_stale_button(page: Page, app_url: str) -> None:
|
|
# Phase 79: chat is require_user-gated (and the in-app token gate
|
|
# locks #main for anonymous) — the round-trip signs in as admin
|
|
# first (real form login; DB-free, so the story's DB-down error-
|
|
# banner path still works).
|
|
login(page, app_url, next="/")
|
|
page.locator("#message-input").fill("hello brain")
|
|
page.locator("#send-btn").click()
|
|
|
|
# User bubble appears first.
|
|
page.locator(".msg.user .bubble").first.wait_for(state="visible", timeout=10_000)
|
|
# Then either a streamed Brain answer (DB up) or an error banner
|
|
# (DB down) — but the turn must always complete.
|
|
page.wait_for_selector(
|
|
".msg.brain .bubble, #kb-banner.is-error",
|
|
state="visible",
|
|
timeout=20_000,
|
|
)
|
|
|
|
# Button is never left stuck: back to "Send" and enabled.
|
|
expect(page.locator("#send-btn")).to_be_enabled(timeout=10_000)
|
|
expect(page.locator("#send-label")).to_have_text("Send", timeout=10_000)
|