Files
reverse-engineering-anything/src/browser/CdpCaptureStorage.test.ts
T

143 lines
4.6 KiB
TypeScript

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<Awaited<ReturnType<typeof captureStorage>>["value"]> => {
const connection = {
send(method: string): Promise<unknown> {
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<string, unknown> = {
"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<unknown> {
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);
});