test(images): the singular copy when scrolling loads one image; countCopy in the shared inventory helper

This commit is contained in:
Vito Sansevero
2026-10-20 07:57:27 -07:00
parent c2dde80a2a
commit 76ebe912f0
2 changed files with 19 additions and 5 deletions
+4
View File
@@ -11,6 +11,10 @@ export const SIZES=Object.freeze([[1600,1100],[390,844]]);
export const THEMES=Object.freeze(['dark','light']);
export const MOTIONS=Object.freeze(['no-preference','reduce']);
/** D35: production uses the singular for exactly one; the concept's plurals are hard-coded (app.js 447, 489, 517-521). */
export const countCopy=text=>text.replace(/(^|\D)1 positive prompts\b/g,'$11 positive prompt')
.replace(/(^|\D)1 more images\b/g,'$11 more image').replace(/(^|\D)1 images\b/g,'$11 image');
/** Seed the concept-shaped real fixture (tests/browser/workspace_concept_fixture.py) and return its manifest. */
export async function seedConcept(request,data={}) {
const response=await request.post('/__test__/concept/reset',{data});
+15 -5
View File
@@ -1,7 +1,7 @@
import {writeFile} from 'node:fs/promises';
import {test,expect} from '../../tools/vendor/node_modules/@playwright/test/index.mjs';
import {captureCanonicalState} from './history-canonical-comparison.mjs';
import {SIZES,THEMES,MOTIONS,seedConcept,openConcept,openProduction,inventoryOf,diffInventory,mutate,stripExact} from './concept-inventory.mjs';
import {SIZES,THEMES,MOTIONS,seedConcept,openConcept,openProduction,inventoryOf,diffInventory,mutate,stripExact,countCopy} from './concept-inventory.mjs';
// Task C7 of #249: the production Images page against the immutable concept, on the concept-shaped real fixture (24
// images of the concept's six prompts, its seeds, sizes and favorites). Heading, toolbar, filter row, caption, grid,
@@ -21,10 +21,6 @@ const LOAD_MORE_EXTRA=2*PRODUCTION_BATCH-FIXTURE_IMAGES;
const CARDS='.gallery-body > .image-grid > .media-card';
const WIDE_SIZES=Object.freeze([[1200,900],[1800,1100]]);
/** D35: production uses the singular for exactly one; the concept's plurals are hard-coded (app.js 447, 489, 517-521). */
export const countCopy=text=>text.replace(/(^|\D)1 positive prompts\b/g,'$11 positive prompt')
.replace(/(^|\D)1 more images\b/g,'$11 more image').replace(/(^|\D)1 images\b/g,'$11 image');
/** D17: "<Today|Yesterday|weekday> · <Month D>" of the newest file (the fixture's own mtime), in the test's UTC zone. */
function captionDay(seconds,now=new Date()) {
const day=value=>Date.UTC(value.getUTCFullYear(),value.getUTCMonth(),value.getUTCDate());
@@ -531,6 +527,20 @@ test('one appended image reads in the singular',async({page,request})=>{
await expect(page.locator('.infinite-continuation > p').first()).toHaveText(`You’re all caught up · ${total} images`);
});
// The same singular copy when the page's own observer loads the one image: the user only scrolls (no press).
test('one image appended by scrolling reads in the singular',async({page,request})=>{
test.setTimeout(120_000);
await page.setViewportSize({width:1600,height:1100});
const total=PRODUCTION_BATCH+1;
await seedConcept(request,{extra_images:total-FIXTURE_IMAGES});
await openProductionLoaded(page,'dark','no-preference',total);
await expect(page.locator('#result-count')).toHaveText(new RegExp(`^${PRODUCTION_BATCH} of ${total} images`));
await page.locator('.infinite-continuation').scrollIntoViewIfNeeded();
await expect(page.locator('#result-count')).toHaveText(new RegExp(`^${total} of ${total} images`));
await expect(page.locator('.toast')).toHaveText(countCopy(`1 more images loaded. ${total} of ${total}.`));
await expect(page.locator('.infinite-continuation > p').first()).toHaveText(`You’re all caught up · ${total} images`);
});
// D3 (one footer height for the collection): bounded rendering cannot measure unrendered cards, so every row reserves
// the tallest measured footer. Two seedless files (D11 "W × H · PNG", one line) form the first row at 390px, where
// every concept subtitle wraps: their row is as tall as the wrapped rows, and every concept row moves down by one.