From 2f772e132274e75a05deb0a0dd363dadebc9175a Mon Sep 17 00:00:00 2001 From: cesnimda Date: Wed, 21 Oct 2026 08:05:01 +0200 Subject: [PATCH] test(admin): navigate populated Users pagination in responsive checks --- .../phase-7/p7-12/USERS_PAGINATION.md | 9 ++ .../users-pagination-static-checks.json | 104 ++++++++++++++++++ job-tracker-ui/e2e/phase7-admin-users.spec.ts | 14 +++ 3 files changed, 127 insertions(+) create mode 100644 docs/redesign/phase-7/p7-12/USERS_PAGINATION.md create mode 100644 docs/redesign/phase-7/p7-12/evidence/users-pagination-static-checks.json diff --git a/docs/redesign/phase-7/p7-12/USERS_PAGINATION.md b/docs/redesign/phase-7/p7-12/USERS_PAGINATION.md new file mode 100644 index 0000000..1b0f6ab --- /dev/null +++ b/docs/redesign/phase-7/p7-12/USERS_PAGINATION.md @@ -0,0 +1,9 @@ +# Users browser-fixture pagination + +The [interrupted integrated run](CURRENT_FAILURES.md) exposed an invalid test precondition: the long identity was expected on the first desktop page after earlier suites had created80users. Its trace shows a populated10-row alphabetically sorted grid, not an unavailable account or a failed load. The mobile samples passed before the desktop assertion failed. + +The existing finite language/theme case now creates10ordinary fixture accounts that sort before its target, so the isolated case exercises pagination too. At desktop widths it uses the existing named next-page control, asserts that control is enabled and waits for the first rendered row to change before checking the target. The original visible-identity, keyboard, clipping, reflow, axe and no-browser-write assertions remain. An absent target fails when no next page is available; no timeout, assertion or product pagination is relaxed. No accounts are deleted and no product UI, role, permission or save behavior changes. The control's English name comes from the existing MUI pagination localization, as captured in the failure trace; no product string is added. + +The17-case ordinary Audit/Users/application-form vector passes06:00:43–06:03:24UTC, including all3Users cases and all6locale/theme width samples. It has0skips,0flaky cases and0configured retries. Browser TypeScript and lint pass05:56:28–05:56:52UTC on the changed fixture. [Native raw hashes](evidence/sqlite-repair.json) retain the overlapping vector; it adds no test cases to the351inventory. + +The independent SQLite repair is published as `f51e0506cc6a4fdcbc6c91c8cee9f6112cdecbf0`, normally pushed/directly verified06:04:31UTC. That receipt honestly retains this fixture as its one pending path; this publication completes the separate fixture correction. Full integrated acceptance remains pending. diff --git a/docs/redesign/phase-7/p7-12/evidence/users-pagination-static-checks.json b/docs/redesign/phase-7/p7-12/evidence/users-pagination-static-checks.json new file mode 100644 index 0000000..7b75b83 --- /dev/null +++ b/docs/redesign/phase-7/p7-12/evidence/users-pagination-static-checks.json @@ -0,0 +1,104 @@ +{ + "schemaVersion": 1, + "checkpoint": "p7-12", + "status": "PASS", + "checkedUtc": "2026-10-21T06:04:54.881035+00:00", + "commands": [ + { + "name": "secret-scan", + "command": [ + "rtk", + "proxy", + "C:\\Users\\Connor\\AppData\\Local\\Programs\\Python\\Python312\\python.exe", + "-X", + "utf8", + "scripts/supply-chain.py", + "scan-secrets" + ], + "startedUtc": "2026-10-21T06:04:51.386065+00:00", + "finishedUtc": "2026-10-21T06:04:54.088966+00:00", + "exitCode": 0, + "log": ".artifacts/phase7/current/static/20261021T060451Z/secret-scan.log", + "logSha256Raw": "be5119e6057287d397e87759f855c91e634e3bfac61c8be7584d05592ba2dfcd" + }, + { + "name": "working-whitespace", + "command": [ + "rtk", + "proxy", + "git", + "diff", + "--check" + ], + "startedUtc": "2026-10-21T06:04:54.088966+00:00", + "finishedUtc": "2026-10-21T06:04:54.173403+00:00", + "exitCode": 0, + "log": ".artifacts/phase7/current/static/20261021T060451Z/working-whitespace.log", + "logSha256Raw": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "name": "staged-whitespace", + "command": [ + "rtk", + "proxy", + "git", + "diff", + "--cached", + "--check" + ], + "startedUtc": "2026-10-21T06:04:54.173904+00:00", + "finishedUtc": "2026-10-21T06:04:54.253761+00:00", + "exitCode": 0, + "log": ".artifacts/phase7/current/static/20261021T060451Z/staged-whitespace.log", + "logSha256Raw": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "name": "phase7-whitespace", + "command": [ + "rtk", + "proxy", + "git", + "diff", + "--check", + "b5319981ad3d1bd635daff861453d23c0de5320b" + ], + "startedUtc": "2026-10-21T06:04:54.254767+00:00", + "finishedUtc": "2026-10-21T06:04:54.451316+00:00", + "exitCode": 0, + "log": ".artifacts/phase7/current/static/20261021T060451Z/phase7-whitespace.log", + "logSha256Raw": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + ], + "untrackedSecretScan": { + "files": 0, + "findings": 0 + }, + "documentation": { + "files": 46, + "relativeLinks": 693, + "errors": [] + }, + "preservation": { + "groups": 57, + "statuses": { + "PARTIAL": 56, + "PASS": 0, + "FAIL": 0, + "DEFERRED": 1 + }, + "originalRoutesPreserved": true, + "currentConcreteRoutes": 33 + }, + "production": { + "main": "5f835e54a9b74e6b71418422e28431b2af06453f", + "originMain": "5f835e54a9b74e6b71418422e28431b2af06453f", + "status": "NO-GO", + "qualification": "Local fetched refs; direct push observation recorded separately." + }, + "hashPolicy": "Portable JSON UTF8 LF; raw log hashes measure exact saved bytes.", + "limits": [ + "Pattern scanner skips binary and files over2MiB; not historical Git/production secrets.", + "Local links check target existence, not URL/heading anchors.", + "Static evidence is not runtime/manual/device/provider/production acceptance." + ] +} diff --git a/job-tracker-ui/e2e/phase7-admin-users.spec.ts b/job-tracker-ui/e2e/phase7-admin-users.spec.ts index ed4bef8..dddf5c1 100644 --- a/job-tracker-ui/e2e/phase7-admin-users.spec.ts +++ b/job-tracker-ui/e2e/phase7-admin-users.spec.ts @@ -120,12 +120,26 @@ test('[P7-10 Users A01] finite bilingual light/dark widths retain long identitie test.setTimeout(180_000); const administrator=await login(session.requests, page.request, 'e2e@example.test'); const email=`long-administrative-identity-${Date.now()}@example.test`; expect((await call(session.requests, page.request, 'POST', '/users', administrator.headers, { email, password, roles: [] })).status()).toBe(200); + for (let index=0; index<10; index++) { + expect((await call(session.requests, page.request, 'POST', '/users', administrator.headers, { email: `a-page-${index}-${email}`, password, roles: [] })).status()).toBe(200); + } const samples=[{ width: 320, language: 'nb', mode: 'dark' }, { width: 390, language: 'en', mode: 'light' }, { width: 768, language: 'nb', mode: 'light' }, { width: 1024, language: 'en', mode: 'dark' }, { width: 1440, language: 'en', mode: 'light' }, { width: 1920, language: 'nb', mode: 'dark' }] as const; for (const sample of samples) { expect((await call(session.requests, page.request, 'PUT', '/auth/preferences/language', administrator.headers, { language: sample.language==='nb' ? 'nb-NO' : 'en' })).status()).toBe(204); await page.addInitScript(value => { localStorage.setItem('uiLanguage', value.language); localStorage.setItem('jobtracker.themeMode', value.mode); }, sample); await start(page, '/admin/users', sample.width); await expect(page.getByRole('heading', { level: 3, name: copy('adminUsersCreateUser', sample.language), exact: true })).toBeVisible(); + if (sample.width>=768) { + const grid=page.getByRole('grid'); + await expect(grid.getByRole('row').nth(1)).toBeVisible(); + while (!await page.getByText(email, { exact: true }).first().isVisible()) { + const next=page.getByRole('button', { name: 'Go to next page', exact: true }); + await expect(next).toBeEnabled(); + const before=await grid.getByRole('row').nth(1).innerText(); + await next.click(); + await expect.poll(() => grid.getByRole('row').nth(1).innerText()).not.toBe(before); + } + } await expect(page.getByText(email, { exact: true }).first()).toBeVisible(); if (sample.width>=768) { const region=page.getByRole('region', { name: copy('adminUsersTitle', sample.language), exact: true }); await expect(region).toHaveAttribute('tabindex', '0');