Coverage goal delivered and verified (39 post specs pass on :8091); superseded by 2026-07-07-journal-post-form-review-handover-and-qa.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
9.0 KiB
Session handover — Playwright coverage for the edit-mode photo editor
✅ COMPLETE (2026-07-07) — SUPERSEDED by
2026-07-05→2026-07-07-journal-post-form-review-handover-and-qa.md. The requested coverage landed:tests/ui/post/photo-editor.spec.js+edit-mode.spec.jsnow cover the add/delete/reorder happy and failure paths (auth-expiry "sign in again" E5/E7, retry-able delete failure E4/DEL3, prefill-failure ES2/ES3). Verified green:39 passedon:8091(2026-07-07). All remaining work (owner UI QA + landing) is tracked in the 2026-07-07 handover. This file is retained for history only — no further action.
Date: 2026-07-05
Branch: feat/journal-post-form (worktree: .worktrees/journal-post-form)
Next session goal: Add Playwright coverage for the edit-mode photo editor add / delete / reorder paths — especially the failure paths just implemented, which currently have zero automated coverage.
TL;DR — where things stand
The photo-editor media-API feature is code-complete and committed but not smoke-tested. Three review follow-ups landed this session (commit 7ffd75e) on the edit-mode add/delete/reorder failure paths. Those paths are exercised by no existing test, so nothing proves the behavioral changes work end-to-end. That's the whole reason for the next session.
Do not push, do not bump the submodule pin, and do not touch the other-session WIP (see Constraints) until the new tests pass and Mischa says go.
Git state at handover
Outer repo (.worktrees/journal-post-form):
HEAD=7534d7d test(post-form): expect zero-padded photo-01..NN filenames- Status: only
M user— the submodule pin is intentionally stale (not bumped mid-feature; per project convention bump once at feature end). Leave it.
user/ submodule (branch feat/journal-post-form):
HEAD=7ffd75e fix(review): surface auth-expiry, harden add-batch rollback, add audit log361a6b4 fix(review): harden photo reorder against data loss + failure-path drifta4432d8 feat(post-form): live photo editor on entry edit (media API + SortableJS)
- Dirty (DO NOT COMMIT — belongs to a different session):
config/plugins/api.yamlconfig/site.yamlthemes/intotheeast/js/src/post-form.css(a trailing FilePond CSS block)
- Nothing pushed on either repo.
What commit 7ffd75e changed (the code under test)
All in the edit-mode photo editor (the initPhotoEditor IIFE in
user/themes/intotheeast/js/src/post-form.js, bundled to
user/themes/intotheeast/js/post/post-form.js):
- Surfaced auth-expiry. Replaced the boolean
apiOkwithapiSend(url, opts, okStatuses), which rejects with anErrorcarrying.status. A lapsed owner login mid-edit (401/403) now shows "Your login session expired — sign in again, then retry." instead of a generic "try again". Applies to reorder, delete, and add paths (editErrorMsg(err, fallback)picks the copy). - Hardened the add-batch rollback (review item #6). When a post-upload reorder fails, the cleanup DELETEs no longer swallow individual failures. Each rollback DELETE resolves true/false (204/404 = truly gone); any
falsesetsrollbackIncomplete, producing "Couldn't finish adding photos and cleanup was incomplete — reload the page and check your photos." instead of a false "rolled back cleanly". This closes the window where a surviving stock-named file steals the lexicographic cover slot (media.images|first). - Audit log on the two owner-only destructive routes in
user/plugins/entry-actions/classes/EntryActionsApiController.php(deleteEntry,reorderPhotos) — behaviorally inert, logs owner + slug. Not worth a Playwright test.
User-facing strings to assert against (stable; survive minification):
login session expired/sign in againcleanup was incomplete- The N-photos-couldn't-be-added count message
The API surface the editor talks to
- Add photo:
POST /api/v1/pages{route}/media(stock media API, multipart) - Delete photo:
DELETE /api/v1/pages{route}/media/{filename}— editor treats 204 and 404 as success - Reorder:
POST /api/v1/entry/{slug}/photos/order, body{ "order": ["photo-01.jpg", …] }— custom scope-guarded route in theentry-actionsplugin; returns 204 - All requests use
credentials: 'include'(session-cookie auth).
Server-side numbering invariant lives in PhotoRenumberer (shared by cache-on-save + entry-actions): every on-disk image is renamed photo-01..NN zero-padded; the manifest only supplies order, and any unlisted image is appended (never lost).
Test harness facts (read before writing specs)
- Runner: Playwright, config at
playwright.config.js.testDir: ./tests/ui. Specs are*.spec.js. - Auth is already solved. The
setupproject (tests/ui/auth/auth.setup.js) logs in withGRAV_TEST_USER/GRAV_TEST_PASS(from.env) and savesstorageStatetotests/.auth/user.json; thechromiumproject loads it. So every test already runs as the authenticated owner — edit mode is reachable without extra login steps. - ⚠️ Port:
baseURLdefaults tohttp://localhost:8081, but this worktree's dev container serves on:8091(itte_journal_grav, mapped8091->80). Run withGRAV_BASE_URL=http://localhost:8091or the specs will hit the wrong container. - Helpers (
tests/ui/helpers.js, exported):fillEditor,waitForPhotoUpload,postEntry,cleanupEntry,findEntry,readEntryMd,TRACKER_DIR,ACTIVE_TRIP_URL.findEntry(tag)/cleanupEntry(tag)locate/remove an entry folder on disk — use them to build a fixture entry and to clean up. - Existing post specs live in
tests/ui/post/(post-form-ux.spec.js,post.spec.js,validation.spec.js). They cover the create form only — none open/post?edit=…or the photo editor. Mirror their style (fixtures attests/fixtures/test-photo*.jpg). - Global setup/teardown:
tests/global-setup.js/tests/global-teardown.js.
Suggested test plan for the next session
Edit mode is GET /post?edit=<slug> (verify the exact param against the template). Failure paths need page.route() interception to force API errors — that's the core technique here.
- Fixture: post one entry via the create form (or drop a folder), capture its slug, open it in edit mode. Clean up with
cleanupEntryinafterAll. - Happy paths (no interception): add a photo → persists (appears on disk / in grid); delete a photo → gone; drag-reorder → files renamed
photo-01..NNin new order. - Auth-expiry (item #1):
page.route('**/api/v1/**', r => r.fulfill({ status: 401 }))on a reorder/delete/add → assert the "login session expired … sign in again" copy appears. - Incomplete rollback (#6): let the uploads succeed but force the reorder to fail and at least one cleanup DELETE to fail (route-match
DELETE **/media/**→ 500). Assert the "cleanup was incomplete — reload" message. This is the highest-value, never-before-tested branch. - Delete failure: force a
DELETEto 500 → assert "Couldn't delete that photo. Try again." and the photo stays in the grid.
Keep assertions on the user-facing strings above, not on minified identifiers.
Also pending: manual smoke test
Independent of automation, the behavioral changes still want one manual owner-session pass on :8091: log in, open an entry in edit mode, add/delete/reorder and confirm each persists; then simulate a lapsed session and confirm the "sign in again" copy. If Playwright covers 2–5 above, this becomes a quick confidence check rather than the only verification.
Constraints (carried from this session — still in force)
- Other-session WIP is off-limits. Do not stage/commit
config/plugins/api.yaml,config/site.yaml, or the FilePond block inthemes/intotheeast/js/src/post-form.css. Ifmake build-assetsrecompilescss-compiled/post-form.cssfrom that dirty source, revert it:git checkout -- themes/intotheeast/css-compiled/post-form.css. - Never read
.env,.env.prod,.env.test(pass them tomake/composeonly).GRAV_TEST_USER/PASSlive there. - Only write inside
travel-blog-intotheeast/or subfolders. - Do not bump the submodule pin or push until the feature is done and Mischa approves.
- Do not hand-edit the bundle (
js/post/post-form.js) orcss-compiled/*— editjs/src/*and rebuild withmake build-assets. - No dev/prod mode switching; fix issues at the app level.
- New test files go in the outer repo (
tests/is outer-repo, not theuser/submodule).
Fast start for the next session
# worktree root
cd /home/mischa/Nextcloud/Projects/travel-blog-intotheeast/.worktrees/journal-post-form
# confirm the dev container is up on 8091
docker ps --format '{{.Names}}\t{{.Ports}}' | grep itte
# run existing post specs against THIS worktree's container
GRAV_BASE_URL=http://localhost:8091 npx playwright test tests/ui/post