The 11-admin spec walked links that terminate on FrankBook-Pro (192.168.0.112), which sleeps when idle — every deploy gate timed out there (measured 2026-10-05, two deploy windows). Split: the frankbook links move to tests/e2e/specs/19-frankbook.spec.ts under a frankbook project that run.sh excludes by default and deploy.sh triggers ONLY when a frankbook blast-radius path changed (the spec, frankbook-pro/, the homepage registry, the Caddyfile arr vhosts). deploy.sh computes the trigger from the same BASE..HEAD revision range the plan uses.
71 lines
3.0 KiB
Bash
Executable File
71 lines
3.0 KiB
Bash
Executable File
#!/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
|
|
}
|