diff --git a/.github/workflows/viewerjs-check.yml b/.github/workflows/viewerjs-check.yml index 485c223..41ddf1b 100644 --- a/.github/workflows/viewerjs-check.yml +++ b/.github/workflows/viewerjs-check.yml @@ -26,7 +26,12 @@ jobs: container: image: mcr.microsoft.com/playwright:v1.64.1-noble options: --user 1001 - timeout-minutes: 25 + # This job runs every page workflow twice (chromium, then touch) on one worker with V8 coverage on, so it + # takes about twice a single-browser job. Measured 2026-10-20: whole job 18m26s-24m57s (main 5ded3cf + # 22m15s; PR head 6359999 was cancelled at the old 25-minute limit while still passing), coverage step + # alone 20m55s-22m17s+, against ~12-15 minutes for the firefox/webkit jobs. 40 minutes leaves headroom + # for suite growth while still stopping a hung run; re-measure if a run passes 30 minutes. + timeout-minutes: 40 steps: - uses: actions/checkout@v7 # The image's own Python 3.12 and Node 24: setup-python/setup-node install the runner's toolcache diff --git a/tests/browser/images-concept.spec.mjs b/tests/browser/images-concept.spec.mjs index 0777b0c..e88d417 100644 --- a/tests/browser/images-concept.spec.mjs +++ b/tests/browser/images-concept.spec.mjs @@ -410,7 +410,12 @@ for(const [width,height] of SIZES)for(const theme of THEMES)test(`images page ge await openProductionLoaded(page,theme,motion,total); const before=await page.locator(CARDS).count(); const loadingRow=(await inventoryOf(page,'#workspace-main')).continuation,loadingCount=await countText(page); - await page.getByRole('button',{name:'Load more images',exact:true}).click(); + // A dispatched press, as on the concept side: a pointer click scrolls the row into view first, and the page's + // own observer (rootMargin 250px) can append the final batch and hide the button before the click lands + // (WebKit, run 39512528039). The button must still be the enabled one the user would press. + const more=page.getByRole('button',{name:'Load more images',exact:true}); + await expect(more).toBeVisible();await expect(more).toHaveAttribute('aria-disabled','false'); + await more.dispatchEvent('click'); await expect(page.locator('#result-count')).toHaveText(new RegExp(`^${total} of ${total} images`)); result[motion].productionLoad={before,after:await page.locator(CARDS).count(),toast:await toastText(page),count:await countText(page)}; result[motion].loadingDiff=compareLoadingRow(result[motion].conceptLoad.loadingRow,loadingRow,loadingCount);