feat(02-04): harness A24 — empirical Blob URL download verification (D-P2-01 closes P0-6)
Wire A24 into the Plan 01-13 Approach B UAT harness as the binding empirical gate for D-P2-01. A24 verifies end-to-end that SAVE_ARCHIVE → chrome.downloads. download receives a `blob:` URL prefix (NOT `data:application/zip;base64,`), closing audit P0-6 functionally. The Plan 02-02 unit tests pin the wire-format at the SW↔offscreen boundary; A24 pins it at the chrome.downloads platform boundary through a real Chrome instance. Strategy: chrome.downloads.onCreated listener captures the URL cross-realm. The plan's <action> block proposed a chrome.downloads.download monkey-patch installed in the harness page realm — but that intercepts only same-realm calls, missing the SW's call. The canonical cross-realm capture pattern is chrome.downloads.onCreated (fires for any download initiated by any extension realm, with the full DownloadItem including .url). Documented as a deviation from the plan's pseudo-code in SUMMARY.md (Rule 1 — bug fix vs the pseudo-code strategy; same A24 contract verified, correct mechanism). Files modified: - tests/uat/extension-page-harness.ts (+~150 lines): assertA24 + A24_* constants - tests/uat/lib/harness-page-driver.ts (+~30 lines): driveA24 page.evaluate wrapper - tests/uat/harness.test.ts (+~10 lines): import driveA24, append to drivers list Verification: - HEADLESS=1 npm run test:uat → 25/25 GREEN (24 baseline + A24) - capturedUrl observed: blob:chrome-extension://lpgnfoop.../... - npx vitest run → 171/171 GREEN (no regression) - Tier-1 FORBIDDEN_HOOK_STRINGS gate → 13/13 GREEN (12 strings preserved) - npx tsc --noEmit → clean Plan 02-04 scope: 1/3 tasks landed (A24); Tasks 2-3 add A25+A26+A27+A28 (latency, meta.json shape, multi-tab strict, REQ-archive-layout strict).
This commit is contained in:
@@ -1178,6 +1178,35 @@ export async function driveA23(page: Page): Promise<AssertionRecord> {
|
||||
}) as AssertionRecord;
|
||||
}
|
||||
|
||||
/* ─── Plan 02-04 Task 1 — driveA24 (Blob URL empirical D-P2-01) ─────── */
|
||||
|
||||
/**
|
||||
* Drive A24 (Plan 02-04 D-P2-01 empirical Blob URL verification).
|
||||
* Standard page.evaluate wrapper — page side installs the
|
||||
* chrome.downloads.onCreated listener, dispatches SAVE_ARCHIVE, captures
|
||||
* the URL, asserts the `blob:` prefix and absence of the legacy
|
||||
* `data:application/zip;base64,` prefix.
|
||||
*
|
||||
* Chains AFTER driveA23 in the orchestrator. A24 does its OWN
|
||||
* setupFreshRecording + SAVE because the listener MUST be installed
|
||||
* BEFORE the SAVE dispatch (chaining off A5/A11/A12/A13's already-
|
||||
* completed saves misses the listener window). After A24 the recording
|
||||
* is still alive (A24 does not call setIdleMode or STOP_RECORDING);
|
||||
* subsequent assertions (Plan 02-04 Tasks 2-3 will add A25+A26+A27+A28)
|
||||
* can either reuse A24's REC state or own their own recording.
|
||||
*
|
||||
* @param page - The harness page from `launchHarnessBrowser`.
|
||||
* @returns Structured AssertionRecord with 4 checks (A24.1..A24.4).
|
||||
*/
|
||||
export async function driveA24(page: Page): Promise<AssertionRecord> {
|
||||
return await page.evaluate(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- evaluate runs in browser context where Window types are loose.
|
||||
const harness = (window as any).__mokoshHarness;
|
||||
const r: AssertionRecord = await harness.assertA24();
|
||||
return r;
|
||||
}) as AssertionRecord;
|
||||
}
|
||||
|
||||
// Note (Wave 3D): the AssertionWithBytes interface is retained at the
|
||||
// top of this file as a public export — but Wave 3D's drivers no
|
||||
// longer use it (the host side now does all bytes-handling internally
|
||||
|
||||
Reference in New Issue
Block a user