3fd149556aba

fix: resolve 27 pre-existing tsc errors in test files — SharedArrayBuffer/Mock drift, unused vars, circular chrome type (v4.0.0)

time
2026-06-12 17:36 UTC · 4 months ago
machine
koh2
agent
claude-sonnet-4-6
session
tsc cleanup
parent
40ffe3171e9b
14 files src/background/clipboard.double-failure.test.ts+2 −2src/background/license.verification.test.ts+2 −2src/background/messages.batch-sanitize.test.ts+1 −1src/background/messages.edit-origin.test.ts+1 −1src/background/ml.predictbatch.test.ts+3 −3src/background/passkey.ed25519.test.ts+4 −4src/background/vault.consolidate-passkeys.test.ts+1 −1src/background/vault.corruption.test.ts+1 −3src/background/vault.purge-trash.test.ts+1 −1src/background/vault.rotate-sync-identity.test.ts+2 −2src/crypto/argon2id.kat.test.ts+2 −2src/popup/codex/codex.multistripe.test.ts+0 −10src/shared/backup.nfc-fallback.test.ts+2 −2src/shared/sync.disconnect.test.ts+3 −3
src/background/clipboard.double-failure.test.ts+2 −2
@@ -114,7 +114,7 @@114114   // Even when we skip writing, the alarm must fire to clear the clipboard later.115115   it("T-037b: alreadyWritten=true → alarm is still created for auto-clear", async () => {116116     const { copyToClipboard } = await import("./clipboard");117-    const alarmsMock = chrome.alarms as { create: ReturnType<typeof vi.fn> };117+    const alarmsMock = chrome.alarms as unknown as { create: ReturnType<typeof vi.fn> };118118 119119     await copyToClipboard("secret-value", "Password", true);120120 @@ -141,7 +141,7 @@141141     // executeScript already fails (no tabs in mock)142142 143143     const { copyToClipboard } = await import("./clipboard");144-    const alarmsMock = chrome.alarms as { create: ReturnType<typeof vi.fn> };144+    const alarmsMock = chrome.alarms as unknown as { create: ReturnType<typeof vi.fn> };145145 146146     // Must not throw even when both paths fail147147     await expect(copyToClipboard("secret", "Password", false)).resolves.toBeUndefined();

view file

src/background/license.verification.test.ts+2 −2
@@ -134,7 +134,7 @@134134       return { valid: false, plan: "free" };135135     }136136 137-    const pubKey = await (crypto.subtle as Record<string, Function>).importKey(137+    const pubKey = await (crypto.subtle as unknown as Record<string, Function>).importKey(138138       "raw",139139       hexToBytes(pubKeyHex),140140       { name: "Ed25519" },@@ -142,7 +142,7 @@142142       ["verify"],143143     ) as CryptoKey;144144 145-    const isValid = await (crypto.subtle as Record<string, Function>).verify(145+    const isValid = await (crypto.subtle as unknown as Record<string, Function>).verify(146146       "Ed25519",147147       pubKey,148148       signature,

view file

src/background/messages.batch-sanitize.test.ts+1 −1
@@ -157,7 +157,7 @@157157     const added = await vault.batchAddEntries([maliciousDraft]);158158     expect(added).toHaveLength(1);159159     // Bug this catches: prototype pollution persists in the saved entry160-    expect((added[0] as Record<string, unknown>).poisoned).toBeUndefined();160+    expect((added[0] as unknown as Record<string, unknown>).poisoned).toBeUndefined();161161     expect(Object.getPrototypeOf(added[0])).toBe(Object.prototype);162162   });163163 

view file

src/background/messages.edit-origin.test.ts+1 −1
@@ -53,7 +53,7 @@5353       id: "test-extension-id",5454       getURL: vi.fn((path: string) => `chrome-extension://test-extension-id/${path}`),5555     },56-  } as unknown as typeof chrome;56+  } as unknown as typeof globalThis.chrome;5757   return { storage, chrome };5858 }5959 

view file

src/background/ml.predictbatch.test.ts+3 −3
@@ -134,7 +134,7 @@134134   it("T-030e: extreme positive feature values → no NaN or Infinity in output", () => {135135     const extremeFeatures: MLFieldFeatures = {} as MLFieldFeatures;136136     for (const key of Object.keys(zeroFeatures()) as (keyof MLFieldFeatures)[]) {137-      (extremeFeatures as Record<string, number>)[key] = 1000;137+      (extremeFeatures as unknown as Record<string, number>)[key] = 1000;138138     }139139 140140     const result = predictBatch([extremeFeatures]);@@ -146,7 +146,7 @@146146   it("T-030f: extreme negative feature values → no NaN or Infinity", () => {147147     const extremeNeg: MLFieldFeatures = {} as MLFieldFeatures;148148     for (const key of Object.keys(zeroFeatures()) as (keyof MLFieldFeatures)[]) {149-      (extremeNeg as Record<string, number>)[key] = -1000;149+      (extremeNeg as unknown as Record<string, number>)[key] = -1000;150150     }151151 152152     const result = predictBatch([extremeNeg]);@@ -158,7 +158,7 @@158158     const mixed: MLFieldFeatures = {} as MLFieldFeatures;159159     let i = 0;160160     for (const key of Object.keys(zeroFeatures()) as (keyof MLFieldFeatures)[]) {161-      (mixed as Record<string, number>)[key] = i % 2 === 0 ? 1e6 : -1e6;161+      (mixed as unknown as Record<string, number>)[key] = i % 2 === 0 ? 1e6 : -1e6;162162       i++;163163     }164164 

view file

src/background/passkey.ed25519.test.ts+4 −4
@@ -176,10 +176,10 @@176176   it("T-015f: Ed25519 signature verifies against the generated public key", async () => {177177     const authData = new Uint8Array(37).fill(0xcc);178178     const clientDataHash = new Uint8Array(32).fill(0xdd);179-    const sig = await signPasskeyAssertion(keypair.privateKeyJwk, -8, authData, clientDataHash);179+    const sig = new Uint8Array(await signPasskeyAssertion(keypair.privateKeyJwk, -8, authData, clientDataHash));180180 181181     // Reconstruct the public key for verification from the JWK 'x' coordinate.182-    const rawPub = base64urlDecode(keypair.privateKeyJwk.x!);182+    const rawPub = new Uint8Array(base64urlDecode(keypair.privateKeyJwk.x!));183183     const pubKey = await crypto.subtle.importKey(184184       "raw",185185       rawPub,@@ -207,9 +207,9 @@207207   it("T-015g: signature does not verify against a different clientDataHash (replay check)", async () => {208208     const authData = new Uint8Array(37).fill(0xee);209209     const clientDataHash = new Uint8Array(32).fill(0xff);210-    const sig = await signPasskeyAssertion(keypair.privateKeyJwk, -8, authData, clientDataHash);210+    const sig = new Uint8Array(await signPasskeyAssertion(keypair.privateKeyJwk, -8, authData, clientDataHash));211211 212-    const rawPub = base64urlDecode(keypair.privateKeyJwk.x!);212+    const rawPub = new Uint8Array(base64urlDecode(keypair.privateKeyJwk.x!));213213     const pubKey = await crypto.subtle.importKey(214214       "raw",215215       rawPub,

view file

src/background/vault.consolidate-passkeys.test.ts+1 −1
@@ -45,7 +45,7 @@4545     },4646     alarms: { clear: vi.fn(), create: vi.fn(), onAlarm: { addListener: vi.fn() } },4747     idle: { setDetectionInterval: vi.fn(), onStateChanged: { addListener: vi.fn() } },48-  } as unknown as typeof chrome;48+  } as unknown as typeof globalThis.chrome;4949   return { storage, chrome };5050 }5151 

view file

src/background/vault.corruption.test.ts+1 −3
@@ -19,8 +19,6 @@1919 2020 import { beforeAll, describe, expect, it, vi } from "vitest";2121 22-type StorageShape = Record<string, unknown>;23-2422 // ---------------------------------------------------------------------------2523 // Helpers: build StoredVault objects for specific scenarios2624 // ---------------------------------------------------------------------------@@ -35,7 +33,7 @@3533 3634 async function aesGcmEncrypt(3735   key: CryptoKey,38-  nonce: Uint8Array,36+  nonce: Uint8Array<ArrayBuffer>,3937   plaintext: string,4038   aadTag = "slot_a_v1",4139 ): Promise<{ ciphertext: string; tag: string }> {

view file

src/background/vault.purge-trash.test.ts+1 −1
@@ -45,7 +45,7 @@4545     },4646     alarms: { clear: vi.fn(), create: vi.fn(), onAlarm: { addListener: vi.fn() } },4747     idle: { setDetectionInterval: vi.fn(), onStateChanged: { addListener: vi.fn() } },48-  } as unknown as typeof chrome;48+  } as unknown as typeof globalThis.chrome;4949   return { storage, chrome };5050 }5151 

view file

src/background/vault.rotate-sync-identity.test.ts+2 −2
@@ -25,7 +25,7 @@2525 2626 function makeChromeStorageMock(): {2727   storage: StorageShape;28-  chrome: typeof chrome;28+  chrome: typeof globalThis.chrome;2929 } {3030   const storage: StorageShape = {};3131   const chrome = {@@ -63,7 +63,7 @@6363       setDetectionInterval: vi.fn(),6464       onStateChanged: { addListener: vi.fn() },6565     },66-  } as unknown as typeof chrome;66+  } as unknown as typeof globalThis.chrome;6767   return { storage, chrome };6868 }6969 

view file

src/crypto/argon2id.kat.test.ts+2 −2
@@ -56,7 +56,7 @@5656 5757 // If you have not yet run the generation script, mark this test as skipped5858 // and uncomment the KAT vector once generated.59-const KAT_AVAILABLE = KAT_EXPECTED_HEX !== "REPLACE_ME_WITH_ACTUAL_HASH_FROM_GEN_SCRIPT";59+const KAT_AVAILABLE = (KAT_EXPECTED_HEX as string) !== "REPLACE_ME_WITH_ACTUAL_HASH_FROM_GEN_SCRIPT";6060 6161 describe("T-019: Argon2id known-answer test + parameter assertion", () => {6262   // T-019a: deriveKey output matches the KAT vector exactly.@@ -64,7 +64,7 @@6464   // test fails — alerting the developer before a parameter regression ships.6565   it(6666     "T-019a: deriveKey('testpassword', salt=0xAB×16) matches KAT vector (m=65536, t=3, p=4)",67-    KAT_AVAILABLE ? undefined : { skip: "KAT vector not yet generated (run gen-argon2id-kat.ts)" },67+    KAT_AVAILABLE ? undefined : { skip: true },6868     async () => {6969       if (!KAT_AVAILABLE) return;7070       const salt = new Uint8Array(16).fill(0xab);

view file

src/popup/codex/codex.multistripe.test.ts+0 −10
@@ -19,7 +19,6 @@1919 import { deflate } from "pako";2020 import { describe, expect, it } from "vitest";2121 import {22-  CHUNK_SIZE,2322   MAX_DATA_SHARDS_PER_STRIPE,2423   CodexError,2524   computeParityShards,@@ -76,15 +75,6 @@7675   for (let i = 0; i < r.parityChunks.length; i++) {7776     chunks.set(r.dataShards + i, r.parityChunks[i]!);7877   }79-  return { chunks, dataShards: r.dataShards, totalChunks: r.totalChunks };80-}81-82-function encodeResultToStripeChunksWithoutParity(r: EncodeResult): StripeChunks {83-  const chunks = new Map<number, Uint8Array>();84-  for (let i = 0; i < r.dataChunks.length; i++) {85-    chunks.set(i, r.dataChunks[i]!);86-  }87-  // Parity shards omitted: RS decoder must reconstruct them (erasure mode)8878   return { chunks, dataShards: r.dataShards, totalChunks: r.totalChunks };8979 }9080 

view file

src/shared/backup.nfc-fallback.test.ts+2 −2
@@ -16,7 +16,7 @@1616   importEntriesFromPeachJson,1717   derivePeachExportKey,1818 } from "./backup";19-import { decrypt, encrypt } from "../background/aes";19+import { encrypt } from "../background/aes";2020 import type { VaultEntry } from "./types";2121 2222 // Use explicit Unicode escapes so the byte sequences are unambiguous regardless@@ -28,7 +28,7 @@2828 const NFC_PASSWORD = "café";2929 3030 // Sanity-check the assumptions at module load time.31-if (NFD_PASSWORD === NFC_PASSWORD) {31+if ((NFD_PASSWORD as string) === NFC_PASSWORD) {3232   throw new Error("Test assumption broken: NFD and NFC passwords are identical on this platform");3333 }3434 if (NFD_PASSWORD.normalize("NFC") !== NFC_PASSWORD) {

view file

src/shared/sync.disconnect.test.ts+3 −3
@@ -31,8 +31,8 @@3131   binaryType: string;3232   onmessage: ((ev: MessageEvent) => void) | null;3333   onerror: (() => void) | null;34-  onclose: (() => void) | null;35-  onopen: (() => void) | null;34+  onclose: ((ev: Event) => void) | null;35+  onopen: ((ev: Event) => void) | null;3636   sentFrames: ArrayBuffer[];3737   send(data: ArrayBuffer | Uint8Array): void;3838   close(): void;@@ -52,7 +52,7 @@5252     sentFrames: [],5353     send(data: ArrayBuffer | Uint8Array) {5454       if (data instanceof Uint8Array) {55-        instance.sentFrames.push(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));55+        instance.sentFrames.push(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer);5656       } else {5757         instance.sentFrames.push(data);5858       }

view file