- trip-header/trips-list specs now assert the cropZoom wide-strip aspect and the all-or-nothing retina rule (1x-only for sub-2w sources), and a new regression on us-canada-mex-2024 covers the reported portrait-blur - remove the orphaned AE4 test (no-photos-demo fixture was deleted) - backlog: full-res pixelfed reimport (luxury quality item) - plan: record the cover-quality follow-up + AE4 fixture removal - bump user pin -> 536ca20 (trip-description-hero cover fix) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
70 lines
3.7 KiB
JavaScript
70 lines
3.7 KiB
JavaScript
// @ts-check
|
||
// Tests: U3 — trip-list card one-liner + retina cover (R5, R6, R7, R14)
|
||
// R11 (set-but-unresolvable cover_image falls back) shares the exact else-branch
|
||
// exercised by the R7/AE3 fallback test below; it is covered by construction in
|
||
// the shared cover macro rather than by a dedicated fixture here.
|
||
const { test, expect } = require('@playwright/test');
|
||
|
||
const DEMO_HREF = '/trips/italy-2026-demo'; // has a tagline, no cover_image (entry-image fallback)
|
||
const NO_TAGLINE_HREF = '/trips/slovenia-2024'; // a real trip with no tagline
|
||
|
||
const demoCard = (page) => page.locator(`.trip-card[href="${DEMO_HREF}"]`);
|
||
|
||
// ── R5: one-liner renders between the title and the meta line ──────────────────
|
||
test('U3/R5: card with a tagline shows a one-liner between title and meta', async ({ page }) => {
|
||
await page.goto('/trips');
|
||
const card = demoCard(page);
|
||
const tagline = card.locator('.trip-card-tagline');
|
||
await expect(tagline).toBeVisible();
|
||
await expect(tagline).toHaveText(/southern Tuscany by bike/);
|
||
|
||
const order = await card.evaluate((el) =>
|
||
Array.from(el.children).map((c) => c.className.split(' ')[0])
|
||
);
|
||
expect(order.indexOf('trip-card-title')).toBeLessThan(order.indexOf('trip-card-tagline'));
|
||
expect(order.indexOf('trip-card-tagline')).toBeLessThan(order.indexOf('trip-card-meta'));
|
||
});
|
||
|
||
// ── R5/AE1: a card with no tagline renders no one-liner element ────────────────
|
||
test('U3/R5/AE1: card without a tagline renders no one-liner element', async ({ page }) => {
|
||
await page.goto('/trips');
|
||
const card = page.locator(`.trip-card[href="${NO_TAGLINE_HREF}"]`);
|
||
await expect(card).toBeVisible();
|
||
await expect(card.locator('.trip-card-tagline')).toHaveCount(0);
|
||
});
|
||
|
||
// ── R6/AE5: card cover exposes a 1x srcset; 2x only when the source is ≥2×w ────
|
||
test('U3/R6/AE5: card cover img carries a 720w srcset, 2x omitted for a narrow source', async ({ page }) => {
|
||
await page.goto('/trips');
|
||
const img = demoCard(page).locator('.trip-card-cover img');
|
||
const srcset = await img.getAttribute('srcset');
|
||
expect(srcset).toContain('720w');
|
||
// The 1200px source can't supply a non-upscaled 2x (needs ≥1440), so the
|
||
// retina descriptor is omitted — 1x only, no upscale, no intermediate width.
|
||
expect(srcset).not.toContain('1440w');
|
||
expect(srcset).not.toContain('1200w');
|
||
// cropZoom cover strip (~3:1), not a cropResize fit-inside sliver.
|
||
const ratio = await img.evaluate((el) => new Promise((res) => {
|
||
const done = () => res(el.naturalWidth / el.naturalHeight);
|
||
el.complete && el.naturalWidth ? done() : el.addEventListener('load', done, { once: true });
|
||
}));
|
||
expect(ratio).toBeGreaterThan(2.5);
|
||
});
|
||
|
||
// ── R7/AE3: with no cover_image set, the card falls back to a journal image ────
|
||
test('U3/R7/AE3: card with no cover_image uses the first journal entry image', async ({ page }) => {
|
||
await page.goto('/trips');
|
||
// The demo trip sets cover_image: '' so the cover comes from the fallback.
|
||
const img = demoCard(page).locator('.trip-card-cover img');
|
||
await expect(img).toBeVisible();
|
||
const src = await img.getAttribute('src');
|
||
expect(src).toMatch(/\/images\/.+\.(jpg|jpeg|png|webp)/i);
|
||
});
|
||
|
||
// ── R14: cover alt text equals the trip title ─────────────────────────────────
|
||
test('U3/R14: card cover alt equals the trip title', async ({ page }) => {
|
||
await page.goto('/trips');
|
||
const img = demoCard(page).locator('.trip-card-cover img');
|
||
await expect(img).toHaveAttribute('alt', 'Tuscany 2026');
|
||
});
|