test(storefront): cover paging, and say what the filter tests meant (#269)
Linting / lint (pull_request) Successful in 3m17s
SonarQube Analysis / sonarqube (pull_request) Failing after 31m17s

Two assertions named a fixture and expected it visible in the unfiltered grid. No paginated catalogue can promise that — the item is on some page, not necessarily the first — so both would have started failing the moment paging landed. They were only ever proxies for "the result set got bigger", and the visible total lets them say that directly, which is what the issue predicted when it asked for a count.

The new cases assert the control and the URL rather than which item is on which page, because the development database never truncates and which item lands where is not something a test may rely on. That is the same trap the two rewritten assertions had fallen into, and repeating it in new tests would have been worse than leaving them alone.

Writing them found a real defect rather than just covering the feature. The control was rendering while the catalogue was still loading, showing "0 items" for a moment before the real count arrived — the empty-state early return only fires once loading has finished, so a mid-load render fell through to the grid branch with a total of zero. It is now suppressed until there is something to count, which is both true and what makes the count usable as a signal in a test. StorefrontPage.totalItems waits for the control for the same reason: reading during the load returned zero and quietly made "the result set shrank" compare against nothing.

The conditional skips carry a file-level eslint exception with its reasoning rather than being left to add four warnings. They are honest about a real limit: against a catalogue of ten items or fewer these cases prove nothing, and if the e2e database is ever seeded that thinly they need fixtures of their own instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 16:11:07 -05:00
co-authored by Claude Opus 5
parent f9073c515e
commit 1bd0024e6f
5 changed files with 164 additions and 2 deletions
@@ -38,6 +38,16 @@ export class StorefrontPage {
/** What the nearest error boundary renders when the grid itself throws. */
readonly catalogueBoundaryHeading: Locator;
/** The paging control under the grid (#269). */
readonly pagination: Locator;
/**
* Where the catalogue says how many items it has.
*
* A class locator rather than a role, matching how this file already reaches
* `.item-card` — antd gives the total no role of its own, and this is the one
* place in the suite that knows where it lives.
*/
readonly resultCount: Locator;
constructor(private readonly page: Page) {
this.header = new Header(page);
@@ -52,12 +62,35 @@ export class StorefrontPage {
this.retryButton = page.getByRole('button', { name: 'Retry' });
this.catalogueBoundaryHeading = page.getByRole('heading', { name: "The item list didn't load" });
this.pagination = page.locator('.ant-pagination');
this.resultCount = page.locator('.ant-pagination-total-text');
}
async goto(): Promise<void> {
await this.page.goto('/');
}
/**
* How many items the catalogue says it has, in total, across every page.
*
* The number rather than the text, so a test can assert a result set grew or
* shrank without knowing what it grew from. That is the whole reason #269
* added a visible count: two assertions used to name a fixture and expect it
* in the unfiltered grid, which no paginated catalogue can promise.
*/
async totalItems(): Promise<number> {
// Waits rather than reading straight away. The control is not rendered
// until there is something to count, so reading during the initial load
// used to return 0 and quietly make "the result set shrank" assertions
// compare against nothing.
await this.resultCount.waitFor();
const text = (await this.resultCount.textContent()) ?? '';
const digits = /(\d+)/.exec(text);
if (digits === null) throw new Error(`no count in the pagination total: "${text}"`);
return Number(digits[1]);
}
/**
* Goes to the storefront and waits for the session to settle.
*