import { test, expect } from "@playwright/test"; const PASSWORD = process.env.TEST_ACCOUNT_PASSWORD || "e2e-test-password"; // The login error panel is driven by a stable ?error= code the server // attaches on failed OAuth redirects. The app clears the query string on // load, so these assert on the rendered panel, never on the transient URL. test("a ?error= code on load renders the designed login error panel", async ({ page, }) => { await page.goto("/?error=access_denied"); await expect(page.locator(".login-error")).toBeVisible(); await expect(page.locator(".login-error__code")).toHaveText("ACCESS_DENIED"); await expect(page.locator(".login-error__copy")).toContainText( "turned the request down", ); }); test("an unresolvable handle redirects back with resolve_failed copy", async ({ page, }) => { await page.goto("/"); await page.fill('input[type="text"]', "no-such-handle.test"); await page.click("text=LOG IN WITH ATPROTO"); await expect(page.locator(".login-error")).toBeVisible({ timeout: 15_000 }); await expect(page.locator(".login-error__code")).toHaveText( "RESOLVE_FAILED", ); await expect(page.locator(".login-error__copy")).toContainText( "Couldn't find that handle's PDS", ); }); test("denying authorization at the PDS lands on the error panel", async ({ page, }) => { await page.goto("/"); await page.fill('input[type="text"]', "alice.test"); await page.click("text=LOG IN WITH ATPROTO"); await page.waitForURL(/oauth\/authorize/, { timeout: 15_000 }); await page.fill('input[type="password"]', PASSWORD); await page.click('button:has-text("Sign in")'); const deny = page.locator('button:has-text("Deny")'); await deny.waitFor({ timeout: 15_000 }); await deny.click(); await expect(page.locator(".login-error")).toBeVisible({ timeout: 15_000 }); await expect(page.locator(".login-error__code")).toHaveText( "ACCESS_DENIED", ); });