import { expect, it } from "vitest"; import { inspectWebPageInputSchema } from "../domain/browserObservation.js"; import { captureStorage } from "./CdpCaptureStorage.js"; import { CdpCommandRejection } from "./CdpCommandRejection.js"; import type { CdpConnection } from "./CdpConnection.js"; const NO_CACHE_COMMAND = Symbol("unsupported"); const captureWithCacheResult = async ( cacheResult: unknown, ): Promise>["value"]> => { const connection = { send(method: string): Promise { switch (method) { case "Storage.getUsageAndQuota": return Promise.resolve({ usage: 1, quota: 10 }); case "DOMStorage.getDOMStorageItems": return Promise.resolve({ entries: [] }); case "IndexedDB.requestDatabaseNames": return Promise.resolve({ databaseNames: [] }); case "Network.getCookies": return Promise.resolve({ cookies: [] }); case "CacheStorage.requestCacheNames": return cacheResult === NO_CACHE_COMMAND ? Promise.reject( new CdpCommandRejection( "inspect_web_page", method, -32601, "Method not found", ), ) : Promise.resolve(cacheResult); case "CacheStorage.requestEntries": return Promise.resolve({ cacheDataEntries: [], returnCount: 0 }); default: return Promise.reject(new Error(`Unexpected command: ${method}`)); } }, } as unknown as CdpConnection; const { value } = await captureStorage( { connection, sessionId: undefined, input: inspectWebPageInputSchema.parse({ cdp_endpoint: "http://127.0.0.1:9222", target_id: "fixture-page", include_storage_keys: true, include_storage_fingerprints: true, }), }, "https://example.test/", [], ); return value; }; it.each([ ["an observed empty cache list", { caches: [] }, true], ["a response without a cache list", {}, false], ["a non-array cache list", { caches: "nope" }, false], ["a cache list with an unusable entry", { caches: [5] }, false], ["an unsupported cache command", NO_CACHE_COMMAND, false], ] as const)( "reports fingerprint completeness for %s", async (_label, cacheResult, complete) => { const value = await captureWithCacheResult(cacheResult); expect(value.cache_names).toEqual([]); expect(value.fingerprints_complete).toBe(complete); }, ); it.each([false, true])( "preserves valid cache evidence beside an unusable entry: %s", async (mixed) => { const cache = { cacheName: "fixture-cache", cacheId: "fixture-cache-id" }; const value = await captureWithCacheResult({ caches: mixed ? [cache, 5] : [cache], }); expect(value.cache_names).toEqual(["fixture-cache"]); expect(value.fingerprints_complete).toBe(!mixed); }, ); it("keeps an omitted IndexedDB remote value unknown", async () => { const replies: Record = { "Storage.getUsageAndQuota": { usage: 0, quota: 1000 }, "DOMStorage.getDOMStorageItems": { entries: [] }, "IndexedDB.requestDatabaseNames": { databaseNames: ["db"] }, "CacheStorage.requestCacheNames": { caches: [] }, "Network.getCookies": { cookies: [] }, "IndexedDB.requestDatabase": { databaseWithObjectStores: { name: "db", objectStores: [ { name: "records", keyPath: { type: "string", string: "id" }, autoIncrement: false, indexes: [], }, ], }, }, "IndexedDB.requestData": { objectStoreDataEntries: [ { key: { type: "number", value: 1 }, primaryKey: { type: "number", value: 1 }, }, ], hasMore: false, }, }; const connection = { async send(method: string): Promise { if (!(method in replies)) throw new Error(method); return replies[method]; }, } as unknown as CdpConnection; const { value } = await captureStorage( { connection, sessionId: undefined, input: inspectWebPageInputSchema.parse({ cdp_endpoint: "http://127.0.0.1:9222", allowed_origins: ["https://example.test"], target_id: "page-1", include_storage_keys: true, include_storage_fingerprints: true, }), }, "https://example.test/app", [], ); const record = value.content_fingerprints.find( (item) => item.scope === "indexed_db_record", ); expect(record).toMatchObject({ value_sha256: null, complete: false }); expect(value.fingerprints_complete).toBe(false); });