Files
m038andClaude Opus 4.8 d576487886 test(post): share createPhotoEntry helper and fix cleanup leak
Hoist the duplicated per-spec createEntry photo-fixture into a single
createPhotoEntry() in helpers.js (used by delete-flow, edit-mode, and the
anon-view draft). Register the tag for cleanup BEFORE the awaited 15s
success-toast assertion, so a create that lands on disk but whose toast
assertion times out no longer leaks an untracked entry. Add AE3b covering the
disclosure deviation branch (a non-default toggle auto-expands More options).

Code review F2 (leak), F3 (duplication), F6 (coverage).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-07 08:32:09 +02:00

67 lines
3.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// @ts-check
// Tests: AN1AN2 — the anonymous (logged-out) visitor's view of the active trip.
//
// Every other spec runs as the authenticated owner, so nothing guards the
// owner/anon boundary. These assert the two things that boundary must enforce
// (R5, KTD7):
// - AN1: owner-only controls (Edit/Delete, data-entry-route) never render for
// an anonymous visitor, even though published entries are visible.
// - AN2: an unpublished DRAFT is shown to the owner (with a badge) but is
// completely absent for an anonymous visitor.
//
// The whole file runs UNauthenticated by clearing storageState. AN2 spins up a
// short-lived authenticated context to create the draft fixture and confirm the
// owner-visible side.
const { test, expect } = require('@playwright/test');
const { createPhotoEntry, cleanupEntry, findEntry, ACTIVE_TRIP_URL } = require('../helpers');
const AUTH_STATE = 'tests/.auth/user.json';
const BASE = process.env.GRAV_BASE_URL || 'http://localhost:8081';
// Run this file with NO owner session.
test.use({ storageState: { cookies: [], origins: [] } });
const created = [];
test.afterAll(() => created.forEach(cleanupEntry));
// ── AN1: anonymous visitor sees content but no owner controls ─────────────────
test('AN1: an anonymous visitor sees published entries but no owner controls', async ({ page }) => {
await page.goto(ACTIVE_TRIP_URL);
// The demo trip has published journal cards — content is public.
await expect(page.locator('.journal-post').first()).toBeVisible();
// …but none of the owner-only affordances are present in the markup.
await expect(page.locator('.journal-post-actions')).toHaveCount(0);
await expect(page.locator('.entry-action--edit')).toHaveCount(0);
await expect(page.locator('.entry-action--delete')).toHaveCount(0);
await expect(page.locator('[data-entry-route]')).toHaveCount(0);
});
// ── AN2: a draft is owner-only ────────────────────────────────────────────────
test('AN2: a draft entry is shown to the owner but hidden from an anonymous visitor', async ({ page, browser }) => {
const tag = `draft-${Date.now()}`;
// Create an UNPUBLISHED entry as the owner, in a separate authed context.
const owner = await browser.newContext({ storageState: AUTH_STATE, baseURL: BASE });
const op = await owner.newPage();
await createPhotoEntry(op, tag, {
created,
publish: false,
content: `Draft body ${tag}. Safe to delete.`,
});
expect(findEntry(tag), 'draft fixture should exist on disk').not.toBeNull();
// Owner side: the draft appears in the feed WITH a Draft badge.
await op.goto(ACTIVE_TRIP_URL);
const ownerCard = op.locator('.journal-post', { hasText: tag });
await expect(ownerCard).toHaveCount(1);
await expect(ownerCard.locator('.journal-draft-badge')).toBeVisible();
await owner.close();
// Anonymous side (the default page fixture): the draft is nowhere to be seen.
await page.goto(ACTIVE_TRIP_URL);
await expect(page.locator('.journal-post', { hasText: tag })).toHaveCount(0);
await expect(page.locator('body')).not.toContainText(tag);
});