Fix e2e fallout from default-private profile_visibility
Three places assumed the old default-public model: 1. e2e/public-content.test.ts: "profile 404 when user has no public content" → updated to assert the new locked-account stub renders 200 with "This profile is private" and the private route doesn't appear. The two follow-on tests (public-route profile, unlisted route) now flip the owner to public via a setProfileVisibilityPublic helper before the anon-visit assertions, since new users default to private. 2. e2e/demo-bot.test.ts: bruno is seeded with profile_visibility = 'public' on insert (timestamped seed) and the existing-bruno path gets a follow-up UPDATE so the test's anon-visitor assertion (profile renders, public route is listed) holds regardless of which default he was first created under. 3. apps/journal/app/lib/demo-bot.server.ts ensureDemoUser: also pins profile_visibility = 'public' on insert. The demo persona is discoverable by design — that's the whole point. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5da7ffa037
commit
ff09775091
3 changed files with 41 additions and 7 deletions
|
|
@ -279,6 +279,11 @@ export async function ensureDemoUser(
|
|||
displayName: persona.displayName,
|
||||
bio: persona.bio,
|
||||
domain,
|
||||
// The demo persona is meant to be discoverable to anyone — its
|
||||
// entire purpose is to populate empty instances with public
|
||||
// content. Force `public` even though new accounts default to
|
||||
// `private` (locked-account model).
|
||||
profileVisibility: "public",
|
||||
termsAcceptedAt: new Date(),
|
||||
termsVersion: TERMS_VERSION,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -19,9 +19,12 @@ async function seedBrunoWithSyntheticRoute(): Promise<{ username: string; routeN
|
|||
const userId = randomUUID();
|
||||
const routeId = randomUUID();
|
||||
try {
|
||||
// Demo bot needs profile_visibility='public' so anon visitors see
|
||||
// his profile in full (the locked-account default would render a
|
||||
// stub instead).
|
||||
await sql`
|
||||
INSERT INTO journal.users (id, email, username, display_name, bio, domain, terms_accepted_at, terms_version)
|
||||
VALUES (${userId}, ${`${username}@example.com`}, ${username}, 'Bruno', 'Professional park inspector.', 'localhost', now(), '2026-04-19')
|
||||
INSERT INTO journal.users (id, email, username, display_name, bio, domain, profile_visibility, terms_accepted_at, terms_version)
|
||||
VALUES (${userId}, ${`${username}@example.com`}, ${username}, 'Bruno', 'Professional park inspector.', 'localhost', 'public', now(), '2026-04-19')
|
||||
`;
|
||||
await sql`
|
||||
INSERT INTO journal.routes (id, owner_id, name, description, visibility, synthetic, distance, created_at, updated_at)
|
||||
|
|
@ -79,13 +82,18 @@ test.describe("Demo-bot UX", () => {
|
|||
// Use ON CONFLICT so a pre-existing prod `bruno` user doesn't block
|
||||
// the test; we don't clean up a row we didn't create.
|
||||
const created = await sql`
|
||||
INSERT INTO journal.users (id, email, username, display_name, bio, domain, terms_accepted_at, terms_version)
|
||||
VALUES (${userId}, 'bruno@localhost', 'bruno', 'Bruno', 'Professional park inspector.', 'localhost', now(), '2026-04-19')
|
||||
INSERT INTO journal.users (id, email, username, display_name, bio, domain, profile_visibility, terms_accepted_at, terms_version)
|
||||
VALUES (${userId}, 'bruno@localhost', 'bruno', 'Bruno', 'Professional park inspector.', 'localhost', 'public', now(), '2026-04-19')
|
||||
ON CONFLICT (username) DO NOTHING
|
||||
RETURNING id
|
||||
`;
|
||||
const weCreatedIt = created.length > 0;
|
||||
const effectiveUserId = weCreatedIt ? userId : (await sql`SELECT id FROM journal.users WHERE username='bruno'`)[0]!.id as string;
|
||||
// Make sure bruno is public regardless of who created him — the
|
||||
// demo profile must render in full for anon visitors. If he was
|
||||
// pre-existing with `private` (e.g. on a fresh DB after the
|
||||
// default flipped), force him public for this test's purposes.
|
||||
await sql`UPDATE journal.users SET profile_visibility = 'public' WHERE id = ${effectiveUserId}`;
|
||||
|
||||
await sql`
|
||||
INSERT INTO journal.routes (id, owner_id, name, description, visibility, synthetic, distance, created_at, updated_at)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ async function setRouteVisibility(
|
|||
await page.waitForURL(new RegExp(`/routes/${id}$`), { timeout: 10000 });
|
||||
}
|
||||
|
||||
// New users default to profile_visibility='private' (locked-account
|
||||
// model). Tests that need an anon visitor to see the profile in full
|
||||
// have to flip the owner to public first.
|
||||
async function setProfileVisibilityPublic(page: Page) {
|
||||
await page.goto("/settings");
|
||||
await page.getByLabel("Public").check();
|
||||
await page.getByRole("button", { name: /^Save$/ }).first().click();
|
||||
await page.waitForLoadState("networkidle");
|
||||
}
|
||||
|
||||
// Registration + WebAuthn virtual authenticator can race under parallel
|
||||
// Playwright workers on a shared local Postgres; run this file serially.
|
||||
test.describe.configure({ mode: "serial" });
|
||||
|
|
@ -111,19 +121,28 @@ test.describe("Public content visibility", () => {
|
|||
await expect(page.getByRole("heading", { name: "My only route" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("profile 404 when user has no public content", async ({ page, browser }) => {
|
||||
test("profile renders private stub when user has no public content (locked model)", async ({ page, browser }) => {
|
||||
const cdp = await page.context().newCDPSession(page);
|
||||
await setupVirtualAuthenticator(cdp);
|
||||
|
||||
const email = `pcv-empty-${Date.now()}@example.com`;
|
||||
const username = `pcvempty${Date.now()}`;
|
||||
await registerUser(page, email, username);
|
||||
await createRoute(page, "Private thoughts"); // left private
|
||||
// New users default to profile_visibility='private', so an anonymous
|
||||
// visitor sees the locked-account stub (200, not 404). Their private
|
||||
// route never appears.
|
||||
const id = await createRoute(page, "Private thoughts"); // left private
|
||||
|
||||
const anonCtx = await browser.newContext();
|
||||
const anon = await anonCtx.newPage();
|
||||
const resp = await anon.goto(`/users/${username}`);
|
||||
expect(resp?.status()).toBe(404);
|
||||
expect(resp?.status()).toBe(200);
|
||||
await expect(anon.getByText(/This profile is private/i)).toBeVisible();
|
||||
await expect(anon.getByText("Private thoughts")).not.toBeVisible();
|
||||
// Direct route URL still 404s for visitors because the route itself
|
||||
// is private-visibility.
|
||||
const direct = await anon.goto(`/routes/${id}`);
|
||||
expect(direct?.status()).toBe(404);
|
||||
await anonCtx.close();
|
||||
});
|
||||
|
||||
|
|
@ -134,6 +153,7 @@ test.describe("Public content visibility", () => {
|
|||
const email = `pcv-prof-${Date.now()}@example.com`;
|
||||
const username = `pcvprof${Date.now()}`;
|
||||
await registerUser(page, email, username);
|
||||
await setProfileVisibilityPublic(page);
|
||||
const id = await createRoute(page, "Bikepacking loop");
|
||||
await setRouteVisibility(page, id, "public");
|
||||
|
||||
|
|
@ -154,6 +174,7 @@ test.describe("Public content visibility", () => {
|
|||
const email = `pcv-unl-${Date.now()}@example.com`;
|
||||
const username = `pcvunl${Date.now()}`;
|
||||
await registerUser(page, email, username);
|
||||
await setProfileVisibilityPublic(page);
|
||||
|
||||
// Two routes: one unlisted, one public — profile shows only the public one.
|
||||
const publicId = await createRoute(page, "Public one");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue