Broaden e2e coverage: invalid credentials, session persistence, API auth
CI / web (push) Successful in 17s
CI / api (push) Successful in 32s

Added: wrong-password rejection (local + OIDC), session survives a
page reload, and API-level checks that /api/hosts, /api/devices,
/api/auth/me all reject unauthenticated requests regardless of what
the UI does.

No new app bugs found this round -- one test assertion was itself
wrong (expected no session cookie on failed login; @fastify/session
issues an anonymous cookie on any response by design, that's normal).
Fixed to assert the property that actually matters: the cookie grants
no access. 9/9 tests green across 4 consecutive full-suite runs with
parallel workers, no flakiness.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-12 22:38:10 -06:00
parent 13f69ea1aa
commit 48acfcd715
3 changed files with 76 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
import { test, expect } from "@playwright/test";
// No page/cookies involved -- confirms protected routes actually reject
// unauthenticated requests, independent of whatever the UI does.
test.describe("unauthenticated API access is rejected", () => {
for (const path of ["/api/hosts", "/api/devices", "/api/auth/me"]) {
test(`GET ${path} without a session returns 401`, async ({ request }) => {
const res = await request.get(path);
expect(res.status()).toBe(401);
});
}
test("POST /api/auth/login with bad credentials returns 401 and grants no access", async ({
request,
}) => {
const res = await request.post("/api/auth/login", {
data: { username: "admin", password: "definitely-not-the-password" },
});
expect(res.status()).toBe(401);
// @fastify/session issues an anonymous session cookie on any response by
// design (regardless of login success) -- that alone doesn't mean anything.
// What matters is that cookie doesn't carry authentication: the same
// request context (Playwright persists cookies across calls) must still
// be rejected from a protected route.
const hostsRes = await request.get("/api/hosts");
expect(hostsRes.status()).toBe(401);
});
});