mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
Add /, /settings/integrations to the WCAG 2.1 AA serious+critical sweep under an authenticated test.use(storageState). /admin is parked as test.fixme() because the overview page surfaces three real critical violations (button-name × N, select-name × 1, colour-contrast × 1) all originating in src/components/admin/**, which Phase 4b is restructuring concurrently — re-enable the audit once 4b ships. Repair pre-existing breakage in login.spec.ts: the "Login with password" copy was renamed to "Sign in with password" months ago, but the regex never tracked it. Also disambiguate the strict-mode violation between the passkey CTA and the password submit (both match /sign in/) by restricting to button[type=submit]. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
74 lines
2.5 KiB
TypeScript
74 lines
2.5 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
/**
|
|
* Smoke checks on the login surface — must render, must wire the
|
|
* password-manager autofill hints (autoComplete="username" /
|
|
* "current-password"), must let the user submit.
|
|
*
|
|
* These do NOT log in (no DB seed required); the password-flow
|
|
* roundtrip is exercised by the integration test in
|
|
* tests/integration/auth-flow.test.ts.
|
|
*/
|
|
async function openPasswordForm(page: import("@playwright/test").Page) {
|
|
await page.goto("/auth/login");
|
|
// The login page defaults to passkey mode; the password form is
|
|
// mounted only after clicking the "Login with password" / "Mit
|
|
// Passwort anmelden" outline button.
|
|
await page
|
|
.getByRole("button", {
|
|
name: /sign in with password|login with password|mit passwort/i,
|
|
})
|
|
.click();
|
|
}
|
|
|
|
test.describe("login page", () => {
|
|
test("renders username + password inputs with the right autoComplete", async ({
|
|
page,
|
|
}) => {
|
|
await openPasswordForm(page);
|
|
|
|
const username = page
|
|
.getByLabel(/username|benutzername|email|e-mail/i)
|
|
.first();
|
|
await expect(username).toBeVisible();
|
|
await expect(username).toHaveAttribute("autoComplete", /username|email/);
|
|
|
|
const password = page.locator('input[type="password"]').first();
|
|
await expect(password).toBeVisible();
|
|
await expect(password).toHaveAttribute("autoComplete", "current-password");
|
|
});
|
|
|
|
test("rejects an obviously-wrong credential pair", async ({ page }) => {
|
|
await openPasswordForm(page);
|
|
|
|
await page
|
|
.getByLabel(/username|benutzername|email|e-mail/i)
|
|
.first()
|
|
.fill("nobody-here");
|
|
await page.locator('input[type="password"]').first().fill("not-the-pw");
|
|
|
|
// Intercept the API call so the test does not depend on a real
|
|
// backend rejecting the credentials. The login form's error
|
|
// surfacing is what we actually want to prove here.
|
|
await page.route("**/api/auth/login", (route) =>
|
|
route.fulfill({
|
|
status: 401,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({ error: "Invalid credentials" }),
|
|
}),
|
|
);
|
|
|
|
// The form has multiple buttons matching /sign in/ — both the
|
|
// passkey CTA and the password submit. Filter to the submit button
|
|
// so the click lands on the right one.
|
|
await page
|
|
.locator('button[type="submit"]')
|
|
.filter({ hasText: /login|anmelden|sign in/i })
|
|
.click();
|
|
|
|
await expect(
|
|
page.getByText(/invalid credentials|ungültig|falsch/i),
|
|
).toBeVisible({ timeout: 5_000 });
|
|
});
|
|
});
|