From 74071298129bf89df5a764924044e1b164caecda Mon Sep 17 00:00:00 2001 From: Mischa Date: Sat, 4 Jul 2026 13:58:27 +0200 Subject: [PATCH] test: re-point suite off retired standalone views Phase-1 fallout: delete tests for deleted pages, re-point moved-behavior tests to the trip/home page where the content now lives. - maps.spec: keep M4/M7/M8 (home+trip maps); drop M1-3,5,6,9-11 (/map, /dailies & /stories mini-maps) - map-ux: re-point MUX4/5 sort toggle to #trip-sort-toggle on trip page - nav: N1->trip page, N2->home, drop N3 (/stats) + N5 (obsolete skip) - dailies: T1->trip page; T2->trip page with oldest-first assertion; fix T3-T6 stale entry-detail selectors (.entry-* -> .journal-post-*, pre-existing failures from an earlier entry redesign) - stories: S1/S5 -> trip feed story cards ([data-type=story]) - gpx-journey: load MapUtils from the trip page instead of /map - a11y: A4 photo strips -> trip page; drop AX3 (covered by AX2) - post/helpers: verify posted entry on the trip page (ACTIVE_TRIP_URL) Co-Authored-By: Claude Opus 4.8 --- tests/ui/a11y/accessibility.spec.js | 5 +- tests/ui/dailies/dailies.spec.js | 32 ++++---- tests/ui/gpx/gpx-journey.spec.js | 8 +- tests/ui/helpers.js | 19 ++--- tests/ui/maps/map-ux.spec.js | 25 ++++--- tests/ui/maps/maps.spec.js | 109 ++-------------------------- tests/ui/nav/nav.spec.js | 35 +++------ tests/ui/post/post.spec.js | 10 +-- tests/ui/stories/stories.spec.js | 26 +++---- 9 files changed, 80 insertions(+), 189 deletions(-) diff --git a/tests/ui/a11y/accessibility.spec.js b/tests/ui/a11y/accessibility.spec.js index 399c295..c9a6de3 100644 --- a/tests/ui/a11y/accessibility.spec.js +++ b/tests/ui/a11y/accessibility.spec.js @@ -69,7 +69,7 @@ test('A3f: clicking Cycling toggle sets aria-expanded="true" then back to false' // ── A4: Photo strip keyboard navigation ─────────────────────────────────────── test('A4a: all photo strips have role=region and aria-label', async ({ page }) => { - await page.goto('/trips/italy-2026-demo/dailies'); + await page.goto('/trips/italy-2026-demo'); const strips = page.locator('.journal-photo-strip'); const count = await strips.count(); if (count === 0) return; @@ -80,7 +80,7 @@ test('A4a: all photo strips have role=region and aria-label', async ({ page }) = }); test('A4b: multi-slide photo strips have accessible prev/next controls', async ({ page }) => { - await page.goto('/trips/italy-2026-demo/dailies'); + await page.goto('/trips/italy-2026-demo'); const multiCount = await page.locator('.journal-photo-strip').evaluateAll( els => els.filter(el => parseInt(el.dataset.slides, 10) >= 2).length ); @@ -133,7 +133,6 @@ function axeScan(id, url) { axeScan('AX1', '/'); axeScan('AX2', '/trips/italy-2026-demo'); -axeScan('AX3', '/trips/italy-2026-demo/dailies'); axeScan('AX4', '/trips/italy-2026-demo/dailies/2026-09-01-0700-setting-off-from-campiglia.entry'); axeScan('AX5', '/trips'); diff --git a/tests/ui/dailies/dailies.spec.js b/tests/ui/dailies/dailies.spec.js index 96e01a4..36273c6 100644 --- a/tests/ui/dailies/dailies.spec.js +++ b/tests/ui/dailies/dailies.spec.js @@ -12,17 +12,19 @@ const KNOWN_COUNTRY = 'Italy'; const NEWER_SLUG = '2023-10-18-hunting-the-mother-of-georgia-from-above.entry'; // newest date in that trip const OLDER_SLUG = '2023-08-28-welcome-to-my-central-asian-picture-diary.entry'; // oldest date in that trip -// ── T1: Dailies page loads ───────────────────────────────────────────────────── -test('T1: /trips/italy-2026-demo/dailies loads and shows at least one entry card', async ({ page }) => { - await page.goto('/trips/italy-2026-demo/dailies'); +// ── T1: Trip page journal feed loads ────────────────────────────────────────── +// The journal feed moved onto the trip page when the standalone /dailies view was retired. +test('T1: trip page loads and shows at least one journal entry card', async ({ page }) => { + await page.goto('/trips/italy-2026-demo'); await expect(page.locator('.journal-post').first()).toBeVisible(); await expect(page.locator('.site-header')).toBeVisible(); }); -// ── T2: Entries are newest-first ────────────────────────────────────────────── +// ── T2: Trip feed default order is oldest-first ─────────────────────────────── +// The trip page sorts the feed oldest→newest by default (home uses newest-first). // Verify using two known real entries from central-asia-2023 (22 entries, stable order). -test('T2: dailies shows newer entries before older entries', async ({ page }) => { - await page.goto('/trips/central-asia-2023/dailies'); +test('T2: trip feed shows older entries before newer entries (oldest-first default)', async ({ page }) => { + await page.goto('/trips/central-asia-2023'); // Use attribute selector to handle dots in slug names (CSS dots are class selectors) const newerCard = page.locator(`.journal-post[id="entry-${NEWER_SLUG}"]`); @@ -31,7 +33,7 @@ test('T2: dailies shows newer entries before older entries', async ({ page }) => await expect(newerCard).toBeVisible(); await expect(olderCard).toBeVisible(); - // The newer entry should appear higher in the DOM (lower index) + // The older entry should appear higher in the DOM (lower index) const newerIdx = await newerCard.evaluate(el => { return [...document.querySelectorAll('.journal-post')].findIndex(c => c.id === el.id); }); @@ -39,36 +41,36 @@ test('T2: dailies shows newer entries before older entries', async ({ page }) => return [...document.querySelectorAll('.journal-post')].findIndex(c => c.id === el.id); }); - expect(newerIdx).toBeLessThan(olderIdx); + expect(olderIdx).toBeLessThan(newerIdx); }); // ── T3: Individual entry page loads ─────────────────────────────────────────── test('T3: individual entry page loads at /trips/italy-2026-demo/dailies/{slug}', async ({ page }) => { await page.goto(`/trips/italy-2026-demo/dailies/${KNOWN_SLUG}`); - await expect(page.locator('article.entry')).toBeVisible(); + await expect(page.locator('article.journal-post')).toBeVisible(); await expect(page.locator('.site-header')).toBeVisible(); }); // ── T4: Entry page shows title, date, and content ───────────────────────────── test('T4: entry page shows title and body content', async ({ page }) => { await page.goto(`/trips/italy-2026-demo/dailies/${KNOWN_SLUG}`); - await expect(page.locator('.entry-title')).toContainText(KNOWN_TITLE); - await expect(page.locator('.entry-body')).not.toBeEmpty(); - await expect(page.locator('time.entry-date')).toBeVisible(); + await expect(page.locator('.journal-post-title')).toContainText(KNOWN_TITLE); + await expect(page.locator('.journal-post-body')).not.toBeEmpty(); + await expect(page.locator('.journal-post-meta time')).toBeVisible(); }); // ── T5: Entry page shows location when present ──────────────────────────────── test('T5: entry page shows city and country when set', async ({ page }) => { await page.goto(`/trips/italy-2026-demo/dailies/${KNOWN_SLUG}`); - await expect(page.locator('.entry-location')).toContainText(KNOWN_CITY); - await expect(page.locator('.entry-location')).toContainText(KNOWN_COUNTRY); + await expect(page.locator('.journal-post-location')).toContainText(KNOWN_CITY); + await expect(page.locator('.journal-post-location')).toContainText(KNOWN_COUNTRY); }); // ── T6: Entry page has a fixed top back pill and a footer back pill ─────────────── test('T6: entry page has fixed back pill at top and back pill in footer', async ({ page }) => { const KNOWN_ENTRY = `/trips/italy-2026-demo/dailies/${KNOWN_SLUG}`; await page.goto(KNOWN_ENTRY); - await expect(page.locator('article.entry')).toBeVisible(); + await expect(page.locator('article.journal-post')).toBeVisible(); const topPill = page.locator('.entry-back-fixed'); await expect(topPill).toBeVisible(); await expect(topPill).toHaveText(/← Back/); diff --git a/tests/ui/gpx/gpx-journey.spec.js b/tests/ui/gpx/gpx-journey.spec.js index 535862f..13dfa1f 100644 --- a/tests/ui/gpx/gpx-journey.spec.js +++ b/tests/ui/gpx/gpx-journey.spec.js @@ -1,13 +1,13 @@ // @ts-check // Tests: G1–G5 — buildJourneySegments algorithm correctness -// These tests load the italy-2026-demo map page (which has GPX) to get MapUtils in scope, -// then call the functions with synthetic data via page.evaluate. +// These tests load the italy-2026-demo trip page (which has GPX + the map bundle) to get +// MapUtils in scope, then call the functions with synthetic data via page.evaluate. // Requires demo data: run `make demo-load` before this suite. const { test, expect } = require('@playwright/test'); async function getMapUtils(page) { - await page.goto('/trips/italy-2026-demo/map'); - await expect(page.locator('canvas.maplibregl-canvas')).toBeVisible({ timeout: 10000 }); + await page.goto('/trips/italy-2026-demo'); + await expect(page.locator('#trip-map canvas.maplibregl-canvas')).toBeVisible({ timeout: 10000 }); } // G1: No GPX → all pairs connected in one segment diff --git a/tests/ui/helpers.js b/tests/ui/helpers.js index e3892a3..e88fae2 100644 --- a/tests/ui/helpers.js +++ b/tests/ui/helpers.js @@ -62,19 +62,20 @@ const USER_DIR = resolveUserDir(); const TRACKER_DIR = resolveDailiesDir(USER_DIR) || path.join(USER_DIR, 'pages/01.trips/italy-2026-demo/01.dailies'); /** - * The Grav route to the active dailies listing page, - * read from the post-form.md pageconfig.parent value. - * Falls back to '/trips/italy-2026-demo/dailies'. + * The Grav route to the active trip page, derived from the post-form.md + * pageconfig.parent value (the dailies container route, minus the trailing + * `/dailies`). Posted entries surface in this page's journal feed. + * Falls back to '/trips/italy-2026-demo'. */ -function resolveActiveDailiesUrl() { +function resolveActiveTripUrl() { const postFormPath = path.join(USER_DIR, 'pages/02.post/post-form.md'); - if (!fs.existsSync(postFormPath)) return '/trips/italy-2026-demo/dailies'; + if (!fs.existsSync(postFormPath)) return '/trips/italy-2026-demo'; const content = fs.readFileSync(postFormPath, 'utf-8'); - const m = content.match(/parent:\s*['"]?(\/trips\/[^'"]+\/dailies)['"]?/); - return m ? m[1] : '/trips/italy-2026-demo/dailies'; + const m = content.match(/parent:\s*['"]?(\/trips\/[^'"]+)\/dailies['"]?/); + return m ? m[1] : '/trips/italy-2026-demo'; } -const DAILIES_URL = resolveActiveDailiesUrl(); +const ACTIVE_TRIP_URL = resolveActiveTripUrl(); /** * Wait for all filepond items to finish XHR upload. @@ -136,4 +137,4 @@ function readEntryMd(entryDir) { return fs.readFileSync(path.join(entryDir, name), 'utf-8'); } -module.exports = { waitForFilePondUpload, postEntry, cleanupEntry, findEntry, readEntryMd, TRACKER_DIR, DAILIES_URL }; +module.exports = { waitForFilePondUpload, postEntry, cleanupEntry, findEntry, readEntryMd, TRACKER_DIR, ACTIVE_TRIP_URL }; diff --git a/tests/ui/maps/map-ux.spec.js b/tests/ui/maps/map-ux.spec.js index cce2fd8..a1a207a 100644 --- a/tests/ui/maps/map-ux.spec.js +++ b/tests/ui/maps/map-ux.spec.js @@ -48,11 +48,13 @@ test('MUX3: trip page map has a fullscreen toggle button', async ({ page }) => { await expect(fsBtn).toHaveAttribute('aria-label', 'Expand map'); }); -// ── MUX4: Dailies sort toggle reverses entry order ─────────────────────────── -test('MUX4: dailies sort toggle reverses the feed entry order', async ({ page }) => { - await page.goto('/trips/italy-2026-demo/dailies'); +// ── MUX4: Trip feed sort toggle reverses entry order ───────────────────────── +// The sort toggle moved onto the trip page (#trip-sort-toggle) when the standalone +// /dailies feed view was retired. +test('MUX4: trip feed sort toggle reverses the feed entry order', async ({ page }) => { + await page.goto('/trips/italy-2026-demo'); - const sortBtn = page.locator('#feed-sort-toggle'); + const sortBtn = page.locator('#trip-sort-toggle'); await expect(sortBtn).toBeVisible(); const firstBefore = await page.locator('[data-type]').first().getAttribute('id'); @@ -67,21 +69,22 @@ test('MUX4: dailies sort toggle reverses the feed entry order', async ({ page }) expect(firstRestored, 'Entry order restored after second toggle').toBe(firstBefore); }); -// ── MUX5: Stories sort toggle reverses story card order ───────────────────── -test('MUX5: stories sort toggle reverses the story card order', async ({ page }) => { - await page.goto('/trips/italy-2026-demo/stories'); +// ── MUX5: Trip feed sort toggle reverses story card order ──────────────────── +// Story cards live in the trip feed as [data-type="story"] (the /stories grid was retired). +test('MUX5: trip feed sort toggle reverses the story card order', async ({ page }) => { + await page.goto('/trips/italy-2026-demo'); - const sortBtn = page.locator('#feed-sort-toggle'); + const sortBtn = page.locator('#trip-sort-toggle'); await expect(sortBtn).toBeVisible(); - const firstBefore = await page.locator('.story-card').first().getAttribute('id'); + const firstBefore = await page.locator('[data-type="story"]').first().getAttribute('id'); await sortBtn.click(); - const firstAfter = await page.locator('.story-card').first().getAttribute('id'); + const firstAfter = await page.locator('[data-type="story"]').first().getAttribute('id'); expect(firstAfter, 'Story order reversed after sort').not.toBe(firstBefore); await sortBtn.click(); - const firstRestored = await page.locator('.story-card').first().getAttribute('id'); + const firstRestored = await page.locator('[data-type="story"]').first().getAttribute('id'); expect(firstRestored, 'Story order restored after second toggle').toBe(firstBefore); }); diff --git a/tests/ui/maps/maps.spec.js b/tests/ui/maps/maps.spec.js index 82d3bf4..41fce8d 100644 --- a/tests/ui/maps/maps.spec.js +++ b/tests/ui/maps/maps.spec.js @@ -1,38 +1,11 @@ // @ts-check -// Tests: M1–M4 — MapLibre GL canvas renders on all three map surfaces +// Tests: M4, M7, M8 — MapLibre GL renders on the two live map surfaces (home + trip page). +// The standalone /map, /dailies mini-map and /stories mini-map surfaces were retired +// (see docs/working/plans/2026-07-04-standalone-page-cleanup.md); their coverage now +// lives on the trip and home maps, both driven by MapUtils.initEntryMap(). // Requires demo data: run `make demo-load` before this suite. const { test, expect } = require('@playwright/test'); -// ── M1: Full map page renders MapLibre canvas ───────────────────────────────── -test('M1: /map page renders MapLibre GL canvas without JS errors', async ({ page }) => { - const errors = []; - page.on('pageerror', e => errors.push(e.message)); - - await page.goto('/trips/italy-2026-demo/map'); - await expect(page.locator('canvas.maplibregl-canvas')).toBeVisible({ timeout: 10000 }); - expect(errors, 'No JS errors on map page').toHaveLength(0); -}); - -// ── M2: Full map page — dot markers are in the DOM ─────────────────────────── -test('M2: /map page has at least one dot marker', async ({ page }) => { - await page.goto('/trips/italy-2026-demo/map'); - await expect(page.locator('canvas.maplibregl-canvas')).toBeVisible({ timeout: 10000 }); - // Markers are added in map.on('load') — wait for first to appear in the DOM - await expect(page.locator('.maplibregl-marker').first()).toBeVisible({ timeout: 15000 }); - const markerCount = await page.locator('.maplibregl-marker').count(); - expect(markerCount, 'At least one marker present').toBeGreaterThan(0); -}); - -// ── M3: Dailies mini-map renders MapLibre canvas ───────────────────────────── -test('M3: Dailies mini-map renders MapLibre GL canvas without JS errors', async ({ page }) => { - const errors = []; - page.on('pageerror', e => errors.push(e.message)); - - await page.goto('/trips/italy-2026-demo/dailies'); - await expect(page.locator('#feed-map canvas.maplibregl-canvas')).toBeVisible({ timeout: 10000 }); - expect(errors, 'No JS errors on dailies page').toHaveLength(0); -}); - // ── M4: Home map renders MapLibre canvas ───────────────────────────────────── test('M4: Home page map renders MapLibre GL canvas without JS errors', async ({ page }) => { const errors = []; @@ -43,42 +16,6 @@ test('M4: Home page map renders MapLibre GL canvas without JS errors', async ({ expect(errors, 'No JS errors on home page').toHaveLength(0); }); -// ── M5: Italy map — no JS errors with GPX present ──────────────────────────── -test('M5: Italy map page renders without JS errors (GPX present)', async ({ page }) => { - const errors = []; - page.on('pageerror', e => errors.push(e.message)); - - await page.goto('/trips/italy-2026-demo/map'); - await expect(page.locator('canvas.maplibregl-canvas')).toBeVisible({ timeout: 10000 }); - // Wait for markers to confirm map.on('load') completed - await expect(page.locator('.maplibregl-marker').first()).toBeVisible({ timeout: 15000 }); - // Give Promise.all time to resolve - await page.waitForTimeout(3000); - - expect(errors, 'No JS errors on Italy map page').toHaveLength(0); -}); - -// ── M6: Italy map — journey source exists after GPX loads ──────────────────── -test('M6: Italy map has a journey MapLibre source after GPX settles', async ({ page }) => { - await page.goto('/trips/italy-2026-demo/map'); - await expect(page.locator('canvas.maplibregl-canvas')).toBeVisible({ timeout: 10000 }); - await expect(page.locator('.maplibregl-marker').first()).toBeVisible({ timeout: 15000 }); - - // Wait until the journey source appears — addJourneySegments runs inside Promise.all.then() - // `var map = ...` in map.html.twig is a plain