trails/e2e/explore.test.ts
Ullrich Schäfer 7a290cd56f
e2e: register and repair the settings/explore/social specs
settings.test.ts, explore.test.ts, and social.test.ts weren't matched
by any Playwright project, so they had silently never run — which is
how they rotted. Register them (one project each) and repair the
selectors against the current UI:

- settings: the page was split into sibling sections
  (/settings/{profile,security,account}); the spec assumed one page.
  Navigate to the right sub-page per test, use the stable section-nav
  links + #id input locators (the Vite dev server transiently
  double-renders the profile form during hydration, breaking
  getByLabel), and wait for hydration before interacting with
  fetcher-backed forms and the avatar dropdown.
- explore: setProfileVisibility now targets /settings/profile and
  waits for hydration so the visibility save uses the fetcher.
- social: already green once registered.

Also fixes an app bug the specs surfaced: deleting a passkey redirected
to /settings#security, a stale anchor that now resolves to
/settings/profile — so you'd land on the wrong section. It now
redirects to /settings/security.

Verified locally against Postgres/BRouter: green under CI-style
retries (the residual registration flake is the same cold-start class
the rest of the suite has, which is why CI runs retries=2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 08:32:18 +02:00

51 lines
2.2 KiB
TypeScript

import { test, expect, waitForHydration, type CDPSession, type Page } from "./fixtures/test";
import { setupVirtualAuthenticator, registerUser } from "./helpers/auth";
async function setProfileVisibility(page: Page, value: "public" | "private") {
await page.goto("/settings/profile");
// Wait for hydration so the visibility form submits via the fetcher
// (and shows the "Profile saved." toast) instead of native-navigating.
await waitForHydration(page);
await page.locator(`input[type=radio][name=profileVisibility][value=${value}]`).check();
await page.getByRole("button", { name: /^Save$/ }).first().click();
await expect(page.getByText("Profile saved.")).toBeVisible({ timeout: 10000 });
}
test.describe.configure({ mode: "serial" });
test.describe("/explore", () => {
test("anonymous visitor can load /explore", async ({ page }) => {
const resp = await page.goto("/explore");
expect(resp?.status()).toBe(200);
await expect(page.getByRole("heading", { name: "Explore" })).toBeVisible();
});
test("private profile is excluded from the directory", async ({ page, browser }) => {
const cdp = await page.context().newCDPSession(page);
await setupVirtualAuthenticator(cdp);
const stamp = Date.now();
// A: signed-in viewer (public, default in test below)
const aEmail = `ex-a-${stamp}@example.com`;
const aUsername = `exa${stamp}`;
await registerUser(page, aEmail, aUsername);
await setProfileVisibility(page, "public");
// B: a separate user who stays at the default `private`
const bCtx = await browser.newContext();
const bPage = await bCtx.newPage();
const bCdp = await bPage.context().newCDPSession(bPage);
await setupVirtualAuthenticator(bCdp);
const bEmail = `ex-b-${stamp}@example.com`;
const bUsername = `exb${stamp}`;
await registerUser(bPage, bEmail, bUsername);
// B stays private — should NOT appear on /explore.
// A loads /explore — the directory should include A but not B.
await page.goto("/explore");
await expect(page.getByText(`@${aUsername}`)).toBeVisible({ timeout: 5000 });
await expect(page.getByText(`@${bUsername}`)).toHaveCount(0);
await bCtx.close();
});
});