test(ui): qualify profile selection to CV download workflow
@@ -1,5 +1,7 @@
|
||||
# A3-IM10 Cross-application qualification
|
||||
|
||||
4 November Profile→CV creation/edit/preview/download client journey on unchanged **9bfc51b067c4da4164b84578f5dacf452125ba62**:8 representative390/1440×EN/NB×theme journeys/40 states PASSED,16 intercepted creates/renames and8 revision-checked export/download events. No unexpected writes/errors/axe violations;8 company and8 template-preview reads unavailable. Selected contact/summary inheritance request and unchanged settings at rename checked; backend Profile rendering/physical PDF NOT RUN. Synthetic download bytes explicitly are not a PDF. See visual-correction/CV_JOURNEY_REVIEW.md. Matching-count receipt **8fef819c4e5a17eee65c8707d014155dea8a6322** published/readback-verified with1,256 integrity checks. Remaining application→follow-up/import/error/native/owner/security/recovery/release gates stay OPEN.
|
||||
|
||||
4 November matching-count source **9bfc51b067c4da4164b84578f5dacf452125ba62**:48 selected native cases/four suites, types/full lint/export build and36 configurations/72 table/board states PASSED,zero writes/unavailable reads/page errors/axe violations. V22 singular text resolved in EN/NB, no new dynamic translation call; existing locale-triggered active-view reload preserved. See visual-correction/MATCHING_COUNT_REVIEW.md for retained RED/path failures and exact superseded counts. Viewer24 families/864 actual bindings/28 frozen references;48 artifact selections passed separately. Discovery receipt **ed4ce4cc3a0fffecfa406793a60680e490fa6674** published and independently verified after one ordinary retry of a remote unpack checksum rejection;1,287 integrity checks matched. No infrastructure change. Remaining IM10/route/workflow/owner/native/European/security/recovery/release gates remain OPEN.
|
||||
|
||||
4 November discovery→preview→review→tracker qualification on unchanged runtime **a84a97cb61eda975d73690c818d56666f0929515**:36 connected journeys/144 rendered states PASSED;36 intercepted previews and36 creates, original source fields checked, no unexpected writes/unavailable reads/errors/axe violations. No actual provider/backend or attachment/AI execution. Existing wizard controls retained. Count grammar V22 found and remains open for the next bounded fix. Comparison viewer22 families/792 actual bindings/28 frozen references;44 artifact selections passed separately. Evidence Bank receipt **b5b9069d1e835197cc37c5e7e293c3a60857ec2f** is published/readback-verified with1,321 integrity checks. Other connected journeys and all final roadmap/native/owner/security/recovery/release gates remain OPEN.
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
"docs/ui-modernisation/visual-correction/evidence/reference/approved-settings-390.png": "be4fe05cc4bf5e8f51ed1cae04af1835c30ea4026a9722c5f7b168390bfaa632",
|
||||
"docs/ui-modernisation/visual-correction/evidence/reference/approved-settings-1440.png": "76a1c71396b8bb4920859779195369660cba187f21d300dec2b9dbd18c905568",
|
||||
"docs/ui-modernisation/visual-correction/evidence/reference/approved-automation-390.png": "9d7c2c573397b7edd57d1246a150beb132fe0b96b4e105c426d9034369e346a8",
|
||||
"docs/ui-modernisation/visual-correction/evidence/reference/approved-automation-1440.png": "5b08bf976ab212dfe1446669f24fda7c1222c0d217f2822852e467fe4aa3a3dc"
|
||||
"docs/ui-modernisation/visual-correction/evidence/reference/approved-automation-1440.png": "5b08bf976ab212dfe1446669f24fda7c1222c0d217f2822852e467fe4aa3a3dc",
|
||||
"docs/ui-modernisation/visual-correction/evidence/reference/approved-cv-390.png": "d0235b28b846f2cdc5a3687c60a56cad08c419d65657f4e70bf4c0f886bd75a3",
|
||||
"docs/ui-modernisation/visual-correction/evidence/reference/approved-cv-1440.png": "396290ac3c626e09db4c18013c096e2ddadb98a6d422c59a69118483f74f7ce6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Profile selection to CV download: controlled client journey
|
||||
|
||||
4 November 2026. Runtime `9bfc51b067c4da4164b84578f5dacf452125ba62`, after published matching-count receipt8fef819c. No application source or build changed; use the previously sealed source/export. This is a representative connected workflow check at390/1440×EN/NB×light/dark, not another nine-width visual matrix or physical renderer qualification.
|
||||
|
||||
PASSED:8 controlled journeys/40 axe scans and screenshots. Empty library→New CV→select existing Profile contact and summary→create→editor rename/autosave→live preview→download. Create explicitly sends `includeProfileContact:true`, `sectionsExplicit:true` and the selected summary reference. Rename sends the returned version and identical settings, preserving inherited/null settings instead of copying or replacing canonical Profile data. Export sends the saved version2; client download filename reflects the saved name and its bytes match the transport fixture.
|
||||
|
||||
Exactly16 fixture persistence requests (eight creates/eight renames), eight revision-checked export requests and eight download events; no unexpected writes, page exceptions or axe violations. Preview responses are synthetic HTML; the displayed name is checked against the fixture Profile. Profile-to-content rendering and PDF output are backend responsibilities and are not established by this mock. Download transport bytes explicitly say they are not a rendered PDF; no PDF file, typography/page metric or semantic-quality acceptance is claimed. Existing accepted physical PDF evidence is unchanged and not rerun.
|
||||
|
||||
The initial pilot changed the identically labelled name field while the creation dialog was still replacing itself with the editor: URL change alone was insufficient synchronisation. Its failed receipt is retained. The corrected verifier waits for dialog removal and the actual editor region before editing, then checks persistence. No application code was changed to accommodate the verifier. The overlapping two-config/ten-state pilot is not added to the final8/40 count.
|
||||
|
||||
Unavailable fixture reads:companies8 and template-modern-preview8. Template/service qualification therefore remains open. No import engine, model, provider, actual account/database, public sharing or delete action executed. Previous native CV/preservation evidence is reused where relevant component/test/dependencies are unchanged; no fresh native suite or build is claimed for this verifier-only package. Scoped verifier lint passed. Source integrity binds the current app and harness separately.
|
||||
|
||||
Screenshots: [phone editor](evidence/cv-journey/edited-en-light-390.png), [phone preview](evidence/cv-journey/preview-en-light-390.png), [desktop editor in Bokmål/dark](evidence/cv-journey/edited-nb-dark-1440.png), [desktop preview](evidence/cv-journey/preview-nb-dark-1440.png). Exact frozen A3 references: [phone](evidence/reference/approved-cv-390.png), [desktop](evidence/reference/approved-cv-1440.png). Compare editor-left/preview-right, navigation, spacing and controls; content and workshop chrome differ.
|
||||
|
||||
Remaining: legacy import acceptance→edit/export, conflict/failure/retry/restore, all template services, actual canonical rendering/physical PDF, human/native/device and final owner visual review. Application status→follow-up scheduling is the next independent connected journey. Phase10/full IM10/European localisation/integrated security/recovery/release acceptance remain OPEN.
|
||||
@@ -30,6 +30,7 @@ Owner correction: 3 November 2026. This register extends IM10 and the original 3
|
||||
| V20 | Shared feedback | ToastProvider outside the application theme produced failing information-toast contrast3.85:1 | Fixed provider order in a84a97cb;70 native cases and36 configurations/252 Settings states passed, toast visible during contrast analysis | Other feedback/workflow and human/native acceptance remain separate; failed scan retained |
|
||||
| V21 | Administration hierarchy | Repeated generic route/page headings remain after opening section surfaces | OPEN minor visual discrepancy from rendered review | Review current route heading ownership and focus/test contracts before removing repetition |
|
||||
| V22 | Application localisation | One result renders `1 matching jobs` / `1 jobber samsvarer` | RESOLVED in9bfc51b0:48 native cases and36 configurations/72 focused table/board count states passed,zero writes | Existing active-view locale reload/loading/error suppression retained; owner/native/European acceptance separate |
|
||||
| V23 | CV localisation | One section item renders `1 entries` / `1 oppføringer`; one-page Bokmål caption uses `1 sider` | OPEN reproduced in connected CV screenshot and confirmed at section-entry/page-count callers | Add paired singular labels with0/1/2/current-locale regression; preserve document content, UI/output-language ownership, paging and revision behavior |
|
||||
|
||||
The owner-approved design foundation remains original A1 dashboard, D1 visual system, B1 tracking, editor left / preview right, application context right, desktop sidebar and hybrid mobile navigation. No controls, imports, revisions, permissions or provider rights may be removed to obtain visual simplicity.
|
||||
|
||||
|
||||
@@ -188,9 +188,9 @@
|
||||
"CvBuilderPage"
|
||||
],
|
||||
"visualStatus": "OPEN_SURFACES_SCOPED_REVIEW_FULL_ACCEPTANCE_OPEN",
|
||||
"afterStatus": "PASSED:36 configurations /216 Career-family states;14 keyboard edit targets; synthetic revisions/import selection only; unavailable services disclosed",
|
||||
"afterStatus": "PASSED:36 configurations /216 Career-family states;14 keyboard edit targets; synthetic revisions/import selection only; unavailable services disclosed; representative source-selection/create/edit/preview/download transport8/40 passed; physical PDF/backend/template services NOT RUN",
|
||||
"functionalCriteria": "Original preservation register retained; no capability acceptance promotion",
|
||||
"evidence": "evidence/career/BROWSER.json; CAREER_DOCUMENT_ACTIVITY.md"
|
||||
"evidence": "evidence/career/BROWSER.json; CAREER_DOCUMENT_ACTIVITY.md; CV_JOURNEY_REVIEW.md; evidence/cv-journey/BROWSER.json"
|
||||
},
|
||||
{
|
||||
"route": "/career/builder/:id",
|
||||
@@ -198,8 +198,8 @@
|
||||
"CvBuilderEditor"
|
||||
],
|
||||
"visualStatus": "OPEN_SURFACES_SCOPED_REVIEW_FULL_ACCEPTANCE_OPEN",
|
||||
"afterStatus": "PASSED:36 configurations /216 Career-family states;14 keyboard edit targets; synthetic revisions/import selection only; unavailable services disclosed",
|
||||
"evidence": "evidence/career/BROWSER.json; CAREER_DOCUMENT_ACTIVITY.md",
|
||||
"afterStatus": "PASSED:36 configurations /216 Career-family states;14 keyboard edit targets; synthetic revisions/import selection only; unavailable services disclosed; representative source-selection/create/edit/preview/download transport8/40 passed; physical PDF/backend/template services NOT RUN",
|
||||
"evidence": "evidence/career/BROWSER.json; CAREER_DOCUMENT_ACTIVITY.md; CV_JOURNEY_REVIEW.md; evidence/cv-journey/BROWSER.json",
|
||||
"functionalCriteria": "Original preservation register retained; no capability acceptance promotion"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,648 @@
|
||||
{
|
||||
"screens": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "library",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "edited",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "preview",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "download",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"state": "library",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"state": "edited",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"state": "preview",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"state": "download",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"state": "library",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"state": "edited",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"state": "preview",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"state": "download",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"state": "library",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"state": "edited",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"state": "preview",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"state": "download",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "library",
|
||||
"capture": "full page at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "edited",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "preview",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "download",
|
||||
"capture": "full page at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"state": "library",
|
||||
"capture": "full page at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"state": "edited",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"state": "preview",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"state": "download",
|
||||
"capture": "full page at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"state": "library",
|
||||
"capture": "full page at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"state": "edited",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"state": "preview",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"state": "download",
|
||||
"capture": "full page at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"state": "library",
|
||||
"capture": "full page at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"state": "edited",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"state": "preview",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"state": "download",
|
||||
"capture": "full page at top",
|
||||
"violations": []
|
||||
}
|
||||
],
|
||||
"journeys": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"selectedProfileInheritance": "PASS",
|
||||
"createEditPreviewDownloadTransport": "PASS",
|
||||
"exportUsesSavedRevision": "PASS",
|
||||
"importAndPhysicalPdf": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"selectedProfileInheritance": "PASS",
|
||||
"createEditPreviewDownloadTransport": "PASS",
|
||||
"exportUsesSavedRevision": "PASS",
|
||||
"importAndPhysicalPdf": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"selectedProfileInheritance": "PASS",
|
||||
"createEditPreviewDownloadTransport": "PASS",
|
||||
"exportUsesSavedRevision": "PASS",
|
||||
"importAndPhysicalPdf": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"selectedProfileInheritance": "PASS",
|
||||
"createEditPreviewDownloadTransport": "PASS",
|
||||
"exportUsesSavedRevision": "PASS",
|
||||
"importAndPhysicalPdf": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"selectedProfileInheritance": "PASS",
|
||||
"createEditPreviewDownloadTransport": "PASS",
|
||||
"exportUsesSavedRevision": "PASS",
|
||||
"importAndPhysicalPdf": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"selectedProfileInheritance": "PASS",
|
||||
"createEditPreviewDownloadTransport": "PASS",
|
||||
"exportUsesSavedRevision": "PASS",
|
||||
"importAndPhysicalPdf": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"selectedProfileInheritance": "PASS",
|
||||
"createEditPreviewDownloadTransport": "PASS",
|
||||
"exportUsesSavedRevision": "PASS",
|
||||
"importAndPhysicalPdf": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"selectedProfileInheritance": "PASS",
|
||||
"createEditPreviewDownloadTransport": "PASS",
|
||||
"exportUsesSavedRevision": "PASS",
|
||||
"importAndPhysicalPdf": "NOT RUN"
|
||||
}
|
||||
],
|
||||
"errors": [],
|
||||
"unexpectedWrites": [],
|
||||
"mockedWrites": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"action": "createVariantFromProfile"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"action": "variantRename"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"action": "createVariantFromProfile"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"action": "variantRename"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"action": "createVariantFromProfile"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"action": "variantRename"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"action": "createVariantFromProfile"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"action": "variantRename"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"action": "createVariantFromProfile"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"action": "variantRename"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"action": "createVariantFromProfile"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"action": "variantRename"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"action": "createVariantFromProfile"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"action": "variantRename"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"action": "createVariantFromProfile"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"action": "variantRename"
|
||||
}
|
||||
],
|
||||
"exportRequests": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"expectedVersion": 2
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"expectedVersion": 2
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"expectedVersion": 2
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"expectedVersion": 2
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"expectedVersion": 2
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"expectedVersion": 2
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"expectedVersion": 2
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"expectedVersion": 2
|
||||
}
|
||||
],
|
||||
"downloads": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"filename": "Reviewed teacher career CV.pdf",
|
||||
"bytes": 63,
|
||||
"renderedPdfValidation": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"filename": "Reviewed teacher career CV.pdf",
|
||||
"bytes": 63,
|
||||
"renderedPdfValidation": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"filename": "Reviewed teacher career CV.pdf",
|
||||
"bytes": 63,
|
||||
"renderedPdfValidation": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"filename": "Reviewed teacher career CV.pdf",
|
||||
"bytes": 63,
|
||||
"renderedPdfValidation": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"filename": "Reviewed teacher career CV.pdf",
|
||||
"bytes": 63,
|
||||
"renderedPdfValidation": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "dark",
|
||||
"filename": "Reviewed teacher career CV.pdf",
|
||||
"bytes": 63,
|
||||
"renderedPdfValidation": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "light",
|
||||
"filename": "Reviewed teacher career CV.pdf",
|
||||
"bytes": 63,
|
||||
"renderedPdfValidation": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "nb",
|
||||
"mode": "dark",
|
||||
"filename": "Reviewed teacher career CV.pdf",
|
||||
"bytes": 63,
|
||||
"renderedPdfValidation": "NOT RUN"
|
||||
}
|
||||
],
|
||||
"renderReads": 8,
|
||||
"unavailableReads": [
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview",
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview",
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview",
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview",
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview",
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview",
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview",
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview"
|
||||
],
|
||||
"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"
|
||||
],
|
||||
"limits": [
|
||||
"All API and preview responses are controlled fixtures; not backend end-to-end or physical PDF qualification.",
|
||||
"Synthetic download transport bytes are not a PDF; only client revision/filename/download flow qualified. Profile inheritance uses fixture data; import, physical rendering and semantic quality NOT RUN.",
|
||||
"No native device, screen reader, provider, integrated security, deployment or release acceptance."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"screens": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "library",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
}
|
||||
],
|
||||
"journeys": [],
|
||||
"errors": [],
|
||||
"unexpectedWrites": [],
|
||||
"mockedWrites": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"action": "createVariantFromProfile"
|
||||
}
|
||||
],
|
||||
"exportRequests": [],
|
||||
"downloads": [],
|
||||
"renderReads": 1,
|
||||
"unavailableReads": [
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview"
|
||||
],
|
||||
"blockedExternal": [
|
||||
"https://fonts.googleapis.com"
|
||||
],
|
||||
"limits": [
|
||||
"All API and preview responses are controlled fixtures; not backend end-to-end or physical PDF qualification.",
|
||||
"Synthetic download transport bytes are not a PDF; only client revision/filename/download flow qualified. Profile inheritance uses fixture data; import, physical rendering and semantic quality NOT RUN.",
|
||||
"No native device, screen reader, provider, integrated security, deployment or release acceptance."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"screens": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "library",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "edited",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "preview",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "download",
|
||||
"capture": "viewport at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "library",
|
||||
"capture": "full page at top",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "create-from-profile",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "edited",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "preview",
|
||||
"capture": "targeted viewport",
|
||||
"violations": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"state": "download",
|
||||
"capture": "full page at top",
|
||||
"violations": []
|
||||
}
|
||||
],
|
||||
"journeys": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"selectedProfileInheritance": "PASS",
|
||||
"createEditPreviewDownloadTransport": "PASS",
|
||||
"exportUsesSavedRevision": "PASS",
|
||||
"importAndPhysicalPdf": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"selectedProfileInheritance": "PASS",
|
||||
"createEditPreviewDownloadTransport": "PASS",
|
||||
"exportUsesSavedRevision": "PASS",
|
||||
"importAndPhysicalPdf": "NOT RUN"
|
||||
}
|
||||
],
|
||||
"errors": [],
|
||||
"unexpectedWrites": [],
|
||||
"mockedWrites": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"action": "createVariantFromProfile"
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"action": "variantRename"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"action": "createVariantFromProfile"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"action": "variantRename"
|
||||
}
|
||||
],
|
||||
"exportRequests": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"expectedVersion": 2
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"expectedVersion": 2
|
||||
}
|
||||
],
|
||||
"downloads": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"filename": "Reviewed teacher career CV.pdf",
|
||||
"bytes": 63,
|
||||
"renderedPdfValidation": "NOT RUN"
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"mode": "light",
|
||||
"filename": "Reviewed teacher career CV.pdf",
|
||||
"bytes": 63,
|
||||
"renderedPdfValidation": "NOT RUN"
|
||||
}
|
||||
],
|
||||
"renderReads": 2,
|
||||
"unavailableReads": [
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview",
|
||||
"/api/companies",
|
||||
"/api/cv/themes/modern/preview"
|
||||
],
|
||||
"blockedExternal": [
|
||||
"https://fonts.googleapis.com",
|
||||
"https://fonts.googleapis.com"
|
||||
],
|
||||
"limits": [
|
||||
"All API and preview responses are controlled fixtures; not backend end-to-end or physical PDF qualification.",
|
||||
"Synthetic download transport bytes are not a PDF; only client revision/filename/download flow qualified. Profile inheritance uses fixture data; import, physical rendering and semantic quality NOT RUN.",
|
||||
"No native device, screen reader, provider, integrated security, deployment or release acceptance."
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"checks": [
|
||||
{
|
||||
"width": 390,
|
||||
"language": "nb",
|
||||
"theme": "dark",
|
||||
"selections": 24,
|
||||
"errors": []
|
||||
},
|
||||
{
|
||||
"width": 1440,
|
||||
"language": "en",
|
||||
"theme": "light",
|
||||
"selections": 24,
|
||||
"errors": []
|
||||
}
|
||||
],
|
||||
"scope": "Static comparison artifact only, not application acceptance."
|
||||
}
|
||||
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 206 KiB |
@@ -7,6 +7,7 @@
|
||||
body{margin:24px;font:16px/1.5 system-ui,sans-serif;color:#302744;background:#f5f4f9}h1{font-size:26px}p{max-width:95ch}nav{display:flex;flex-wrap:wrap;gap:16px}label{display:grid;gap:4px}select{min-height:44px;max-width:100%;font:inherit;padding:6px}main{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:24px;align-items:start}figure{margin:0;min-width:0}figcaption{font-weight:600;margin-bottom:12px}img{display:block;width:100%}a{color:#694394}:focus-visible{outline:3px solid #694394;outline-offset:3px}@media(max-width:850px){body{margin:16px}main{grid-template-columns:1fr}}
|
||||
</style>
|
||||
<h1>A3: approved reference and real application</h1>
|
||||
<p><a href="CV_JOURNEY_REVIEW.md">Connected Profile-to-CV creation, edit, preview and download review</a> covers eight representative phone/desktop configurations. Its synthetic download transport is not physical PDF qualification.</p>
|
||||
<p>Development evidence, not final acceptance. References are unchanged PNG bytes from approved A3 commit237c79b8. They include workshop controls and different synthetic content. Compare hierarchy, spacing, borders, navigation and available actions rather than whole-image pixels. Reference text is English/light; the real capture follows the controls below. Human, device, native-language and final security/release qualifications remain separate.</p>
|
||||
<nav aria-label="Review controls">
|
||||
<label>Screen<select id="screen"></select></label>
|
||||
|
||||
@@ -9,13 +9,15 @@ const compiled = ts.transpileModule(fs.readFileSync(new URL('../src/i18n/transla
|
||||
const { translations } = await import(`data:text/javascript;base64,${Buffer.from(compiled).toString('base64')}`);
|
||||
const visualMatrix = process.env.A3_VISUAL_MATRIX === '1';
|
||||
const evidenceOnly = process.env.A3_EVIDENCE_REVIEW === '1';
|
||||
const cvJourney = process.env.A3_CV_JOURNEY === '1';
|
||||
assert.ok(!cvJourney || !(evidenceOnly || visualMatrix || process.env.A3_BOUNDARY), 'CV journey is a separate representative workflow scope.');
|
||||
assert.ok(!evidenceOnly || !process.env.A3_BOUNDARY, 'Evidence review does not repeat editor boundary qualification.');
|
||||
const out = path.resolve(import.meta.dirname, evidenceOnly ? '../../docs/ui-modernisation/visual-correction/evidence/career-evidence' : visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/career' : '../../docs/ui-modernisation/evidence/career/browser');
|
||||
const out = path.resolve(import.meta.dirname, cvJourney ? '../../docs/ui-modernisation/visual-correction/evidence/cv-journey' : evidenceOnly ? '../../docs/ui-modernisation/visual-correction/evidence/career-evidence' : visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/career' : '../../docs/ui-modernisation/evidence/career/browser');
|
||||
fs.mkdirSync(out, { recursive: true });
|
||||
const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], mockedWrites: [], renderReads: 0, unavailableReads: [], blockedExternal: [] };
|
||||
const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], mockedWrites: [], exportRequests: [], downloads: [], renderReads: 0, unavailableReads: [], blockedExternal: [] };
|
||||
const browser = await chromium.launch();
|
||||
try {
|
||||
const configurations = process.env.A3_BOUNDARY ? [320, 390, 768, 1000, 1001, 1440].map(width => [width, 'en', 'light']) : process.env.A3_PILOT ? (evidenceOnly ? [[320, 'en', 'light'], [1440, 'en', 'light']] : [[320, 'en', 'light']]) : (visualMatrix || evidenceOnly ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440]).flatMap(width => ['en', 'nb'].flatMap(language => ['light', 'dark'].map(mode => [width, language, mode])));
|
||||
const configurations = process.env.A3_BOUNDARY ? [320, 390, 768, 1000, 1001, 1440].map(width => [width, 'en', 'light']) : process.env.A3_PILOT ? (cvJourney ? [[390, 'en', 'light'], [1440, 'en', 'light']] : evidenceOnly ? [[320, 'en', 'light'], [1440, 'en', 'light']] : [[320, 'en', 'light']]) : (cvJourney ? [390, 1440] : visualMatrix || evidenceOnly ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440]).flatMap(width => ['en', 'nb'].flatMap(language => ['light', 'dark'].map(mode => [width, language, mode])));
|
||||
for (const [width, language, mode] of configurations) {
|
||||
console.log(`Checking ${width}/${language}/${mode}`);
|
||||
const t = key => { assert.ok(translations[language][key], key); return translations[language][key]; };
|
||||
@@ -29,19 +31,29 @@ try {
|
||||
jobs: [], education: [], interests: [], awards: [], publications: [], organisations: [], references: [], otherSections: [], sections: [],
|
||||
}, completeness: { percent: 70, missing: ['Experience', 'Education'], sections: ['personal', 'summary', 'experience', 'education', 'skills', 'projects', 'languages'].map(key => ({ key, label: key, complete: !['experience', 'education'].includes(key), count: 1 })) } };
|
||||
let variant = { id: 3, name: 'Teacher CV', version: 4, settings: { themeId: 'modern', showPhoto: false, showPageNumbers: false, showIcons: true, sections: [], overrides: {}, customSections: [] }, isPublic: false, publicSlug: 'synthetic', jobApplicationId: null, updatedAtUtc: '2026-11-03T10:00:00Z' };
|
||||
let created = !cvJourney;
|
||||
const exportBytes = Buffer.from('Synthetic download transport fixture. Not a rendered PDF or CV.');
|
||||
let letter = { revision: 7, text: 'Dear team\n\nRecorded teaching experience.', currentVersion: 2, versions: [{ version: 2, source: 'manual', length: 45, createdAtUtc: '2026-11-03T10:00:00Z', isCurrent: true }], aiSuggestionCount: 0 };
|
||||
const theme = { id: 'modern', name: 'Modern', category: 'Professional', description: 'Synthetic template', layout: 'header-band', accent: '#3157d5', photoShape: 'none', supportsIcons: false, atsFriendly: true, requiresPro: false, available: true, swatches: ['#3157d5'] };
|
||||
let evidenceState = 'populated';
|
||||
const evidenceItems = [{ id: 1, category: 'achievement', title: 'Recorded nurse mentoring', statement: 'Mentored new colleagues in a synthetic training scenario.', tags: ['Training', 'Communication'], sourceReference: 'Synthetic review' }, { id: 2, category: 'project', title: 'Recorded electrician project', statement: 'Documented a synthetic installation handover.', tags: ['Safety'], sourceReference: 'Synthetic project notes' }];
|
||||
await page.route('**/*', route => {
|
||||
const req = route.request(), url = new URL(req.url()), p = url.pathname;
|
||||
if (evidenceOnly && url.origin !== 'http://localhost:4338' && !(url.origin === 'http://localhost:5202' && p.startsWith('/api/'))) { report.blockedExternal.push(url.origin); return route.abort(); }
|
||||
if ((evidenceOnly || cvJourney) && url.origin !== 'http://localhost:4338' && !(url.origin === 'http://localhost:5202' && p.startsWith('/api/'))) { report.blockedExternal.push(url.origin); return route.abort(); }
|
||||
if (!['localhost', '127.0.0.1'].includes(url.hostname)) { report.blockedExternal.push(url.origin); return route.abort(); }
|
||||
if (!p.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 (evidenceOnly && req.method() !== 'GET') { report.unexpectedWrites.push(p); return route.abort(); }
|
||||
if (evidenceOnly && p === '/api/career/evidence') return evidenceState === 'error' ? route.fulfill({ status: 503, contentType: 'application/json', body: '{}' }) : answer(evidenceState === 'empty' ? [] : evidenceItems);
|
||||
if (cvJourney && req.method() === 'POST' && p === '/api/cv/variants') {
|
||||
const body = req.postDataJSON(); assert.equal(created, false); assert.equal(body.name, 'Teacher career CV'); assert.equal(body.settings.includeProfileContact, true); assert.equal(body.settings.sectionsExplicit, true); assert.deepEqual(body.settings.sections, [{ key: 'summary' }]);
|
||||
variant = { ...variant, name: body.name, settings: body.settings, version: 1 }; created = true; note('createVariantFromProfile'); return answer(variant);
|
||||
}
|
||||
if (cvJourney && req.method() === 'POST' && p === '/api/cv/variants/3/export-pdf') {
|
||||
assert.equal(created, true); assert.equal(variant.version, 2); assert.equal(url.searchParams.get('expectedVersion'), String(variant.version)); assert.deepEqual(req.postDataJSON(), {});
|
||||
report.exportRequests.push({ width, language, mode, expectedVersion: variant.version }); return route.fulfill({ status: 200, contentType: 'application/octet-stream', body: exportBytes });
|
||||
}
|
||||
if (req.method() === 'PUT' && p === '/api/career/profile') {
|
||||
const body = req.postDataJSON(); assert.equal(body.expectedVersion, career.revision); assert.equal(body.cvText, career.cvText);
|
||||
assert.equal(body.profile.projects[0].id, 'project-one'); assert.equal(body.profile.projects[0].name, 'Updated community project');
|
||||
@@ -57,6 +69,7 @@ try {
|
||||
letter = { ...letter, text: body.text, revision: letter.revision + 1, currentVersion: 3 }; note('manualLetterSave'); return answer(letter);
|
||||
}
|
||||
if (req.method() === 'POST' && p === '/api/cv/preview') {
|
||||
if (cvJourney) { assert.equal(req.postDataJSON().settings.includeProfileContact, true); assert.deepEqual(req.postDataJSON().settings.sections, [{ key: 'summary' }]); }
|
||||
report.renderReads++; return answer({ themeId: 'modern', html: '<!doctype html><html lang="en"><head><title>Controlled CV preview</title></head><body><main><h1>Alex Sample</h1><p>Recorded teaching experience</p></main></body></html>', suggestedFileName: 'teacher.pdf' });
|
||||
}
|
||||
if (req.method() !== 'GET') { report.unexpectedWrites.push(p); return route.abort(); }
|
||||
@@ -66,7 +79,7 @@ try {
|
||||
'/api/career/profile': career, '/api/career/profile/versions': [], '/api/career/evidence': [],
|
||||
'/api/profile-cv/runs': [{ id: 41, trigger: 'upload', status: 'pending_review', startedAtUtc: '2026-11-03T10:00:00Z', parserVersion: 'offline-fixture', normalizerVersion: 'offline-fixture', llmPromptVersion: 'offline-fixture' }],
|
||||
'/api/profile-cv/runs/41/diff': { runId: 41, status: 'pending_review', revision: career.revision, diff: { totalAdded: 1, totalUpdated: 1, totalLowConfidence: 1, hasChanges: true, categories: [{ category: 'Languages', unchangedCount: 0, lowConfidenceCount: 1, added: [{ id: 'Languages|french', label: 'French', confidence: 'Low', fieldChanges: [] }], updated: [{ id: 'Languages|norwegian', label: 'Norwegian', confidence: 'Medium', fieldChanges: [{ field: 'Level', oldValue: 'A2', newValue: 'B1' }] }] }] } },
|
||||
'/api/cv/variants': [{ ...variant, themeId: 'modern', language: 'en' }], '/api/cv/variants/3': variant, '/api/cv/themes': [theme], '/api/cv/variants/3/versions': [],
|
||||
'/api/cv/variants': created ? [{ ...variant, themeId: 'modern', language: 'en' }] : [], '/api/cv/variants/3': variant, '/api/cv/themes': [theme], '/api/cv/variants/3/versions': [],
|
||||
'/api/cv/outline': { fullName: 'Alex Sample', headline: 'Teacher', sections: [{ key: 'summary', title: 'Professional Summary', kind: 'bullets', bullets: ['Recorded summary'], tags: [], entries: [] }] },
|
||||
'/api/jobapplications/42/workspace': { id: 42, revision: letter.revision, jobTitle: 'Primary teacher', company: 'Synthetic school', status: 'Saved', stageGroup: 'Applied', stageOrder: 1, location: 'Oslo', countryCode: 'NO', jobUrl: null, source: 'nav', description: 'Recorded source advertisement.', descriptionLanguage: 'en', tags: [], notes: '', applicationAnswerDraft: '', recruiterMessageDraft: '', hasJobDescription: true, cv: { variantId: 3, variantName: variant.name, themeId: 'modern', hasTailoredCvText: false }, hasCoverLetter: true, documentCount: 0, hasPortfolio: false, aiInteractionCount: 0, recentActivity: [], nextStep: null, checklistProgress: { total: 0, completed: 0, dismissed: 0, percent: 0 } },
|
||||
'/api/jobapplications/42/cover-letter': letter, '/api/jobapplications/42/status-suggestion': null,
|
||||
@@ -86,6 +99,21 @@ try {
|
||||
if (width >= 600) await page.getByRole('tab', { name: t(key), exact: true }).click();
|
||||
else { await page.getByRole('combobox', { name: t('careerWorkspaceNavigation'), exact: true }).click(); await page.getByRole('option', { name: t(key), exact: true }).click(); }
|
||||
};
|
||||
if (cvJourney) {
|
||||
await page.goto('http://localhost:4338/career/builder'); await expect(page.getByRole('button', { name: t('cvDashboardNewCv'), exact: true })).toBeEnabled(); await scan('library');
|
||||
await page.getByRole('button', { name: t('cvDashboardNewCv'), exact: true }).click();
|
||||
const dialog = page.getByRole('dialog', { name: t('cvDashboardCreateTitle'), exact: true });
|
||||
await dialog.getByRole('textbox', { name: new RegExp(t('cvEditorName')) }).fill('Teacher career CV'); await dialog.getByRole('radio', { name: t('cvDashboardFromProfile'), exact: true }).check();
|
||||
await dialog.getByRole('checkbox', { name: t('cvEditorIncludeProfileContact'), exact: true }).check(); await dialog.getByRole('checkbox', { name: 'Professional Summary', exact: true }).check(); await scan('create-from-profile', dialog);
|
||||
await dialog.getByRole('button', { name: t('cvDashboardCreateCv'), exact: true }).click(); await expect.poll(() => new URL(page.url()).pathname).toBe('/career/builder/3');
|
||||
await expect(dialog).toBeHidden(); await expect(page.getByRole('region', { name: t('cvEditorEditingRegion'), exact: true })).toBeVisible();
|
||||
const name = page.getByRole('textbox', { name: t('cvEditorName'), exact: true }); await expect(name).toHaveValue('Teacher career CV'); await name.fill('Reviewed teacher career CV'); await expect.poll(() => variant.version, { timeout: 15000 }).toBe(2); await scan('edited', name);
|
||||
if (width < 768) await page.getByRole('button', { name: t('cvEditorPreview'), exact: true }).click();
|
||||
const preview = page.getByRole('region', { name: t('cvEditorLivePreview'), exact: true }); await expect(preview).toBeVisible(); await expect(preview.frameLocator('iframe').getByRole('heading', { name: career.profile.contact.fullName, exact: true })).toBeVisible(); await scan('preview', preview);
|
||||
const downloading = page.waitForEvent('download'); await page.getByRole('button', { name: t('cvEditorDownloadPdf'), exact: true }).click(); const download = await downloading; const stream = await download.createReadStream(); const chunks = []; for await (const chunk of stream) chunks.push(chunk); assert.deepEqual(Buffer.concat(chunks), exportBytes); assert.equal(download.suggestedFilename(), 'Reviewed teacher career CV.pdf');
|
||||
report.downloads.push({ width, language, mode, filename: download.suggestedFilename(), bytes: exportBytes.length, renderedPdfValidation: 'NOT RUN' }); await scan('download');
|
||||
report.journeys.push({ width, language, mode, selectedProfileInheritance: 'PASS', createEditPreviewDownloadTransport: 'PASS', exportUsesSavedRevision: 'PASS', importAndPhysicalPdf: 'NOT RUN' }); await context.close(); continue;
|
||||
}
|
||||
if (evidenceOnly) {
|
||||
const openEvidence = async () => { await page.goto('http://localhost:4338/career'); await careerSection('careerWorkspaceEvidenceTab'); };
|
||||
await openEvidence();
|
||||
@@ -146,10 +174,10 @@ try {
|
||||
report.journeys.push({ width, language, mode, all14KeyboardEditTargets: 'PASS', canonicalSaveStableIds: 'PASS', legacyImportComparisonSelectionNoApply: 'PASS', libraryKeyboardOpen: 'PASS', cvResponsiveRename: 'PASS', letterResponsiveManualSave: 'PASS' });
|
||||
await context.close();
|
||||
}
|
||||
assert.equal(report.screens.length, configurations.length * 6); assert.equal(report.journeys.length, configurations.length); assert.equal(report.mockedWrites.length, evidenceOnly ? 0 : configurations.length * 3);
|
||||
assert.equal(report.screens.length, configurations.length * (cvJourney ? 5 : 6)); assert.equal(report.journeys.length, configurations.length); assert.equal(report.mockedWrites.length, evidenceOnly ? 0 : configurations.length * (cvJourney ? 2 : 3)); assert.equal(report.exportRequests.length, cvJourney ? configurations.length : 0); assert.equal(report.downloads.length, cvJourney ? configurations.length : 0);
|
||||
assert.deepEqual(report.errors, []); assert.deepEqual(report.unexpectedWrites, []); assert.ok(report.blockedExternal.every(origin => origin === 'https://fonts.googleapis.com'));
|
||||
console.log(`PASS:${report.journeys.length} controlled journeys,${report.screens.length} axe scans/captures,${report.mockedWrites.length} fixture mutations.`);
|
||||
} finally {
|
||||
fs.writeFileSync(path.join(out, process.env.A3_BOUNDARY ? 'BOUNDARY.json' : process.env.A3_PILOT ? 'PILOT.json' : 'BROWSER.json'), JSON.stringify({ ...report, limits: ['All API and preview responses are controlled fixtures; not backend end-to-end or physical PDF qualification.', evidenceOnly ? 'Evidence-only scope: delete confirmation cancelled, all mutations blocked; profile/editor/import/export workflows NOT RUN.' : 'Legacy import comparison and selection only; no parser, model, import acceptance or source mutation.', 'No native device, screen reader, provider, integrated security, deployment or release acceptance.'] }, null, 2));
|
||||
fs.writeFileSync(path.join(out, process.env.A3_BOUNDARY ? 'BOUNDARY.json' : process.env.A3_PILOT ? 'PILOT.json' : 'BROWSER.json'), JSON.stringify({ ...report, limits: ['All API and preview responses are controlled fixtures; not backend end-to-end or physical PDF qualification.', cvJourney ? 'Synthetic download transport bytes are not a PDF; only client revision/filename/download flow qualified. Profile inheritance uses fixture data; import, physical rendering and semantic quality NOT RUN.' : evidenceOnly ? 'Evidence-only scope: delete confirmation cancelled, all mutations blocked; profile/editor/import/export workflows NOT RUN.' : 'Legacy import comparison and selection only; no parser, model, import acceptance or source mutation.', 'No native device, screen reader, provider, integrated security, deployment or release acceptance.'] }, null, 2));
|
||||
await browser.close();
|
||||
}
|
||||
|
||||