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
83 lines
4.0 KiB
JavaScript
83 lines
4.0 KiB
JavaScript
// @ts-check
|
||
// Tests: ES1–ES3 — edit mode field SAVE round-trip + prefill error states.
|
||
//
|
||
// Complements photo-editor.spec.js (which covers the live photo add/delete/
|
||
// reorder inside edit mode). Here we cover the *text* side of edit mode:
|
||
// - ES1 drives a real end-to-end save: create → open the feed card's Edit link
|
||
// → change title + body → Save → assert the new values land back on disk.
|
||
// - ES2/ES3 mock the prefill fetch to force the two D7 failure branches
|
||
// (404 "no longer exists" vs a transient "couldn't be loaded") — the copy
|
||
// that tells the owner whether a retry is worthwhile. These had zero coverage.
|
||
const { test, expect } = require('@playwright/test');
|
||
const {
|
||
fillEditor, createPhotoEntry, cleanupEntry, findEntry, readEntryMd, ACTIVE_TRIP_URL,
|
||
} = require('../helpers');
|
||
|
||
// Synthetic route for the mocked error tests — never has to exist on disk.
|
||
const MISSING_ROUTE = '/trips/italy-2026-demo/dailies/does-not-exist';
|
||
|
||
const created = [];
|
||
test.afterAll(() => created.forEach(cleanupEntry));
|
||
|
||
// ── ES1: edit-mode save writes the changed title + body back to disk ──────────
|
||
test('ES1: editing an entry saves the changed title and body back in place', async ({ page }) => {
|
||
const tag = `es1-${Date.now()}`;
|
||
await createPhotoEntry(page, tag, { created });
|
||
|
||
// Reach edit mode the way the owner does: via the feed card's Edit link.
|
||
await page.goto(ACTIVE_TRIP_URL);
|
||
const card = page.locator('.journal-post', { hasText: tag });
|
||
await expect(card).toHaveCount(1);
|
||
const editHref = await card.locator('.entry-action--edit').getAttribute('href');
|
||
expect(editHref).toContain('/post?edit=');
|
||
|
||
await page.goto(editHref);
|
||
// Prefill is async (GET /api/v1/pages{route}); wait until it populates.
|
||
await expect(page.locator('input[name="data[title]"]'))
|
||
.toHaveValue(`UI Test ${tag}`, { timeout: 15_000 });
|
||
|
||
await page.fill('input[name="data[title]"]', `UI Test ${tag} EDITED`);
|
||
await fillEditor(page, `Edited body for ${tag}.`);
|
||
await page.locator('.btn-post').evaluate(el => el.click());
|
||
|
||
// overwrite_mode:edit writes back in place — assert both changes on disk.
|
||
await expect.poll(() => {
|
||
const dir = findEntry(tag);
|
||
return dir ? (readEntryMd(dir) || '') : '';
|
||
}, { timeout: 15_000 }).toContain('EDITED');
|
||
|
||
const md = readEntryMd(findEntry(tag));
|
||
expect(md, 'edited body should persist').toContain(`Edited body for ${tag}.`);
|
||
});
|
||
|
||
// ── ES2: prefill 404 → the "no longer exists" (deleted) branch ────────────────
|
||
test('ES2: opening a deleted entry for editing shows the "no longer exists" notice', async ({ page }) => {
|
||
await page.route('**/api/v1/pages/**', (route) => {
|
||
if (route.request().method() === 'GET') return route.fulfill({ status: 404, body: '' });
|
||
return route.continue();
|
||
});
|
||
|
||
await page.goto('/post?edit=' + encodeURIComponent(MISSING_ROUTE));
|
||
|
||
const banner = page.locator('.post-edit-error');
|
||
await expect(banner).toContainText('no longer exists', { timeout: 15_000 });
|
||
await expect(banner).toHaveAttribute('role', 'alert');
|
||
// D7: the form is left empty rather than half-filled.
|
||
await expect(page.locator('input[name="data[title]"]')).toHaveValue('');
|
||
});
|
||
|
||
// ── ES3: prefill 500 → the transient "couldn't be loaded" (retry) branch ──────
|
||
test('ES3: a transient prefill failure shows the retry-able "be loaded" notice', async ({ page }) => {
|
||
await page.route('**/api/v1/pages/**', (route) => {
|
||
if (route.request().method() === 'GET') return route.fulfill({ status: 500, body: '' });
|
||
return route.continue();
|
||
});
|
||
|
||
await page.goto('/post?edit=' + encodeURIComponent(MISSING_ROUTE));
|
||
|
||
// Copy differs from the 404 case so the owner knows a retry is worthwhile.
|
||
await expect(page.locator('.post-edit-error'))
|
||
.toContainText('be loaded for editing', { timeout: 15_000 });
|
||
await expect(page.locator('input[name="data[title]"]')).toHaveValue('');
|
||
});
|