#!/usr/bin/env bats # Seam: tests/e2e — Playwright suite structure. The suite drives the LIVE # fleet (homepage + Anubis/Authentik guard chain) and is deliberately not # part of ./tests/run.sh; this seam only asserts the scaffold is present, # well-formed, and that no credentials or browser auth state are tracked. load helpers @test "e2e: runner, config, lib, and specs exist" { for f in run.sh package.json playwright.config.ts .env.local.example \ lib/env.ts lib/login.ts \ specs/00-auth.setup.ts specs/10-homepage.spec.ts specs/11-admin.spec.ts \ specs/12-crawl.spec.ts specs/13-sso.spec.ts specs/14-guard.spec.ts \ specs/19-frankbook.spec.ts; do [ -f "$REPO_ROOT/tests/e2e/$f" ] || { echo "missing tests/e2e/$f" return 1 } done } @test "e2e: package.json is valid JSON with the playwright dependency" { python3 - "$REPO_ROOT/tests/e2e/package.json" <<'PY' import json, sys pkg = json.load(open(sys.argv[1])) assert "@playwright/test" in pkg.get("devDependencies", {}), "missing @playwright/test" PY } @test "e2e: run.sh parses" { bash -n "$REPO_ROOT/tests/e2e/run.sh" } @test "e2e: example env file carries only placeholders" { if grep -E '^E2E_[A-Z_]*PASS=' "$REPO_ROOT/tests/e2e/.env.local.example" | grep -vq REPLACE_ME; then echo ".env.local.example must hold REPLACE_ME placeholders, never real passwords" return 1 fi } @test "e2e: no credentials or auth state are tracked" { cd "$REPO_ROOT" tracked="$(git ls-files tests/e2e)" if echo "$tracked" | grep -Eq '(^|/)\.env\.local$|(^|/)\.auth(/|$)|node_modules'; then echo "tracked files must not include creds or auth state:" echo "$tracked" | grep -E '(^|/)\.env\.local$|(^|/)\.auth(/|$)|node_modules' return 1 fi } @test "every e2e spec is matched by a playwright project" { # Playwright projects match specs by NUMBER PREFIX, not by glob, so a spec # whose prefix is not listed in any project silently never runs: the suite # reports green while the test does not exist. That happened on 2026-09-16 # with 17-hermes-vhost.spec.ts — written to catch a real regression (a # loopback-only bind that killed hermes.franksdank.cloud's upstream while # every gate stayed green), and invisible until the prefix was registered. local cfg="$REPO_ROOT/tests/e2e/playwright.config.ts" python3 - "$cfg" <<'PYEOF' import pathlib, re, sys cfg = pathlib.Path(sys.argv[1]).read_text() patterns = [re.compile(p) for p in re.findall(r"testMatch:\s*/(.+?)/,", cfg)] assert patterns, "no testMatch patterns found in the playwright config" specs = sorted(pathlib.Path(sys.argv[1]).parent.joinpath("specs").glob("*.spec.ts")) assert specs, "no spec files found" unmatched = [s.name for s in specs if not any(p.search(s.name) for p in patterns)] assert not unmatched, f"specs matched by no project (they will never run): {unmatched}" print(f"{len(specs)} specs, all matched by {len(patterns)} projects") PYEOF }