diff --git a/docs/ui-modernisation/DISCOVERY_VALIDATION.md b/docs/ui-modernisation/DISCOVERY_VALIDATION.md new file mode 100644 index 00000000..4e7f9390 --- /dev/null +++ b/docs/ui-modernisation/DISCOVERY_VALIDATION.md @@ -0,0 +1,31 @@ +# A3-IM05 existing discovery presentation qualification + +3 November2026. Owner explicitly answered **"Approve applications and A3-IM05"**. Branch codex/a3-ui-05 starts at accepted application receipt172074e9. No older design tree or unrelated implementation branch merged. + +Filters and saved searches form a left rail beside a single result list above1000px. Narrow screens preserve filters-before-results DOM order; Jump to results and Return to search filters move focus without requests or route changes. Source coverage explanation is above both columns. Existing query/location fields, sort, saved-search create/run/pause/delete/dismiss, source attribution/provenance/original links, Save-to-tracker route and busy/empty/error/retry owners remain unchanged. Added only three paired EN/NB labels. UI language does not translate source content. + +This is presentation of the existing NAV workflow. No new country, provider, radius, taxonomy, matching or in-app full-description capability was fabricated. Global Jobs' future three-pane authorised-detail experience depends on GJ prerequisites, rights and actual data contracts. GJ-00 planning is separate; GJ-01+ acceptance/provider activation is not implied. Source master and initial planning pack were read at `E:\Storage\Projects\Active\Job tracker\docs\planning\global-jobs-prompts\` because this older integration branch does not contain that pack. The original external source's provider/prerequisite constraints remain intact. + +| Evidence | Result and boundary | +|---|---| +| Baseline |21 discovery tests passed before edits | +| Test-first focus contracts |Two EN/NB missing-landmark failures reproduced before implementation | +| Final frontend |32 tests/3 suites passed: discovery23, provider6, catalogue3; reviewer23 and baseline overlap, not additional cases | +| Backend preservation |14 passed, zero failures/skips: JobDiscoveryControllerTests, SavedJobSearchSqliteTests, SavedJobSearchAlertTests. Synthetic HTTP handler/FakeDiscovery, InMemory/isolated SQLite; no live NAV/provider request or app worker activation | +| Types/full lint/build |Passed; new browser script also passed scoped zero-warning lint | +| Built React browser |16 conditions:320/390/768/1440 × EN/NB × light/dark;48 whole-page axe scans, zero violations,48 PNGs | +| Connected journeys |All16: initial guidance/no automatic provider search, keyboard jump/return, wide/stack geometry, three-occupation search, save nurse/Oslo query, pause alerts, manual saved run, retained original link, dismiss and separately confirmed deletion | +| Mutation boundary |80 explicit requests fulfilled only by in-memory fixtures:16 each create/pause/run/dismiss/delete. Zero unexpected writes/page errors. All external requests aborted; no real backend/provider writes | +| Independent review |No actionable findings;23 tests/one suite passed independently, overlapping32. Reviewer did not independently execute browser/backend | + +Native reports/captures and source manifest: [evidence/discovery](evidence/discovery). Browser harness runs from job-tracker-ui: `rtk proxy node scripts/verify-a3-discovery.mjs`, against the static export on localhost4338. Synthetic nurse/teacher/engineer listings are fixtures, never represented as current live search results. Source data remains in its original language even in Bokmål UI. + +Two harness defects were corrected: initial URL used a nonexistent /jobs/discover path instead of /discover; immediate uncheck assumed optimistic switch state. The final verifier clicks the control and waits for the existing backend-acknowledged state. No application behavior was weakened to satisfy either harness issue. Failed attempts are not passing journeys. Fixed bars can appear within full-page scroll captures; native-device layout is not qualified by those captures. + +Existing unit coverage retains sorting/metadata, initial versus empty results, saved-list validation/loading/retry, per-search result boundaries, stale-free request snapshots, failure-retained drafts/toggles/deletion/dismissal, duplicate-start prevention, current-language errors without replay, and explicit mutation recovery. These are controlled contracts; the browser did not repeat every failure path or perform actual Save-to-tracker import. + +No backend/schema/API/dependency/revision writer/route or physical document renderer changes. Existing owner/persistence/right checks stay with their services. Rollback reverts this UI increment; no database or data rollback. The separate ca519cac document-date patch and de3d5031 security policy are not silently combined here. + +NOT RUN: live NAV/commercial providers, MariaDB, real backend/browser end-to-end, hosted CI, native screen-reader/device/touch/actual zoom/native-language review, final integrated security/recovery/release. Complete Product Review, Global Jobs, European localisation and Phase10 remain open. No production/main changes. + +Next protected dependency: publish/remote verify and owner Gate F before A3-IM06 Career overview/CV/letter workflows. Deferred CV-import engine overhaul remains excluded; canonical Career Profile, null-as-inherit settings, undo/save/conflict/history and RD21 must be preserved. diff --git a/docs/ui-modernisation/UI-05.md b/docs/ui-modernisation/UI-05.md new file mode 100644 index 00000000..c7daca14 --- /dev/null +++ b/docs/ui-modernisation/UI-05.md @@ -0,0 +1,13 @@ +# A3-IM05 — discovery presentation and existing saved searches + +3 November2026 owner reply: **"Approve applications and A3-IM05"**. Application implementation98e9502a/publication receipt172074e9 accepted for progression. Isolated codex/a3-ui-05 starts at172074e9. No new international provider or geography authorization is inferred. + +## Bounded plan + +- [x] Baseline21 existing discovery tests passed. +- [x] Filter/saved-search rail left, result list right above1000px; narrow logical stack and named jump/return focus. Existing source explanation prominent. +- [x] All existing handlers/semantics retained; no unsupported provider/country/radius controls or API changes. +- [x]32 selected frontend/3 suites,14 mocked-provider/local backend tests, type/lint/build,16 controlled browser journeys/48 scans/captures passed. Independent review found no actionable issue; reviewer23 overlaps32. +- [ ] Publish/readback, Gate F before A3-IM06 Career/CV/letter work. + +Callers: JobDiscoveryPage, its EN/NB messages, tests and browser fixtures only. Existing API/data/provider owners retained. Canonical occupation/geography expansion remains Global Jobs work with its own prerequisites and permissions; GJ-01+ is not accepted by a presentation change. Rollback reverts presentation/tests; no migration or data rollback. Preserve source ads and generated-content language distinction. diff --git a/docs/ui-modernisation/evidence/discovery/BASELINE.json b/docs/ui-modernisation/evidence/discovery/BASELINE.json new file mode 100644 index 00000000..6d0fcd33 --- /dev/null +++ b/docs/ui-modernisation/evidence/discovery/BASELINE.json @@ -0,0 +1 @@ +{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":1,"numPassedTests":21,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":1,"numTotalTests":21,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1793697255037,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":[],"duration":248,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"shows honest source metadata and offers the existing reviewed save flow","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"startAt":1793697258527,"status":"passed","title":"shows honest source metadata and offers the existing reviewed save flow"},{"ancestorTitles":[],"duration":74,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"distinguishes the initial guidance from a completed empty search","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697258775,"status":"passed","title":"distinguishes the initial guidance from a completed empty search"},{"ancestorTitles":[],"duration":162,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"retries the last submitted search after an error","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"startAt":1793697258849,"status":"passed","title":"retries the last submitted search after an error"},{"ancestorTitles":[],"duration":167,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"sorts returned vacancies by title","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"startAt":1793697259011,"status":"passed","title":"sorts returned vacancies by title"},{"ancestorTitles":[],"duration":71,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"renders the discovery workflow in Norwegian Bokmål","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"startAt":1793697259178,"status":"passed","title":"renders the discovery workflow in Norwegian Bokmål"},{"ancestorTitles":[],"duration":201,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"runs a saved search, marks unseen vacancies, and dismisses them","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"startAt":1793697259249,"status":"passed","title":"runs a saved search, marks unseen vacancies, and dismisses them"},{"ancestorTitles":[],"duration":77,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"lets the user pause automatic alerts for a saved search","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697259450,"status":"passed","title":"lets the user pause automatic alerts for a saved search"},{"ancestorTitles":[],"duration":50,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"announces saved-search loading without presenting a successful empty list","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"startAt":1793697259527,"status":"passed","title":"announces saved-search loading without presenting a successful empty list"},{"ancestorTitles":[],"duration":265,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"reports saved-search failure and retries that read without replacing active discovery filters or results","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"startAt":1793697259577,"status":"passed","title":"reports saved-search failure and retries that read without replacing active discovery filters or results"},{"ancestorTitles":[],"duration":52,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed saved-search payload null as a failed read rather than an empty list","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697259842,"status":"passed","title":"rejects malformed saved-search payload null as a failed read rather than an empty list"},{"ancestorTitles":[],"duration":60,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed saved-search payload {\"message\":\"not a list\"} as a failed read rather than an empty list","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697259894,"status":"passed","title":"rejects malformed saved-search payload {\"message\":\"not a list\"} as a failed read rather than an empty list"},{"ancestorTitles":[],"duration":61,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed saved-search payload [{\"id\":7}] as a failed read rather than an empty list","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697259954,"status":"passed","title":"rejects malformed saved-search payload [{\"id\":7}] as a failed read rather than an empty list"},{"ancestorTitles":[],"duration":246,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a manual search after saved-search results has no dismiss action belonging to the saved search","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"startAt":1793697260015,"status":"passed","title":"a manual search after saved-search results has no dismiss action belonging to the saved search"},{"ancestorTitles":[],"duration":206,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"starting saved search B hides saved search A's results and actions while the B response is held","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"startAt":1793697260261,"status":"passed","title":"starting saved search B hides saved search A's results and actions while the B response is held"},{"ancestorTitles":[],"duration":250,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"retrying a failed saved-search run repeats that saved ID instead of running a manual query","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"startAt":1793697260467,"status":"passed","title":"retrying a failed saved-search run repeats that saved ID instead of running a manual query"},{"ancestorTitles":[],"duration":199,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"failed saved-search creation retains its draft and recovers only through the save action","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"startAt":1793697260717,"status":"passed","title":"failed saved-search creation retains its draft and recovers only through the save action"},{"ancestorTitles":[],"duration":137,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a failed alert toggle retains its checked state and recovers through that same toggle without manual search retry","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"startAt":1793697260916,"status":"passed","title":"a failed alert toggle retains its checked state and recovers through that same toggle without manual search retry"},{"ancestorTitles":[],"duration":408,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"failed saved-search deletion preserves the search and requires another explicit confirmation to recover","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"startAt":1793697261054,"status":"passed","title":"failed saved-search deletion preserves the search and requires another explicit confirmation to recover"},{"ancestorTitles":[],"duration":317,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"failed dismissal retains the vacancy and recovers only through that same result's dismiss action","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"startAt":1793697261462,"status":"passed","title":"failed dismissal retains the vacancy and recovers only through that same result's dismiss action"},{"ancestorTitles":[],"duration":125,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a held saved-search creation locks its request snapshot and prevents a second start while preserving a failed draft","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"startAt":1793697261779,"status":"passed","title":"a held saved-search creation locks its request snapshot and prevents a second start while preserving a failed draft"},{"ancestorTitles":[],"duration":141,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a saved-run failure follows the current language without refetching or replaying the request","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"startAt":1793697261904,"status":"passed","title":"a saved-run failure follows the current language without refetching or replaying the request"}],"endTime":1793697262047,"message":"","name":"C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\job-discovery.test.tsx","startTime":1793697255934,"status":"passed","summary":""}],"wasInterrupted":false} diff --git a/docs/ui-modernisation/evidence/discovery/CHECKS.json b/docs/ui-modernisation/evidence/discovery/CHECKS.json new file mode 100644 index 00000000..bd5faf2b --- /dev/null +++ b/docs/ui-modernisation/evidence/discovery/CHECKS.json @@ -0,0 +1,17 @@ +{ + "date": "2026-11-03", + "branch": "codex/a3-ui-05", + "base": "172074e90f3c7067b1cbc7e65724b303c2fc9ff6", + "frontend": {"passed": 32, "failed": 0, "suites": 3, "report": "FINAL_TESTS.json"}, + "backend": {"passed": 14, "failed": 0, "skipped": 0, "report": "backend/a3-discovery.trx", "environment": "mock HTTP/FakeDiscovery with InMemory/isolated SQLite"}, + "commands": [ + {"command": "rtk proxy npm run typecheck", "exitCode": 0}, + {"command": "rtk proxy npm run lint", "exitCode": 0}, + {"command": "rtk proxy npm run build", "exitCode": 0}, + {"command": "rtk proxy npm exec eslint -- scripts/verify-a3-discovery.mjs --max-warnings=0", "exitCode": 0}, + {"command": "rtk proxy node scripts/verify-a3-discovery.mjs", "exitCode": 0}, + {"command": "rtk proxy graphify update .", "exitCode": 0, "limits": "AST only; SQL extractor unavailable"} + ], + "independentReview": {"result": "no actionable findings", "testsPassed": 23, "overlapsFrontend": true}, + "notRun": ["live NAV or commercial providers", "new global geography/taxonomy/provider features", "MariaDB", "real backend browser integration", "hosted CI", "native device/screen-reader/zoom/language qualification", "actual Save-to-tracker import", "final integrated security", "production/release"] +} diff --git a/docs/ui-modernisation/evidence/discovery/FINAL_TESTS.json b/docs/ui-modernisation/evidence/discovery/FINAL_TESTS.json new file mode 100644 index 00000000..72ac6713 --- /dev/null +++ b/docs/ui-modernisation/evidence/discovery/FINAL_TESTS.json @@ -0,0 +1 @@ +{"numFailedTestSuites":0,"numFailedTests":0,"numPassedTestSuites":3,"numPassedTests":32,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":3,"numTotalTests":32,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1793697338423,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":[],"duration":184,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"keeps en filters before results with keyboard jump/return and no automatic provider search","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"startAt":1793697341920,"status":"passed","title":"keeps en filters before results with keyboard jump/return and no automatic provider search"},{"ancestorTitles":[],"duration":72,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"keeps nb filters before results with keyboard jump/return and no automatic provider search","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"startAt":1793697342105,"status":"passed","title":"keeps nb filters before results with keyboard jump/return and no automatic provider search"},{"ancestorTitles":[],"duration":163,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"shows honest source metadata and offers the existing reviewed save flow","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"startAt":1793697342177,"status":"passed","title":"shows honest source metadata and offers the existing reviewed save flow"},{"ancestorTitles":[],"duration":89,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"distinguishes the initial guidance from a completed empty search","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697342340,"status":"passed","title":"distinguishes the initial guidance from a completed empty search"},{"ancestorTitles":[],"duration":183,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"retries the last submitted search after an error","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"startAt":1793697342429,"status":"passed","title":"retries the last submitted search after an error"},{"ancestorTitles":[],"duration":168,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"sorts returned vacancies by title","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"startAt":1793697342612,"status":"passed","title":"sorts returned vacancies by title"},{"ancestorTitles":[],"duration":66,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"renders the discovery workflow in Norwegian Bokmål","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"startAt":1793697342780,"status":"passed","title":"renders the discovery workflow in Norwegian Bokmål"},{"ancestorTitles":[],"duration":237,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"runs a saved search, marks unseen vacancies, and dismisses them","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"startAt":1793697342846,"status":"passed","title":"runs a saved search, marks unseen vacancies, and dismisses them"},{"ancestorTitles":[],"duration":107,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"lets the user pause automatic alerts for a saved search","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697343083,"status":"passed","title":"lets the user pause automatic alerts for a saved search"},{"ancestorTitles":[],"duration":61,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"announces saved-search loading without presenting a successful empty list","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"startAt":1793697343190,"status":"passed","title":"announces saved-search loading without presenting a successful empty list"},{"ancestorTitles":[],"duration":282,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"reports saved-search failure and retries that read without replacing active discovery filters or results","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"startAt":1793697343251,"status":"passed","title":"reports saved-search failure and retries that read without replacing active discovery filters or results"},{"ancestorTitles":[],"duration":69,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed saved-search payload null as a failed read rather than an empty list","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697343533,"status":"passed","title":"rejects malformed saved-search payload null as a failed read rather than an empty list"},{"ancestorTitles":[],"duration":63,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed saved-search payload {\"message\":\"not a list\"} as a failed read rather than an empty list","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697343602,"status":"passed","title":"rejects malformed saved-search payload {\"message\":\"not a list\"} as a failed read rather than an empty list"},{"ancestorTitles":[],"duration":64,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed saved-search payload [{\"id\":7}] as a failed read rather than an empty list","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697343665,"status":"passed","title":"rejects malformed saved-search payload [{\"id\":7}] as a failed read rather than an empty list"},{"ancestorTitles":[],"duration":189,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a manual search after saved-search results has no dismiss action belonging to the saved search","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"startAt":1793697343729,"status":"passed","title":"a manual search after saved-search results has no dismiss action belonging to the saved search"},{"ancestorTitles":[],"duration":258,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"starting saved search B hides saved search A's results and actions while the B response is held","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"startAt":1793697343918,"status":"passed","title":"starting saved search B hides saved search A's results and actions while the B response is held"},{"ancestorTitles":[],"duration":314,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"retrying a failed saved-search run repeats that saved ID instead of running a manual query","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"startAt":1793697344176,"status":"passed","title":"retrying a failed saved-search run repeats that saved ID instead of running a manual query"},{"ancestorTitles":[],"duration":181,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"failed saved-search creation retains its draft and recovers only through the save action","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"startAt":1793697344490,"status":"passed","title":"failed saved-search creation retains its draft and recovers only through the save action"},{"ancestorTitles":[],"duration":108,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a failed alert toggle retains its checked state and recovers through that same toggle without manual search retry","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"startAt":1793697344671,"status":"passed","title":"a failed alert toggle retains its checked state and recovers through that same toggle without manual search retry"},{"ancestorTitles":[],"duration":402,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"failed saved-search deletion preserves the search and requires another explicit confirmation to recover","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"startAt":1793697344779,"status":"passed","title":"failed saved-search deletion preserves the search and requires another explicit confirmation to recover"},{"ancestorTitles":[],"duration":311,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"failed dismissal retains the vacancy and recovers only through that same result's dismiss action","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"startAt":1793697345181,"status":"passed","title":"failed dismissal retains the vacancy and recovers only through that same result's dismiss action"},{"ancestorTitles":[],"duration":156,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a held saved-search creation locks its request snapshot and prevents a second start while preserving a failed draft","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"startAt":1793697345492,"status":"passed","title":"a held saved-search creation locks its request snapshot and prevents a second start while preserving a failed draft"},{"ancestorTitles":[],"duration":160,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a saved-run failure follows the current language without refetching or replaying the request","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"startAt":1793697345648,"status":"passed","title":"a saved-run failure follows the current language without refetching or replaying the request"}],"endTime":1793697345809,"message":"","name":"C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\job-discovery.test.tsx","startTime":1793697339310,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":27,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"migrates the legacy Norwegian code and persists Bokmål using nb-NO","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"startAt":1793697346444,"status":"passed","title":"migrates the legacy Norwegian code and persists Bokmål using nb-NO"},{"ancestorTitles":[],"duration":6,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"hydrates an authenticated server preference without writing it back","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697346471,"status":"passed","title":"hydrates an authenticated server preference without writing it back"},{"ancestorTitles":[],"duration":270,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a failed account language save keeps the local choice and offers a localized retry: Norsk","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"startAt":1793697346478,"status":"passed","title":"a failed account language save keeps the local choice and offers a localized retry: Norsk"},{"ancestorTitles":[],"duration":262,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a failed account language save keeps the local choice and offers a localized retry: English","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"startAt":1793697346749,"status":"passed","title":"a failed account language save keeps the local choice and offers a localized retry: English"},{"ancestorTitles":[],"duration":9,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a delayed language-save failure cannot offer a retry for a newer successful choice","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697347011,"status":"passed","title":"a delayed language-save failure cannot offer a retry for a newer successful choice"},{"ancestorTitles":[],"duration":47,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a previously delivered language retry cannot reverse a newer choice","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"startAt":1793697347020,"status":"passed","title":"a previously delivered language retry cannot reverse a newer choice"}],"endTime":1793697347068,"message":"","name":"C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\i18n-provider.test.tsx","startTime":1793697345819,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":[],"duration":8,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"English and Bokmål expose the same UI message keys","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"startAt":1793697347280,"status":"passed","title":"English and Bokmål expose the same UI message keys"},{"ancestorTitles":[],"duration":4,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"Bokmål preserves every English substitution variable","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"startAt":1793697347289,"status":"passed","title":"Bokmål preserves every English substitution variable"},{"ancestorTitles":[],"duration":4,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"supported UI catalogues contain no blank messages","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"startAt":1793697347293,"status":"passed","title":"supported UI catalogues contain no blank messages"}],"endTime":1793697347297,"message":"","name":"C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\translation-catalogue.test.ts","startTime":1793697347077,"status":"passed","summary":""}],"wasInterrupted":false} diff --git a/docs/ui-modernisation/evidence/discovery/RED_TESTS.json b/docs/ui-modernisation/evidence/discovery/RED_TESTS.json new file mode 100644 index 00000000..7749b91d --- /dev/null +++ b/docs/ui-modernisation/evidence/discovery/RED_TESTS.json @@ -0,0 +1 @@ +{"numFailedTestSuites":1,"numFailedTests":2,"numPassedTestSuites":0,"numPassedTests":0,"numPendingTestSuites":0,"numPendingTests":21,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":1,"numTotalTests":23,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1793697308779,"success":false,"testResults":[{"assertionResults":[{"ancestorTitles":[],"duration":195,"failing":false,"failureDetails":[{"name":"TestingLibraryElementError"}],"failureMessages":["TestingLibraryElementError: Unable to find an accessible element with the role \"complementary\" and name \"Search filters\"\n\nHere are the accessible roles:\n\n textbox:\n\n Name \"Role or company\":\n \u001b[36m\u001b[39m\n\n Name \"Municipality\":\n \u001b[36m\u001b[39m\n\n Name \"Search name\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n button:\n\n Name \"Search NAV\":\n \u001b[36m\u001b[39m\n\n Name \"Save search\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n heading:\n\n Name \"Saved searches\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n paragraph:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n alert:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n region:\n\n Name \"Search results\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n status:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n\nIgnored nodes: comments, script, style\n\u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mRole or company\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mRole or company\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mMunicipality\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mMunicipality\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSearch NAV\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSaved searches\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSaved NAV searches are checked automatically. You will be notified when new vacancies appear.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSearch name\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSearch name\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSave search\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mNo saved searches yet.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mOfficial Norwegian vacancies from NAV. FINN, Indeed and LinkedIn jobs can still be captured by URL.\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSearch recent active vacancies by role, company, or municipality.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n\u001b[36m\u001b[39m\n at Object.getElementError (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\config.js:37:19)\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:76:38\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:52:17\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:95:19\n at getByRole (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\job-discovery.test.tsx:33:26)"],"fullName":"keeps en filters before results with keyboard jump/return and no automatic provider search","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312111,"status":"failed","title":"keeps en filters before results with keyboard jump/return and no automatic provider search"},{"ancestorTitles":[],"duration":87,"failing":false,"failureDetails":[{"name":"TestingLibraryElementError"}],"failureMessages":["TestingLibraryElementError: Unable to find an accessible element with the role \"complementary\" and name \"Søkefiltre\"\n\nHere are the accessible roles:\n\n textbox:\n\n Name \"Rolle eller bedrift\":\n \u001b[36m\u001b[39m\n\n Name \"Kommune\":\n \u001b[36m\u001b[39m\n\n Name \"Navn på søket\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n button:\n\n Name \"Søk i NAV\":\n \u001b[36m\u001b[39m\n\n Name \"Lagre søk\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n heading:\n\n Name \"Lagrede søk\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n paragraph:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n alert:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n region:\n\n Name \"Søkeresultater\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n status:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n\nIgnored nodes: comments, script, style\n\u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mRolle eller bedrift\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mRolle eller bedrift\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mKommune\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mKommune\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSøk i NAV\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mLagrede søk\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mLagrede NAV-søk kontrolleres automatisk. Du får et varsel når nye stillinger dukker opp.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mNavn på søket\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mNavn på søket\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mLagre søk\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mIngen lagrede søk ennå.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mOffisielle norske stillinger fra NAV. Stillinger fra FINN, Indeed og LinkedIn kan fortsatt hentes inn via nettadresse.\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSøk i nylige aktive stillinger etter rolle, bedrift eller kommune.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n\u001b[36m\u001b[39m\n at Object.getElementError (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\config.js:37:19)\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:76:38\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:52:17\n at C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\node_modules\\@testing-library\\dom\\dist\\query-helpers.js:95:19\n at getByRole (C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\job-discovery.test.tsx:33:26)"],"fullName":"keeps nb filters before results with keyboard jump/return and no automatic provider search","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312318,"status":"failed","title":"keeps nb filters before results with keyboard jump/return and no automatic provider search"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"shows honest source metadata and offers the existing reviewed save flow","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312405,"status":"pending","title":"shows honest source metadata and offers the existing reviewed save flow"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"distinguishes the initial guidance from a completed empty search","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312405,"status":"pending","title":"distinguishes the initial guidance from a completed empty search"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"retries the last submitted search after an error","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312405,"status":"pending","title":"retries the last submitted search after an error"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"sorts returned vacancies by title","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312405,"status":"pending","title":"sorts returned vacancies by title"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"renders the discovery workflow in Norwegian Bokmål","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312405,"status":"pending","title":"renders the discovery workflow in Norwegian Bokmål"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"runs a saved search, marks unseen vacancies, and dismisses them","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312405,"status":"pending","title":"runs a saved search, marks unseen vacancies, and dismisses them"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"lets the user pause automatic alerts for a saved search","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312405,"status":"pending","title":"lets the user pause automatic alerts for a saved search"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"announces saved-search loading without presenting a successful empty list","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"announces saved-search loading without presenting a successful empty list"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"reports saved-search failure and retries that read without replacing active discovery filters or results","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"reports saved-search failure and retries that read without replacing active discovery filters or results"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed saved-search payload null as a failed read rather than an empty list","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"rejects malformed saved-search payload null as a failed read rather than an empty list"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed saved-search payload {\"message\":\"not a list\"} as a failed read rather than an empty list","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"rejects malformed saved-search payload {\"message\":\"not a list\"} as a failed read rather than an empty list"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"rejects malformed saved-search payload [{\"id\":7}] as a failed read rather than an empty list","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"rejects malformed saved-search payload [{\"id\":7}] as a failed read rather than an empty list"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a manual search after saved-search results has no dismiss action belonging to the saved search","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"a manual search after saved-search results has no dismiss action belonging to the saved search"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"starting saved search B hides saved search A's results and actions while the B response is held","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"starting saved search B hides saved search A's results and actions while the B response is held"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"retrying a failed saved-search run repeats that saved ID instead of running a manual query","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"retrying a failed saved-search run repeats that saved ID instead of running a manual query"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"failed saved-search creation retains its draft and recovers only through the save action","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"failed saved-search creation retains its draft and recovers only through the save action"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a failed alert toggle retains its checked state and recovers through that same toggle without manual search retry","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"a failed alert toggle retains its checked state and recovers through that same toggle without manual search retry"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"failed saved-search deletion preserves the search and requires another explicit confirmation to recover","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"failed saved-search deletion preserves the search and requires another explicit confirmation to recover"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"failed dismissal retains the vacancy and recovers only through that same result's dismiss action","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"failed dismissal retains the vacancy and recovers only through that same result's dismiss action"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a held saved-search creation locks its request snapshot and prevents a second start while preserving a failed draft","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"a held saved-search creation locks its request snapshot and prevents a second start while preserving a failed draft"},{"ancestorTitles":[],"duration":null,"failing":false,"failureDetails":[],"failureMessages":[],"fullName":"a saved-run failure follows the current language without refetching or replaying the request","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"startAt":1793697312406,"status":"pending","title":"a saved-run failure follows the current language without refetching or replaying the request"}],"endTime":1793697312419,"message":" ● keeps en filters before results with keyboard jump/return and no automatic provider search\n\n TestingLibraryElementError: Unable to find an accessible element with the role \"complementary\" and name \"Search filters\"\n\n Here are the accessible roles:\n\n textbox:\n\n Name \"Role or company\":\n \u001b[36m\u001b[39m\n\n Name \"Municipality\":\n \u001b[36m\u001b[39m\n\n Name \"Search name\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n button:\n\n Name \"Search NAV\":\n \u001b[36m\u001b[39m\n\n Name \"Save search\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n heading:\n\n Name \"Saved searches\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n paragraph:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n alert:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n region:\n\n Name \"Search results\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n status:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n\n Ignored nodes: comments, script, style\n \u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mRole or company\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mRole or company\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mMunicipality\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mMunicipality\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSearch NAV\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSaved searches\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSaved NAV searches are checked automatically. You will be notified when new vacancies appear.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSearch name\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSearch name\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSave search\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mNo saved searches yet.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mOfficial Norwegian vacancies from NAV. FINN, Indeed and LinkedIn jobs can still be captured by URL.\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSearch recent active vacancies by role, company, or municipality.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n\n 31 | renderPage();\n 32 | await screen.findByText(translations[language].jobDiscoveryNoSavedSearches);\n > 33 | const filters = screen.getByRole('complementary', { name: filtersName });\n | ^\n 34 | const results = screen.getByRole('region', { name: translations[language].jobDiscoveryResults });\n 35 | expect(filters.compareDocumentPosition(results) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();\n 36 | expect(within(filters).getByRole('form', { name: filtersName })).toBeInTheDocument();\n\n at Object.getElementError (node_modules/@testing-library/dom/dist/config.js:37:19)\n at node_modules/@testing-library/dom/dist/query-helpers.js:76:38\n at node_modules/@testing-library/dom/dist/query-helpers.js:52:17\n at node_modules/@testing-library/dom/dist/query-helpers.js:95:19\n at getByRole (src/job-discovery.test.tsx:33:26)\n\n ● keeps nb filters before results with keyboard jump/return and no automatic provider search\n\n TestingLibraryElementError: Unable to find an accessible element with the role \"complementary\" and name \"Søkefiltre\"\n\n Here are the accessible roles:\n\n textbox:\n\n Name \"Rolle eller bedrift\":\n \u001b[36m\u001b[39m\n\n Name \"Kommune\":\n \u001b[36m\u001b[39m\n\n Name \"Navn på søket\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n button:\n\n Name \"Søk i NAV\":\n \u001b[36m\u001b[39m\n\n Name \"Lagre søk\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n heading:\n\n Name \"Lagrede søk\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n paragraph:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n alert:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n region:\n\n Name \"Søkeresultater\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n status:\n\n Name \"\":\n \u001b[36m\u001b[39m\n\n --------------------------------------------------\n\n Ignored nodes: comments, script, style\n \u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mRolle eller bedrift\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mRolle eller bedrift\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m
\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mKommune\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mKommune\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSøk i NAV\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mLagrede søk\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mLagrede NAV-søk kontrolleres automatisk. Du får et varsel når nye stillinger dukker opp.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mNavn på søket\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mNavn på søket\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mLagre søk\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mIngen lagrede søk ennå.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mOffisielle norske stillinger fra NAV. Stillinger fra FINN, Indeed og LinkedIn kan fortsatt hentes inn via nettadresse.\u001b[0m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[0mSøk i nylige aktive stillinger etter rolle, bedrift eller kommune.\u001b[0m\n \u001b[36m

\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n \u001b[36m\u001b[39m\n\n 31 | renderPage();\n 32 | await screen.findByText(translations[language].jobDiscoveryNoSavedSearches);\n > 33 | const filters = screen.getByRole('complementary', { name: filtersName });\n | ^\n 34 | const results = screen.getByRole('region', { name: translations[language].jobDiscoveryResults });\n 35 | expect(filters.compareDocumentPosition(results) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();\n 36 | expect(within(filters).getByRole('form', { name: filtersName })).toBeInTheDocument();\n\n at Object.getElementError (node_modules/@testing-library/dom/dist/config.js:37:19)\n at node_modules/@testing-library/dom/dist/query-helpers.js:76:38\n at node_modules/@testing-library/dom/dist/query-helpers.js:52:17\n at node_modules/@testing-library/dom/dist/query-helpers.js:95:19\n at getByRole (src/job-discovery.test.tsx:33:26)\n","name":"C:\\Users\\Connor\\.codex\\worktrees\\direct-roadmap-integration\\Job tracker\\job-tracker-ui\\src\\job-discovery.test.tsx","startTime":1793697309669,"status":"failed","summary":""}],"wasInterrupted":false} diff --git a/docs/ui-modernisation/evidence/discovery/SOURCE_MANIFEST.json b/docs/ui-modernisation/evidence/discovery/SOURCE_MANIFEST.json new file mode 100644 index 00000000..be4c2ba3 --- /dev/null +++ b/docs/ui-modernisation/evidence/discovery/SOURCE_MANIFEST.json @@ -0,0 +1,159 @@ +{ + "base": "172074e90f3c7067b1cbc7e65724b303c2fc9ff6", + "recordedAtUtc": "2026-11-03T09:22:16.775542+00:00", + "policy": "Text LF-normalised SHA256; PNG/export raw bytes", + "sources": { + "JobTrackerApi.Tests/JobDiscoveryControllerTests.cs": "992ef6456e5665000a861445d62be816622ae3474af2017c8e9342b56a98f7c2", + "JobTrackerApi.Tests/SavedJobSearchAlertTests.cs": "bd9d5530a5af618c60be4b16eaf8f46c8e13ba9cc39f10eab95690ca0e820d51", + "JobTrackerApi.Tests/SavedJobSearchSqliteTests.cs": "cce4ec28606b53a4756f6056afbc4ae626cdcb6f624a85ede0268cacd6c1bf50", + "JobTrackerApi/Controllers/JobDiscoveryController.cs": "1ffb95a866dc821c468df8dfbbec75d4c7b1656bfb791109c43915205f4d6ee6", + "docs/ui-modernisation/DISCOVERY_VALIDATION.md": "af3089a2b856546883cfdb243b3e5870d0bf1852665d73a932f6ce47a8f3da0d", + "docs/ui-modernisation/UI-05.md": "556454f107efb305cbdebf08979e852a97ac7c1ddbea6e78c7fb7fb1b78cdcc0", + "job-tracker-ui/package-lock.json": "bf31e90d7af03e8af059db2aaf893925b9e8881a30a1688034ed88ef45d4fcab", + "job-tracker-ui/package.json": "3745394e406cefa40d30a87e840bccb359be147bac6ffba736e2ae90898a8626", + "job-tracker-ui/scripts/verify-a3-discovery.mjs": "b99cdbdcbd9098f29c8415518454e2855d55c4f830dbe81f2356bb931d734292", + "job-tracker-ui/src/App.tsx": "608b4bed6c7e2881dfd65b7541ea211d193a636dd3f9cdf9a6d172acd12d137d", + "job-tracker-ui/src/i18n/I18nProvider.tsx": "d22b5d033d0e405ffb5d581c752d61a24056d1e496f5f6a2f1baecef500f2113", + "job-tracker-ui/src/i18n/translations.ts": "e013bb581545aa0ca46b19698da8db8497172a2ed0050f8012bf726f276c209e", + "job-tracker-ui/src/job-discovery.test.tsx": "16f740b867166aa9bf51377e8732a14e76a539f6d5eb8df989cede48297a1eaa", + "job-tracker-ui/src/views/JobDiscoveryPage.tsx": "1ca763c2d260857b4668874f7edc7e97094b4f5c47cac57fb4a1a1fd5f19e28d" + }, + "evidence": { + "backend/a3-discovery.trx": "65d01af81be5d35525ae59174a201bd7defc9214e1c7a37f59188aa5dfa601a0", + "BASELINE.json": "a3092cc483f35dd3323872fa51392113ddbc3a8fe5116e88253cbc01446d87ee", + "browser/BROWSER.json": "965be1d3e5a5d542d115fad67fa19955045f6b3800839b2dfda6509e3ad03bc2", + "browser/initial-en-dark-1440.png": "3a12fc1471d320f2df83b5c3acb9a7d6f60cb54d64bdc4f4a6c2f041356fc32c", + "browser/initial-en-dark-320.png": "9e2505110b91c3f216cf3f4624e999aaf5491482117829bff285b74122849c5a", + "browser/initial-en-dark-390.png": "73b0c1f06fbce0bfc2ceda5ddfb1c6c601ce45a3a75b38b20deccba55dca1d6c", + "browser/initial-en-dark-768.png": "71549654130c2189ef68e82278e315c7a9b3ff99973e6296c63c9eaa5830e8e0", + "browser/initial-en-light-1440.png": "c499efdbbf8041e33a06f3ab9ce19fb0e5d7f59508db28e75e39a1934b1783b8", + "browser/initial-en-light-320.png": "de9fbcf0b891b2d767f3117a5ccd63bb5e799a2070c9815e10bdfb9fb86c89f6", + "browser/initial-en-light-390.png": "52e33023368e7b8fdf8137b1cc507c3b704e6f9b5a379492c22018810a209b78", + "browser/initial-en-light-768.png": "075a68243d009acc98526bf1c8d883424c7a0897fda531b077d430f8b642005f", + "browser/initial-nb-dark-1440.png": "17fc099d3c589f89cf0585c40c1d951207ce40e5fdcb8c2179f4ed14f34bc9ae", + "browser/initial-nb-dark-320.png": "f5029110e8d2f2897a0738a6be3b274ffd7a7c1f8b83d7d3a13479c565c856ab", + "browser/initial-nb-dark-390.png": "037de0eb12a3fc4ee6e420b9a7be4aba0419e1bed885d00737be480d4c4ab2cf", + "browser/initial-nb-dark-768.png": "d60d04719391a70ca21fd73afe45cad760534f0c6e6d2a75db9f44f0d179ec10", + "browser/initial-nb-light-1440.png": "737c70660b9954f307269e4f78dc751fdce4b6eb6f8537b1754095537cf86f9d", + "browser/initial-nb-light-320.png": "c5ee8c49cba083534e851f9b317b2f12f7d8b6547adf5b548c0bdd6ade3754ba", + "browser/initial-nb-light-390.png": "a5d7bf512b2f905f78a98fad66fb086a1b90ffb08cc5986b8daed9912208c9a4", + "browser/initial-nb-light-768.png": "23039a8c3dc33e5f85de6a70eb8d750775d94e628a30328060c63e84fc0d31b0", + "browser/results-en-dark-1440.png": "be364ec237641931adadc78c562071f75847b365d71f666fb725d6e7aac1693d", + "browser/results-en-dark-320.png": "cc0e14759447e6d17c03ab685ef9297af323adc1f95fe3d4263fca0f7383ab70", + "browser/results-en-dark-390.png": "dc3b1c63dc7b10264b4a06e9de2a1da172bff54c2bdc4c01c8aa595a824f50ad", + "browser/results-en-dark-768.png": "f36b37f508c349baf3b6ac5f28c351a1ccb8278d9d11d25fad9737785071f122", + "browser/results-en-light-1440.png": "8fb5a06e61f9e341004820e42f951c4f819350df3e9affbfc9b60e5f3418d1d1", + "browser/results-en-light-320.png": "1eebe349242081ddadbba1d989c38016284e7749d918cedc2d4c1c95cfa3a5f0", + "browser/results-en-light-390.png": "f0bfe97d323ca5baa3d071b55469d04b5fc2b23d2a643dd8e58486e30a5eca50", + "browser/results-en-light-768.png": "fdc248665539d6288ca0ac56ccfb01e5811bf7a8abf0750b188e0531cc16f25e", + "browser/results-nb-dark-1440.png": "0f925f269fef75ed986df41cf1e2d68010a8cd1fa4df8dbff9b1a21ee544d571", + "browser/results-nb-dark-320.png": "869ac6fdbe1fec789b832193258fd7867f244d36242c7a6e740a9e74c53b4a2c", + "browser/results-nb-dark-390.png": "9e32d6114960e5f54e9381564eecfc59dda5f47e8cb16bafe95cacb72ad3c0a0", + "browser/results-nb-dark-768.png": "ae429e0ca218522b2010f208a261b1aad4fb0ec5ba8b9b940fc6eff46a899a49", + "browser/results-nb-light-1440.png": "36fdb25acfd5c0e717f1a5e78a5787462ab3a1ca19187b6fced3d34353533260", + "browser/results-nb-light-320.png": "d86c08ebe2fcffa90f44d87c3a8f9acd39a2e2ae9d3c94e80d546b58529d2ecd", + "browser/results-nb-light-390.png": "2b45634c04e7980047f3620aeacfb12ae4a18b9bb51da977de212b02ec39a51e", + "browser/results-nb-light-768.png": "21fcc316ab6d0698bf6b92e8bdeceb19aa32931d62be01316f8e2758c62bf567", + "browser/saved-en-dark-1440.png": "02b626a300bd31f47f619c4d843a7c5e93fa8ff3983a3373b2a91ed0658ef58a", + "browser/saved-en-dark-320.png": "be2c6a9afd0e8a9663acee2805fe150132f018572f6055499e9ba92708f7e472", + "browser/saved-en-dark-390.png": "e932c0b4b3b9b2ba50255819acaeda101819e754197bcb558024573d04a43d25", + "browser/saved-en-dark-768.png": "04f0eb72dccd17e3e42c5063159b00b1308428210658bbefcbee22a5781fbbe5", + "browser/saved-en-light-1440.png": "06c2baf578a44d082aad300aa631f54ef5adc861a096ded66ded133696e9f83b", + "browser/saved-en-light-320.png": "a51efbf57e657d36dc96ee3665e890e3113c05368d13fde783d8469e191cbd84", + "browser/saved-en-light-390.png": "faa22fae1a70c149d5cb564f52f095027d2c577a2cdcc4fc3d9426e7d9c2b693", + "browser/saved-en-light-768.png": "ec67225c7ef556a6fafab908e672b593437da890f1ba6282936ae2f63d9f7bd3", + "browser/saved-nb-dark-1440.png": "7eb99d37e71e17a1bcf8084ea888120282b4fdf32cac362f2c27365791872a3f", + "browser/saved-nb-dark-320.png": "29f85685e3ba1ae86613efcb6f82886e3f5606c609b6cbe4982fa9fa99a168b9", + "browser/saved-nb-dark-390.png": "d38f09f29e71a82138200b8aaae7ac6549f69165eaa56eb0d2a08c4b8938f90e", + "browser/saved-nb-dark-768.png": "4d359a62983dc29c0b907345380f62f32224519a35b6617c3db7410a11a8a5f4", + "browser/saved-nb-light-1440.png": "1cdf65b14108abcf4fb33964ecf2ec2431529909605e80c32e974d47443fd4bc", + "browser/saved-nb-light-320.png": "5c15c8b4fdd5a0be8b9961f1bc39ec2f7e7f9ec2b690a09ef636c58b8cf0aea8", + "browser/saved-nb-light-390.png": "42c7346f72fdc0625068351b66f6e0209f8fb6e721ff98c1458cfb32e989e9fa", + "browser/saved-nb-light-768.png": "45cf23dcd9854ed35d2aedf625c695e3f3ce1a63c0ae3572357323928d39af6d", + "CHECKS.json": "ea962db253a526f14b324f310912dd8c1b3dcf8a491f9f54d82275b119cd7126", + "FINAL_TESTS.json": "939dff50fe6c75ca3e29c7d4f738f2488b39d274eec583b41b65aaba41a85674", + "RED_TESTS.json": "e5c4fd470cf3341b1434b6c033a0073c8fecc80124733a0ce92666cc89ac0251" + }, + "export": { + "404.html": "636bbf544e10be51e7100526a1baddbec11c958f507c477eb09905952da42c69", + "__next.__PAGE__.txt": "ba07c5588750e69f569edee00a6f4d1992b6a13094cac48045c2f1d5b7032062", + "__next._full.txt": "454f43dc610f4c46447a8e7a297d53d6a338bfcfb7f5d082c2ae7b654494b937", + "__next._tree.txt": "d96253f659a1ba77e19c0508093bde230d3b45bad49304537648506743c8ea78", + "_next/static/chunks/0-_aq6ipzcshj.js": "39f90c215bf52aef6274ed3dcc0f8af32e21a37fe8845b3bca0d6ea60da6a8c2", + "_next/static/chunks/07vdc-duql714.js": "5a4840d1ba6b65782459968940a2f4cf973c99f0f77890f4171c4f420f339353", + "_next/static/chunks/0ah1fzqmie05a.js": "5c65505a7dcbac63ac71d254e619a4c800943bfb4fa16cd40c10cdbe7e9b6e31", + "_next/static/chunks/0bdt7ln111t48.js": "6184b1a61f22e2a640c17941634fdc75678ce93d142848d9f07f163e0d1fd201", + "_next/static/chunks/0bwvt3mysnclc.js": "7705667a1b75812b7833d9c9dff47fe023015e58e382c40f4507d9948c973af4", + "_next/static/chunks/0cz1d0mv5g_q7.js": "0973c1d64c88adc8e3c950410cb58b288f72118d5965b78049438deb8f2f9683", + "_next/static/chunks/0enhs8x_8oeah.js": "44c76f6178d407e1f147fdf70015fd05c21e58ed220fc922d23dfd1e0f8631bd", + "_next/static/chunks/0jcvc3qm6-lyk.js": "7c27e1fe373b822adc68c63096a5bf38444ad605b9743f0920271652989c56f1", + "_next/static/chunks/0q20g9o8x-k8z.js": "3d4d9086985419aa8866b032158196c774acb8bf318f3c8245508c8daa9c5148", + "_next/static/chunks/0q_pwu9jxv4-d.js": "42a43b3d7245a413c7c29b4cbe87823037a6dbc637e2e282c92405470e0f575d", + "_next/static/chunks/11-48p8kygxgp.js": "57eb9059599b5a5a30598d0a334912d58af571c0ffe28448ca76ad77c8ea8df9", + "_next/static/chunks/14-lfugawba2w.js": "6a5780ca3c84d7f130f3c0a14431c85c7a1e799e2645b8c171161dab40a64360", + "_next/static/chunks/1435in_k_-dhc.js": "4757476512d5c4dd25f9264a18b304ed4824b23aff1c09e134fcbff21d9c36b6", + "_next/static/chunks/145oicobmjvm7.js": "d6bbbdeed1381652dc7412e5ce673a077579ecd5cee8934cb6b533c814098764", + "_next/static/chunks/14e7ovj0s3elm.js": "070567dd4d23fb9fa0b9ba132185a697af6578045d43b2b1c7bbb2a1594d935d", + "_next/static/chunks/154b5a6du9olf.js": "49e4df3a3e10119ddc34f84767883b9228ff6798a07fd759c2fb8e2be62fe9fb", + "_next/static/chunks/16lfece6cnlln.js": "716363ba044f30b0e70440756b4e5eafa2d25f2e1628e855e3bc4ab9eabee3d3", + "_next/static/chunks/1d0xrdyyzw7qc.js": "c11668ff1e152008e0d7b4454af12eb36c97df46a5860938e2eb5d8429b374a8", + "_next/static/chunks/1h7j7ef9e6i41.js": "cb6cd497566dc188b67d09b9c031ef9bbf36f2b85d0aac02621f56daa44faa34", + "_next/static/chunks/1ke8pzecwofrg.css": "32e9ab963ebadebcbe2c68dffb24cfbfc8cc24255ad91b48b7941fc777bf7439", + "_next/static/chunks/1req80b9jj38r.js": "eee4d2e3789e1215195dba99ad0f09d34f8c83da848322b76054722233e9dae3", + "_next/static/chunks/1w3q8yrcjn2jk.js": "365200e241ee9290e93d7c2fdba169f2b0a8e774541e3cbf3f6f2781110fa644", + "_next/static/chunks/1xn023_28rgzj.js": "4f7f2108d030a48d039930736c92a55710975dddf419fe673f84d92899b1f575", + "_next/static/chunks/1xwc-b795syag.css": "f73c002233f931ca14d0ae58815c47ca9f2659f25b1547a6d1fdca12a2a00b3f", + "_next/static/chunks/1yx5pd9k61fi3.js": "1f9bb26664ca84fef80c0987470c1357c63015cf68fd14dc569f504e373fcd2a", + "_next/static/chunks/1zi8i6dnxiac_.js": "8aea28bbe6a138e5d4b619429ca71570883a7aee974b86d5a4a746d90f704dbc", + "_next/static/chunks/2-o9_wag-xnw1.js": "2d5526cb095b6f27580073719533b9448a17869517d9025c08a5b18b5060b1a7", + "_next/static/chunks/22uh2tvaw80j2.js": "dafe6b4e23dc5c1d32f8b4a60c561238d2d5e7545f23ebc5b3f7304b48626dbf", + "_next/static/chunks/22wx8--1b9tnq.js": "3f7d8e762371262c6a740b4dac21725b424847319afac46055e97074a99ff5f5", + "_next/static/chunks/245ibf0f31ne8.js": "8b27ab5d720bd278b5d73a7e824bfcccf4cc893ced9fa6f1937bb2bc7a65f967", + "_next/static/chunks/25bla1_zt8h9n.js": "9bf2c6430507ac6b637ba6f3cda6e7e59a556433dbf84697a3ac466fe028befc", + "_next/static/chunks/280cq9ekejv1f.js": "01de8c1c3555cdd8d711763065ea9d8aec2968c3053f61254e43e26c999027bf", + "_next/static/chunks/2br3ad_-bc7k9.js": "80fa55f7a32db4d743fda36747c36994fde00a0f53f2eb25b2a6d07c6fb97cd7", + "_next/static/chunks/2gd9s_n-0nl1p.js": "31e2811be51a3c4d0ff2d1e3cea756e7fd8d57ef89141b5de69f638c1301d039", + "_next/static/chunks/2ghgf2s9b2iou.js": "23d8ff31e2128d0541c1887785fb75885323fea7c5d4f35826513b75c12c2ae3", + "_next/static/chunks/2s2gjr6ro25dj.js": "7489e2ac285a05b563c2bcb4eaf9274bf930f2a7385f17d6d5e6850064b88b10", + "_next/static/chunks/2u5qve004opku.js": "be388d9a6aa423082bafb4584c3facc65ddfed71bcfa5c1d06b097b408c5ff97", + "_next/static/chunks/2xlg4_1fj8fxh.js": "8ab4ba521db0167f3dbf684787ebf643cbc66fa7ffff7cdc65a8d8076a926155", + "_next/static/chunks/2z42el0b2mp8_.js": "86ff990ef32c90c4839583e4f1d1bcbddb165dad3141b9fcd2ecec67f4ff24b8", + "_next/static/chunks/32_ah983ce851.js": "0c3cd0d2a5ad789e31226a9ea0506c50016804311a58548c7784b7b45aaecd14", + "_next/static/chunks/334vtqp3-g1j6.js": "c33d42da97f3af7388e29273297e9f42c67f54b7f5ec77a5d0637e2da06d7f7e", + "_next/static/chunks/363gk7a7bsb2_.js": "5ab85d081786081f8a028612f2db6ab88e0999f69a1368cc236e7e675336c7dd", + "_next/static/chunks/3720519r84mh6.js": "54358db392a13914e3363046d594e824b1a3ef987913d95002bf48267dded4aa", + "_next/static/chunks/3bqn9b34na0b9.js": "f1b8ebcc1b22251c33c9f3a5d11c1f893cad2da2e8744a441e790f7347aa9e73", + "_next/static/chunks/3ckk_j5ril9ag.js": "87f631dae7b648d32171e9e05a3e000753ecb54f8d3b86a4401c0e4ab4d73553", + "_next/static/chunks/3f96r6vscobou.js": "d4b452ff3f1433f8fe1df705a8f592326f51b5a8846e6c2790d28df5a977aed3", + "_next/static/chunks/3gkylew_qn7cw.js": "7e6c74c81be0c41ab433e36d65b914f62c48f332922e27f7cc953476f4dd78cb", + "_next/static/chunks/3mowdlh-jq9ii.js": "2c6ccd1500d28ec0c7312cb08ee221f0e4184ba21465ee166a054aa9a6c7f3ed", + "_next/static/chunks/3os11ovm65tyl.js": "c5a908bd61f53f0d75927efb71e53aef8fdd9b2e4fef412a167990dbc702c166", + "_next/static/chunks/3q4v10rrqy40n.js": "d87ff7b7a0f07d0d92eab3876481eb686a12d9c43d8b92cbe406aefa227a11c1", + "_next/static/chunks/3q80eur194l-9.js": "7b52d29843c23a0ed74056eeb1704de14488f36e9d05f2f8271434c61051dce0", + "_next/static/chunks/3u61o8t7m_jza.js": "86231c12e0f8cacc8638bed0bc4b34f645fc35e60de342dc154d3cce0c9a5afa", + "_next/static/chunks/40y_aqqilokr2.js": "1f5a5260316134d6bffe949400752ee6b42addf908ae714ef4ae4ebde916dddd", + "_next/static/chunks/42m2bnxn73hts.js": "350a7e8a4f909d9f218e4394ea145e199cdf99cd842daa0707a052ac278111be", + "_next/static/chunks/43b5x8qjjh3ax.js": "6ee7261cf9a63e0e6ea181bbb09125e09948588b6e10b5c02727c686a6062a3a", + "_next/static/chunks/442d7ylb3po0z.js": "d95cedfbdcd00c674fd718cbbf391ec01c0728018b0db2461a06df7074049132", + "_next/static/chunks/turbopack-25fzg9ay_1ss-.js": "c40f39e993a30c96d6247bb3a7b581538bb046efe8ef8ec07bea3ba32291750f", + "_next/static/tWC8u1eSOOrFsplqYcaKg/_buildManifest.js": "9476e0afd3f9da68a64e6ec58631191fd3eaca62c9f5a377e7517fe9a89e59ea", + "_next/static/tWC8u1eSOOrFsplqYcaKg/_clientMiddlewareManifest.js": "5483e3295dc35dfe29ea932efc85341c916f10ff78ff5b0e965e003710893a4a", + "_next/static/tWC8u1eSOOrFsplqYcaKg/_ssgManifest.js": "678f6ce2cb80b1fe72fc67e7412be6e2ab6ada083111b64f7c40d35e3cba5e00", + "_not-found/__next._full.txt": "30087a582f18ddd290f006f5ed523ee36561e7ecafa713cc8b5f3c5db483e6a3", + "_not-found/__next._not-found/__PAGE__.txt": "d1e77903bbaa7e60feb1d15b42ddc75bcdef3d8c493f1a18748de1eba17d9739", + "_not-found/__next._tree.txt": "3c326f353873dabfab4ddfe75ddd0d359a0e7c0fa2b38e52db1cfbd8a27d615c", + "_not-found.html": "636bbf544e10be51e7100526a1baddbec11c958f507c477eb09905952da42c69", + "_not-found.txt": "30087a582f18ddd290f006f5ed523ee36561e7ecafa713cc8b5f3c5db483e6a3", + "favicon.ico": "8d4923e2c487805ea9f852a685b2cf0fb10512ded8290d2a5c37d1cc8fd0702a", + "favicon.svg": "63ecf8f37f8bb146ecfae3917187c6b692d4e801641e8a314486a4007912f3a3", + "index.html": "a851de02d275452557871582a7a875608b84f3b484435887ba70529f9aca2ad8", + "index.txt": "454f43dc610f4c46447a8e7a297d53d6a338bfcfb7f5d082c2ae7b654494b937", + "logo192.png": "bc652031597fabd19b9f14e22a71f809490d218037521b3b64d013418c1390b4", + "logo512.png": "5129e9bc1ba812b711fd9a646d3a38a906d365a26ee685df183b8752458944d4", + "manifest.json": "2667ce63c2e0835b7007239816a5597639321d333da396a78638dfa9e8a7c935", + "mockups/dashboard.svg": "318be3adb1324c26eb30f05572a29528a3e38331c6a604652eef75b54f8c29dc", + "mockups/pipeline.svg": "db2ef41faabeb90e7ce85413e168581686c54535d970fc7d8deda3888a479de4", + "mockups/workspace.svg": "9bbab22349147c7b01d6e18c93c622a6f8aed6dedaf23715189ab54d60e1ddbd", + "robots.txt": "e5ab0d231eeb01b4a982d1c79a6729cac9797ad15a69247e4f28ba6afc149b4c" + } +} diff --git a/docs/ui-modernisation/evidence/discovery/backend/a3-discovery.trx b/docs/ui-modernisation/evidence/discovery/backend/a3-discovery.trx new file mode 100644 index 00000000..c1e1de23 --- /dev/null +++ b/docs/ui-modernisation/evidence/discovery/backend/a3-discovery.trx @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + info: 03/11/2026 10:17:37.621 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) + Executed DbCommand (0ms) [Parameters=[@__ef_filter__p_1='?' (DbType = Boolean), @__ef_filter__CurrentUserId_0='?' (Size = 7), @__owner_0='?' (Size = 7)], CommandType='Text', CommandTimeout='30'] + SELECT "s"."UpdatedAtUtc", "s"."Id", "s"."Name", "s"."Query", "s"."Location", "s"."IsActive", "s"."LastRunAtUtc", ( + SELECT COUNT(*) + FROM "SavedJobSearchResults" AS "s0" + INNER JOIN ( + SELECT "s1"."Id", "s1"."OwnerUserId" + FROM "SavedJobSearches" AS "s1" + WHERE @__ef_filter__p_1 AND "s1"."OwnerUserId" = @__ef_filter__CurrentUserId_0 + ) AS "s2" ON "s0"."SavedJobSearchId" = "s2"."Id" + WHERE @__ef_filter__p_1 AND "s2"."OwnerUserId" = @__ef_filter__CurrentUserId_0 AND "s"."Id" = "s0"."SavedJobSearchId"), ( + SELECT COUNT(*) + FROM "SavedJobSearchResults" AS "s3" + INNER JOIN ( + SELECT "s4"."Id", "s4"."OwnerUserId" + FROM "SavedJobSearches" AS "s4" + WHERE @__ef_filter__p_1 AND "s4"."OwnerUserId" = @__ef_filter__CurrentUserId_0 + ) AS "s5" ON "s3"."SavedJobSearchId" = "s5"."Id" + WHERE @__ef_filter__p_1 AND "s5"."OwnerUserId" = @__ef_filter__CurrentUserId_0 AND "s"."Id" = "s3"."SavedJobSearchId" AND "s3"."IsDismissed") + FROM "SavedJobSearches" AS "s" + WHERE @__ef_filter__p_1 AND "s"."OwnerUserId" = @__ef_filter__CurrentUserId_0 AND "s"."OwnerUserId" = @__owner_0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 9.0.19) +[xUnit.net 00:00:00.19] Discovering: JobTrackerApi.Tests +[xUnit.net 00:00:00.34] Discovered: JobTrackerApi.Tests +[xUnit.net 00:00:00.34] Starting: JobTrackerApi.Tests +[xUnit.net 00:00:02.14] Finished: JobTrackerApi.Tests + + + + \ No newline at end of file diff --git a/docs/ui-modernisation/evidence/discovery/browser/BROWSER.json b/docs/ui-modernisation/evidence/discovery/browser/BROWSER.json new file mode 100644 index 00000000..1c4f56c4 --- /dev/null +++ b/docs/ui-modernisation/evidence/discovery/browser/BROWSER.json @@ -0,0 +1,944 @@ +{ + "screens": [ + { + "width": 320, + "language": "en", + "mode": "light", + "state": "initial", + "violations": [] + }, + { + "width": 320, + "language": "en", + "mode": "light", + "state": "results", + "violations": [] + }, + { + "width": 320, + "language": "en", + "mode": "light", + "state": "saved", + "violations": [] + }, + { + "width": 320, + "language": "en", + "mode": "dark", + "state": "initial", + "violations": [] + }, + { + "width": 320, + "language": "en", + "mode": "dark", + "state": "results", + "violations": [] + }, + { + "width": 320, + "language": "en", + "mode": "dark", + "state": "saved", + "violations": [] + }, + { + "width": 320, + "language": "nb", + "mode": "light", + "state": "initial", + "violations": [] + }, + { + "width": 320, + "language": "nb", + "mode": "light", + "state": "results", + "violations": [] + }, + { + "width": 320, + "language": "nb", + "mode": "light", + "state": "saved", + "violations": [] + }, + { + "width": 320, + "language": "nb", + "mode": "dark", + "state": "initial", + "violations": [] + }, + { + "width": 320, + "language": "nb", + "mode": "dark", + "state": "results", + "violations": [] + }, + { + "width": 320, + "language": "nb", + "mode": "dark", + "state": "saved", + "violations": [] + }, + { + "width": 390, + "language": "en", + "mode": "light", + "state": "initial", + "violations": [] + }, + { + "width": 390, + "language": "en", + "mode": "light", + "state": "results", + "violations": [] + }, + { + "width": 390, + "language": "en", + "mode": "light", + "state": "saved", + "violations": [] + }, + { + "width": 390, + "language": "en", + "mode": "dark", + "state": "initial", + "violations": [] + }, + { + "width": 390, + "language": "en", + "mode": "dark", + "state": "results", + "violations": [] + }, + { + "width": 390, + "language": "en", + "mode": "dark", + "state": "saved", + "violations": [] + }, + { + "width": 390, + "language": "nb", + "mode": "light", + "state": "initial", + "violations": [] + }, + { + "width": 390, + "language": "nb", + "mode": "light", + "state": "results", + "violations": [] + }, + { + "width": 390, + "language": "nb", + "mode": "light", + "state": "saved", + "violations": [] + }, + { + "width": 390, + "language": "nb", + "mode": "dark", + "state": "initial", + "violations": [] + }, + { + "width": 390, + "language": "nb", + "mode": "dark", + "state": "results", + "violations": [] + }, + { + "width": 390, + "language": "nb", + "mode": "dark", + "state": "saved", + "violations": [] + }, + { + "width": 768, + "language": "en", + "mode": "light", + "state": "initial", + "violations": [] + }, + { + "width": 768, + "language": "en", + "mode": "light", + "state": "results", + "violations": [] + }, + { + "width": 768, + "language": "en", + "mode": "light", + "state": "saved", + "violations": [] + }, + { + "width": 768, + "language": "en", + "mode": "dark", + "state": "initial", + "violations": [] + }, + { + "width": 768, + "language": "en", + "mode": "dark", + "state": "results", + "violations": [] + }, + { + "width": 768, + "language": "en", + "mode": "dark", + "state": "saved", + "violations": [] + }, + { + "width": 768, + "language": "nb", + "mode": "light", + "state": "initial", + "violations": [] + }, + { + "width": 768, + "language": "nb", + "mode": "light", + "state": "results", + "violations": [] + }, + { + "width": 768, + "language": "nb", + "mode": "light", + "state": "saved", + "violations": [] + }, + { + "width": 768, + "language": "nb", + "mode": "dark", + "state": "initial", + "violations": [] + }, + { + "width": 768, + "language": "nb", + "mode": "dark", + "state": "results", + "violations": [] + }, + { + "width": 768, + "language": "nb", + "mode": "dark", + "state": "saved", + "violations": [] + }, + { + "width": 1440, + "language": "en", + "mode": "light", + "state": "initial", + "violations": [] + }, + { + "width": 1440, + "language": "en", + "mode": "light", + "state": "results", + "violations": [] + }, + { + "width": 1440, + "language": "en", + "mode": "light", + "state": "saved", + "violations": [] + }, + { + "width": 1440, + "language": "en", + "mode": "dark", + "state": "initial", + "violations": [] + }, + { + "width": 1440, + "language": "en", + "mode": "dark", + "state": "results", + "violations": [] + }, + { + "width": 1440, + "language": "en", + "mode": "dark", + "state": "saved", + "violations": [] + }, + { + "width": 1440, + "language": "nb", + "mode": "light", + "state": "initial", + "violations": [] + }, + { + "width": 1440, + "language": "nb", + "mode": "light", + "state": "results", + "violations": [] + }, + { + "width": 1440, + "language": "nb", + "mode": "light", + "state": "saved", + "violations": [] + }, + { + "width": 1440, + "language": "nb", + "mode": "dark", + "state": "initial", + "violations": [] + }, + { + "width": 1440, + "language": "nb", + "mode": "dark", + "state": "results", + "violations": [] + }, + { + "width": 1440, + "language": "nb", + "mode": "dark", + "state": "saved", + "violations": [] + } + ], + "journeys": [ + { + "width": 320, + "language": "en", + "mode": "light", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 320, + "language": "en", + "mode": "dark", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 320, + "language": "nb", + "mode": "light", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 320, + "language": "nb", + "mode": "dark", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 390, + "language": "en", + "mode": "light", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 390, + "language": "en", + "mode": "dark", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 390, + "language": "nb", + "mode": "light", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 390, + "language": "nb", + "mode": "dark", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 768, + "language": "en", + "mode": "light", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 768, + "language": "en", + "mode": "dark", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 768, + "language": "nb", + "mode": "light", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 768, + "language": "nb", + "mode": "dark", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 1440, + "language": "en", + "mode": "light", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 1440, + "language": "en", + "mode": "dark", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 1440, + "language": "nb", + "mode": "light", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + }, + { + "width": 1440, + "language": "nb", + "mode": "dark", + "searchSavePauseRunDismissConfirmedDelete": "PASS" + } + ], + "errors": [], + "unexpectedWrites": [], + "mockedWrites": [ + { + "width": 320, + "language": "en", + "mode": "light", + "action": "create" + }, + { + "width": 320, + "language": "en", + "mode": "light", + "action": "pauseAlerts" + }, + { + "width": 320, + "language": "en", + "mode": "light", + "action": "manualRun" + }, + { + "width": 320, + "language": "en", + "mode": "light", + "action": "dismiss" + }, + { + "width": 320, + "language": "en", + "mode": "light", + "action": "confirmedDelete" + }, + { + "width": 320, + "language": "en", + "mode": "dark", + "action": "create" + }, + { + "width": 320, + "language": "en", + "mode": "dark", + "action": "pauseAlerts" + }, + { + "width": 320, + "language": "en", + "mode": "dark", + "action": "manualRun" + }, + { + "width": 320, + "language": "en", + "mode": "dark", + "action": "dismiss" + }, + { + "width": 320, + "language": "en", + "mode": "dark", + "action": "confirmedDelete" + }, + { + "width": 320, + "language": "nb", + "mode": "light", + "action": "create" + }, + { + "width": 320, + "language": "nb", + "mode": "light", + "action": "pauseAlerts" + }, + { + "width": 320, + "language": "nb", + "mode": "light", + "action": "manualRun" + }, + { + "width": 320, + "language": "nb", + "mode": "light", + "action": "dismiss" + }, + { + "width": 320, + "language": "nb", + "mode": "light", + "action": "confirmedDelete" + }, + { + "width": 320, + "language": "nb", + "mode": "dark", + "action": "create" + }, + { + "width": 320, + "language": "nb", + "mode": "dark", + "action": "pauseAlerts" + }, + { + "width": 320, + "language": "nb", + "mode": "dark", + "action": "manualRun" + }, + { + "width": 320, + "language": "nb", + "mode": "dark", + "action": "dismiss" + }, + { + "width": 320, + "language": "nb", + "mode": "dark", + "action": "confirmedDelete" + }, + { + "width": 390, + "language": "en", + "mode": "light", + "action": "create" + }, + { + "width": 390, + "language": "en", + "mode": "light", + "action": "pauseAlerts" + }, + { + "width": 390, + "language": "en", + "mode": "light", + "action": "manualRun" + }, + { + "width": 390, + "language": "en", + "mode": "light", + "action": "dismiss" + }, + { + "width": 390, + "language": "en", + "mode": "light", + "action": "confirmedDelete" + }, + { + "width": 390, + "language": "en", + "mode": "dark", + "action": "create" + }, + { + "width": 390, + "language": "en", + "mode": "dark", + "action": "pauseAlerts" + }, + { + "width": 390, + "language": "en", + "mode": "dark", + "action": "manualRun" + }, + { + "width": 390, + "language": "en", + "mode": "dark", + "action": "dismiss" + }, + { + "width": 390, + "language": "en", + "mode": "dark", + "action": "confirmedDelete" + }, + { + "width": 390, + "language": "nb", + "mode": "light", + "action": "create" + }, + { + "width": 390, + "language": "nb", + "mode": "light", + "action": "pauseAlerts" + }, + { + "width": 390, + "language": "nb", + "mode": "light", + "action": "manualRun" + }, + { + "width": 390, + "language": "nb", + "mode": "light", + "action": "dismiss" + }, + { + "width": 390, + "language": "nb", + "mode": "light", + "action": "confirmedDelete" + }, + { + "width": 390, + "language": "nb", + "mode": "dark", + "action": "create" + }, + { + "width": 390, + "language": "nb", + "mode": "dark", + "action": "pauseAlerts" + }, + { + "width": 390, + "language": "nb", + "mode": "dark", + "action": "manualRun" + }, + { + "width": 390, + "language": "nb", + "mode": "dark", + "action": "dismiss" + }, + { + "width": 390, + "language": "nb", + "mode": "dark", + "action": "confirmedDelete" + }, + { + "width": 768, + "language": "en", + "mode": "light", + "action": "create" + }, + { + "width": 768, + "language": "en", + "mode": "light", + "action": "pauseAlerts" + }, + { + "width": 768, + "language": "en", + "mode": "light", + "action": "manualRun" + }, + { + "width": 768, + "language": "en", + "mode": "light", + "action": "dismiss" + }, + { + "width": 768, + "language": "en", + "mode": "light", + "action": "confirmedDelete" + }, + { + "width": 768, + "language": "en", + "mode": "dark", + "action": "create" + }, + { + "width": 768, + "language": "en", + "mode": "dark", + "action": "pauseAlerts" + }, + { + "width": 768, + "language": "en", + "mode": "dark", + "action": "manualRun" + }, + { + "width": 768, + "language": "en", + "mode": "dark", + "action": "dismiss" + }, + { + "width": 768, + "language": "en", + "mode": "dark", + "action": "confirmedDelete" + }, + { + "width": 768, + "language": "nb", + "mode": "light", + "action": "create" + }, + { + "width": 768, + "language": "nb", + "mode": "light", + "action": "pauseAlerts" + }, + { + "width": 768, + "language": "nb", + "mode": "light", + "action": "manualRun" + }, + { + "width": 768, + "language": "nb", + "mode": "light", + "action": "dismiss" + }, + { + "width": 768, + "language": "nb", + "mode": "light", + "action": "confirmedDelete" + }, + { + "width": 768, + "language": "nb", + "mode": "dark", + "action": "create" + }, + { + "width": 768, + "language": "nb", + "mode": "dark", + "action": "pauseAlerts" + }, + { + "width": 768, + "language": "nb", + "mode": "dark", + "action": "manualRun" + }, + { + "width": 768, + "language": "nb", + "mode": "dark", + "action": "dismiss" + }, + { + "width": 768, + "language": "nb", + "mode": "dark", + "action": "confirmedDelete" + }, + { + "width": 1440, + "language": "en", + "mode": "light", + "action": "create" + }, + { + "width": 1440, + "language": "en", + "mode": "light", + "action": "pauseAlerts" + }, + { + "width": 1440, + "language": "en", + "mode": "light", + "action": "manualRun" + }, + { + "width": 1440, + "language": "en", + "mode": "light", + "action": "dismiss" + }, + { + "width": 1440, + "language": "en", + "mode": "light", + "action": "confirmedDelete" + }, + { + "width": 1440, + "language": "en", + "mode": "dark", + "action": "create" + }, + { + "width": 1440, + "language": "en", + "mode": "dark", + "action": "pauseAlerts" + }, + { + "width": 1440, + "language": "en", + "mode": "dark", + "action": "manualRun" + }, + { + "width": 1440, + "language": "en", + "mode": "dark", + "action": "dismiss" + }, + { + "width": 1440, + "language": "en", + "mode": "dark", + "action": "confirmedDelete" + }, + { + "width": 1440, + "language": "nb", + "mode": "light", + "action": "create" + }, + { + "width": 1440, + "language": "nb", + "mode": "light", + "action": "pauseAlerts" + }, + { + "width": 1440, + "language": "nb", + "mode": "light", + "action": "manualRun" + }, + { + "width": 1440, + "language": "nb", + "mode": "light", + "action": "dismiss" + }, + { + "width": 1440, + "language": "nb", + "mode": "light", + "action": "confirmedDelete" + }, + { + "width": 1440, + "language": "nb", + "mode": "dark", + "action": "create" + }, + { + "width": 1440, + "language": "nb", + "mode": "dark", + "action": "pauseAlerts" + }, + { + "width": 1440, + "language": "nb", + "mode": "dark", + "action": "manualRun" + }, + { + "width": 1440, + "language": "nb", + "mode": "dark", + "action": "dismiss" + }, + { + "width": 1440, + "language": "nb", + "mode": "dark", + "action": "confirmedDelete" + } + ], + "blockedExternal": [ + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com", + "https://fonts.googleapis.com" + ], + "limits": [ + "synthetic provider/API fixtures, not live NAV or backend qualification", + "no new providers/geography or native/security/release acceptance" + ] +} \ No newline at end of file diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-1440.png b/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-1440.png new file mode 100644 index 00000000..ba959468 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-320.png b/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-320.png new file mode 100644 index 00000000..f724f929 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-390.png b/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-390.png new file mode 100644 index 00000000..6a1424ec Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-768.png b/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-768.png new file mode 100644 index 00000000..5d863983 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-en-dark-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-1440.png b/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-1440.png new file mode 100644 index 00000000..ed2531a6 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-320.png b/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-320.png new file mode 100644 index 00000000..7e51a51a Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-390.png b/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-390.png new file mode 100644 index 00000000..71dc3fe8 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-768.png b/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-768.png new file mode 100644 index 00000000..bcb49fbc Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-en-light-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-1440.png b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-1440.png new file mode 100644 index 00000000..be48ff83 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-320.png b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-320.png new file mode 100644 index 00000000..79214664 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-390.png b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-390.png new file mode 100644 index 00000000..0435c8d1 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-768.png b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-768.png new file mode 100644 index 00000000..a2b43b4d Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-dark-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-1440.png b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-1440.png new file mode 100644 index 00000000..0d3001f5 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-320.png b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-320.png new file mode 100644 index 00000000..3abb25ef Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-390.png b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-390.png new file mode 100644 index 00000000..9773a59f Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-768.png b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-768.png new file mode 100644 index 00000000..f1f48bcf Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/initial-nb-light-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-1440.png b/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-1440.png new file mode 100644 index 00000000..39fc4705 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-320.png b/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-320.png new file mode 100644 index 00000000..c4fc7001 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-390.png b/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-390.png new file mode 100644 index 00000000..6c2ffc75 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-768.png b/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-768.png new file mode 100644 index 00000000..20d9b036 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-en-dark-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-en-light-1440.png b/docs/ui-modernisation/evidence/discovery/browser/results-en-light-1440.png new file mode 100644 index 00000000..3861b69d Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-en-light-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-en-light-320.png b/docs/ui-modernisation/evidence/discovery/browser/results-en-light-320.png new file mode 100644 index 00000000..a0cbe5d0 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-en-light-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-en-light-390.png b/docs/ui-modernisation/evidence/discovery/browser/results-en-light-390.png new file mode 100644 index 00000000..dcb6527a Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-en-light-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-en-light-768.png b/docs/ui-modernisation/evidence/discovery/browser/results-en-light-768.png new file mode 100644 index 00000000..8f42c445 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-en-light-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-1440.png b/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-1440.png new file mode 100644 index 00000000..52b9e963 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-320.png b/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-320.png new file mode 100644 index 00000000..ce5f990e Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-390.png b/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-390.png new file mode 100644 index 00000000..5288ea2e Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-768.png b/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-768.png new file mode 100644 index 00000000..15192278 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-nb-dark-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-1440.png b/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-1440.png new file mode 100644 index 00000000..a7d91eaf Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-320.png b/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-320.png new file mode 100644 index 00000000..203c1335 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-390.png b/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-390.png new file mode 100644 index 00000000..e886ea47 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-768.png b/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-768.png new file mode 100644 index 00000000..551b2f6f Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/results-nb-light-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-1440.png b/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-1440.png new file mode 100644 index 00000000..4ee95f67 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-320.png b/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-320.png new file mode 100644 index 00000000..d20b8eb6 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-390.png b/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-390.png new file mode 100644 index 00000000..69a4a55e Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-768.png b/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-768.png new file mode 100644 index 00000000..89a6d7ce Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-en-dark-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-1440.png b/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-1440.png new file mode 100644 index 00000000..03a8caa1 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-320.png b/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-320.png new file mode 100644 index 00000000..14ce8ef7 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-390.png b/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-390.png new file mode 100644 index 00000000..228dea94 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-768.png b/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-768.png new file mode 100644 index 00000000..20f4da0c Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-en-light-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-1440.png b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-1440.png new file mode 100644 index 00000000..bb8ea5ad Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-320.png b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-320.png new file mode 100644 index 00000000..9f04211f Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-390.png b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-390.png new file mode 100644 index 00000000..5cde6955 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-768.png b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-768.png new file mode 100644 index 00000000..bb9fcf21 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-dark-768.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-1440.png b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-1440.png new file mode 100644 index 00000000..a87a16ad Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-1440.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-320.png b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-320.png new file mode 100644 index 00000000..36d9b41c Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-320.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-390.png b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-390.png new file mode 100644 index 00000000..68f3ef4a Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-390.png differ diff --git a/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-768.png b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-768.png new file mode 100644 index 00000000..894b3391 Binary files /dev/null and b/docs/ui-modernisation/evidence/discovery/browser/saved-nb-light-768.png differ diff --git a/job-tracker-ui/scripts/verify-a3-discovery.mjs b/job-tracker-ui/scripts/verify-a3-discovery.mjs new file mode 100644 index 00000000..f578ed31 --- /dev/null +++ b/job-tracker-ui/scripts/verify-a3-discovery.mjs @@ -0,0 +1,94 @@ +// Built React with synthetic NAV-shaped fixtures; no provider or backend access. +import { chromium, expect } from '@playwright/test'; +import AxeBuilder from '@axe-core/playwright'; +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import path from 'node:path'; +const out = path.resolve(import.meta.dirname, '../../docs/ui-modernisation/evidence/discovery/browser'); +fs.mkdirSync(out, { recursive: true }); +const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], mockedWrites: [], blockedExternal: [] }; +const browser = await chromium.launch(); +try { + for (const width of [320, 390, 768, 1440]) for (const language of ['en', 'nb']) for (const mode of ['light', 'dark']) { + const context = await browser.newContext({ viewport: { width, height: 1000 }, reducedMotion: 'reduce' }); + const page = await context.newPage(); page.on('pageerror', error => report.errors.push(error.message)); + await page.addInitScript(({ language, mode }) => { localStorage.setItem('uiLanguage', language); localStorage.setItem('jobtracker.themeMode', mode); }, { language, mode }); + const jobs = ['Community nurse', 'Primary teacher', 'Electrical engineer'].map((title, index) => ({ id: `vacancy-${index}`, title, company: 'Synthetic employer', location: 'Oslo', modifiedAt: '2026-11-02T10:00:00Z', deadline: '2026-11-12T12:00:00Z', url: `https://example.test/vacancy-${index}`, source: 'nav', sourceName: 'NAV Arbeidsplassen', acquisitionType: 'searched', retrievedAt: '2026-11-03T10:00:00Z', countryCode: 'NO' })); + let saved = null, searches = 0; + await page.route('**/*', route => { + const req = route.request(), url = new URL(req.url()); + if (!['localhost', '127.0.0.1'].includes(url.hostname)) { report.blockedExternal.push(url.origin); return route.abort(); } + if (!url.pathname.startsWith('/api/')) return route.continue(); + const answer = data => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(data) }); + const note = action => report.mockedWrites.push({ width, language, mode, action }); + if (req.method() === 'POST' && url.pathname === '/api/job-discovery/saved-searches') { + const data = req.postDataJSON(); assert.deepEqual(data, { name: 'Care roles', query: 'nurse', location: 'Oslo' }); + saved = { ...data, id: 7, isActive: true, resultCount: 0, dismissedCount: 0 }; note('create'); return answer(saved); + } + if (req.method() === 'PATCH' && url.pathname === '/api/job-discovery/saved-searches/7') { + assert.deepEqual(req.postDataJSON(), { isActive: false }); saved.isActive = false; note('pauseAlerts'); return answer(saved); + } + if (req.method() === 'POST' && url.pathname === '/api/job-discovery/saved-searches/7/run') { + saved.resultCount = 1; note('manualRun'); return answer({ search: saved, jobs: [{ job: jobs[0], isNew: true, isDismissed: false }] }); + } + if (req.method() === 'PATCH' && url.pathname === '/api/job-discovery/saved-searches/7/results/vacancy-0/dismiss') { + assert.deepEqual(req.postDataJSON(), { isDismissed: true }); note('dismiss'); return answer({}); + } + if (req.method() === 'DELETE' && url.pathname === '/api/job-discovery/saved-searches/7') { saved = null; note('confirmedDelete'); return answer({}); } + if (req.method() !== 'GET') { report.unexpectedWrites.push(url.pathname); return route.abort(); } + if (url.pathname === '/api/job-discovery/saved-searches') return answer(saved ? [saved] : []); + if (url.pathname === '/api/job-discovery/search') { searches++; return answer(jobs.filter(job => !url.searchParams.get('q') || job.title.toLowerCase().includes(url.searchParams.get('q').toLowerCase()))); } + const fixtures = { + '/api/auth/config': { requireAuth: true }, + '/api/auth/me': { id: 'a3-discovery-owner', sessionContext: 'a3-discovery-session', firstName: 'Alex', displayName: 'Alex Sample', roles: [], uiLanguage: language === 'nb' ? 'nb-NO' : 'en' }, + '/api/jobapplications/reminders': [], '/api/notifications/unread-count': { count: 0 }, + }; + return route.fulfill({ status: Object.hasOwn(fixtures, url.pathname) ? 200 : 404, contentType: 'application/json', body: JSON.stringify(fixtures[url.pathname] ?? {}) }); + }); + const scan = async state => { + assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth + 1), false); + const result = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']).analyze(); + report.screens.push({ width, language, mode, state, violations: result.violations }); assert.deepEqual(result.violations, []); + await page.evaluate(() => window.scrollTo(0, 0)); + await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: true }); + }; + await page.goto('http://localhost:4338/discover'); + const filters = page.getByRole('complementary', { name: language === 'en' ? 'Search filters' : 'Søkefiltre' }); await filters.waitFor(); + const results = page.getByRole('region', { name: language === 'en' ? 'Search results' : 'Søkeresultater', exact: true }); await results.waitFor(); + const role = page.getByRole('textbox', { name: language === 'en' ? 'Role or company' : 'Rolle eller bedrift', exact: true }); + await filters.getByRole('button', { name: language === 'en' ? 'Jump to results' : 'Gå til resultater', exact: true }).click(); + assert.equal(await results.evaluate(node => node === document.activeElement), true); + await results.getByRole('button', { name: language === 'en' ? 'Return to search filters' : 'Tilbake til søkefiltre', exact: true }).click(); + assert.equal(await role.evaluate(node => node === document.activeElement), true); assert.equal(searches, 0); + const left = await filters.boundingBox(), right = await results.boundingBox(); + assert.ok(width > 1000 ? right.x > left.x + left.width - 2 && Math.abs(right.y - left.y) < 2 : right.y >= left.y + left.height - 2); + await scan('initial'); + const search = page.getByRole('button', { name: language === 'en' ? 'Search NAV' : 'Søk i NAV', exact: true }); + await search.click(); await results.getByRole('article', { name: 'Electrical engineer', exact: true }).waitFor(); + assert.equal(await results.getByRole('article').count(), 3); await scan('results'); + await role.fill('nurse'); await page.getByRole('textbox', { name: language === 'en' ? 'Municipality' : 'Kommune', exact: true }).fill('Oslo'); + await page.getByRole('textbox', { name: language === 'en' ? 'Search name' : 'Navn på søket', exact: true }).fill('Care roles'); + await page.getByRole('button', { name: language === 'en' ? 'Save search' : 'Lagre søk', exact: true }).click(); + const group = page.getByRole('group', { name: 'Care roles', exact: true }); await group.waitFor(); + const alerts = group.getByRole('switch', { name: language === 'en' ? 'Automatic alerts' : 'Automatiske varsler', exact: true }); + await alerts.click(); await expect(alerts).not.toBeChecked(); + await group.getByRole('button', { name: language === 'en' ? 'Check for new jobs' : 'Se etter nye stillinger', exact: true }).click(); + await results.getByRole('article', { name: 'Community nurse', exact: true }).waitFor(); + assert.equal(await results.getByRole('article').count(), 1); await scan('saved'); + assert.equal(await results.getByRole('link', { name: language === 'en' ? 'View listing' : 'Vis stilling', exact: true }).getAttribute('href'), jobs[0].url); + await results.getByRole('button', { name: language === 'en' ? 'Dismiss' : 'Avvis', exact: true }).click(); + await results.getByRole('article').waitFor({ state: 'hidden' }); + await group.getByRole('button', { name: language === 'en' ? 'Delete' : 'Slett', exact: true }).click(); + const dialog = page.getByRole('dialog', { name: language === 'en' ? 'Delete saved search?' : 'Slette lagret søk?', exact: true }); + await dialog.getByRole('button', { name: language === 'en' ? 'Delete' : 'Slett', exact: true }).click(); await group.waitFor({ state: 'hidden' }); + report.journeys.push({ width, language, mode, searchSavePauseRunDismissConfirmedDelete: 'PASS' }); + await context.close(); + } + assert.equal(report.screens.length, 48); assert.equal(report.journeys.length, 16); assert.equal(report.mockedWrites.length, 80); + assert.deepEqual(report.errors, []); assert.deepEqual(report.unexpectedWrites, []); + assert.ok(report.blockedExternal.every(origin => origin === 'https://fonts.googleapis.com')); + console.log('PASS:16 controlled discovery journeys,48 axe scans/captures,80 intercepted fixture mutations.'); +} finally { + fs.writeFileSync(path.join(out, 'BROWSER.json'), JSON.stringify({ ...report, limits: ['synthetic provider/API fixtures, not live NAV or backend qualification', 'no new providers/geography or native/security/release acceptance'] }, null, 2)); + await browser.close(); +} diff --git a/job-tracker-ui/src/i18n/translations.ts b/job-tracker-ui/src/i18n/translations.ts index 0b540e1f..dad96e1e 100644 --- a/job-tracker-ui/src/i18n/translations.ts +++ b/job-tracker-ui/src/i18n/translations.ts @@ -593,6 +593,9 @@ export const translations = { landingReadyBody: "Sign in to start tracking applications, tailoring CVs, and following up with intent.", landingFooter: "© {year} Jobbjakt — a focused workspace for the modern job search.", jobDiscoveryRoleCompany: "Role or company", + jobDiscoveryFilters: "Search filters", + jobDiscoveryJumpResults: "Jump to results", + jobDiscoveryReturnFilters: "Return to search filters", jobDiscoveryMunicipality: "Municipality", jobDiscoverySearchNav: "Search NAV", jobDiscoveryResults: "Search results", @@ -3748,6 +3751,9 @@ export const translations = { landingReadyBody: "Logg inn for å følge søknader, tilpasse CV-er og jobbe målrettet med oppfølging.", landingFooter: "© {year} Jobbjakt — et fokusert arbeidsområde for moderne jobbsøk.", jobDiscoveryRoleCompany: "Rolle eller bedrift", + jobDiscoveryFilters: "Søkefiltre", + jobDiscoveryJumpResults: "Gå til resultater", + jobDiscoveryReturnFilters: "Tilbake til søkefiltre", jobDiscoveryMunicipality: "Kommune", jobDiscoverySearchNav: "Søk i NAV", jobDiscoveryResults: "Søkeresultater", diff --git a/job-tracker-ui/src/job-discovery.test.tsx b/job-tracker-ui/src/job-discovery.test.tsx index 39717b96..fc4d385d 100644 --- a/job-tracker-ui/src/job-discovery.test.tsx +++ b/job-tracker-ui/src/job-discovery.test.tsx @@ -7,6 +7,7 @@ import { ConfirmProvider } from "./confirm"; import { PromptProvider } from "./prompt"; import { I18nProvider } from "./i18n/I18nProvider"; import JobDiscoveryPage from "./views/JobDiscoveryPage"; +import { translations } from './i18n/translations'; jest.mock("./api", () => ({ api: { get: jest.fn(), post: jest.fn(), patch: jest.fn(), delete: jest.fn() } })); const mockedApi = api as jest.Mocked; @@ -22,6 +23,25 @@ function searchResponse(data: any[]) { beforeEach(() => { jest.resetAllMocks(); window.localStorage.clear(); searchResponse([]); }); afterEach(() => jest.clearAllMocks()); +test.each([ + ['en', 'Search filters', 'Jump to results', 'Return to search filters'], + ['nb', 'Søkefiltre', 'Gå til resultater', 'Tilbake til søkefiltre'], +] as const)('keeps %s filters before results with keyboard jump/return and no automatic provider search', async (language, filtersName, jumpName, returnName) => { + localStorage.setItem('uiLanguage', language); + renderPage(); + await screen.findByText(translations[language].jobDiscoveryNoSavedSearches); + const filters = screen.getByRole('complementary', { name: filtersName }); + const results = screen.getByRole('region', { name: translations[language].jobDiscoveryResults }); + expect(filters.compareDocumentPosition(results) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy(); + expect(within(filters).getByRole('form', { name: filtersName })).toBeInTheDocument(); + fireEvent.click(within(filters).getByRole('button', { name: jumpName })); + expect(results).toHaveFocus(); + fireEvent.click(within(results).getByRole('button', { name: returnName })); + expect(screen.getByRole('textbox', { name: translations[language].jobDiscoveryRoleCompany })).toHaveFocus(); + expect(mockedApi.get.mock.calls.map(([url]) => url)).toEqual(['/job-discovery/saved-searches']); + expect(mockedApi.post).not.toHaveBeenCalled(); +}); + test("shows honest source metadata and offers the existing reviewed save flow", async () => { searchResponse([{ id: "abc", title: "Backend Developer", company: "Acme", location: "OSLO", modifiedAt: "2026-08-01T10:00:00Z", deadline: "2026-08-15T23:59:59Z", url: "https://arbeidsplassen.nav.no/stillinger/stilling/abc", source: "nav", sourceName: "NAV Arbeidsplassen", acquisitionType: "searched", retrievedAt: "2026-08-10T10:00:00Z", countryCode: "NO" }]); renderPage(); diff --git a/job-tracker-ui/src/views/JobDiscoveryPage.tsx b/job-tracker-ui/src/views/JobDiscoveryPage.tsx index 2d7c780e..3ea8c454 100644 --- a/job-tracker-ui/src/views/JobDiscoveryPage.tsx +++ b/job-tracker-ui/src/views/JobDiscoveryPage.tsx @@ -56,6 +56,7 @@ export default function JobDiscoveryPage() { const [mutating, setMutating] = useState(false); const pending = useRef(false); const resultsRef = useRef(null); + const queryRef = useRef(null); const removedControlRef = useRef(null); const busy = loading || savingSearch || updatingSavedSearchId !== null || mutating; @@ -182,8 +183,12 @@ export default function JobDiscoveryPage() { return ( - - setQuery(event.target.value)} /> + {t("jobDiscoverySourceHelp")} + + + resultsRef.current?.focus()}>{t("jobDiscoveryJumpResults")}} /> + + setQuery(event.target.value)} /> setLocation(event.target.value)} /> @@ -223,9 +228,9 @@ export default function JobDiscoveryPage() { )} - {t("jobDiscoverySourceHelp")} + - {hasSearched ? : null} + queryRef.current?.focus()}>{t("jobDiscoveryReturnFilters")}} /> { @@ -245,7 +250,7 @@ export default function JobDiscoveryPage() { ) : null} - + {sortedJobs.map((job) => ( @@ -274,6 +279,7 @@ export default function JobDiscoveryPage() { ))} + ); }