// @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(''); });