use proper ser/de

This commit is contained in:
Simon Knott 2025-02-04 10:34:55 +01:00
parent 3dddfd168e
commit e26bd2a0c0
No known key found for this signature in database
GPG key ID: 8CEDC00028084AEC
2 changed files with 33 additions and 9 deletions

View file

@ -43,6 +43,7 @@ import type { Artifact } from './artifact';
import { Clock } from './clock'; import { Clock } from './clock';
import type { ClientCertificatesProxy } from './socksClientCertificatesInterceptor'; import type { ClientCertificatesProxy } from './socksClientCertificatesInterceptor';
import { RecorderApp } from './recorder/recorderApp'; import { RecorderApp } from './recorder/recorderApp';
import * as utilitySerializers from './isomorphic/utilityScriptSerializers';
export abstract class BrowserContext extends SdkObject { export abstract class BrowserContext extends SdkObject {
static Events = { static Events = {
@ -550,7 +551,7 @@ export abstract class BrowserContext extends SdkObject {
return { return {
key: objectStore.keyPath === null ? key.toString() : undefined, key: objectStore.keyPath === null ? key.toString() : undefined,
value: JSON.stringify(record) value: record
}; };
})); }));
@ -590,6 +591,15 @@ export abstract class BrowserContext extends SdkObject {
}; };
} }
function serializeRecords(indexedDBs: channels.IndexedDBDatabase[]) {
for (const db of indexedDBs) {
for (const store of db.stores) {
for (const record of store.records)
record.value = JSON.stringify(utilitySerializers.serializeAsCallArgument(record.value, v => ({ fallThrough: v })));
}
}
}
// First try collecting storage stage from existing pages. // First try collecting storage stage from existing pages.
for (const page of this.pages()) { for (const page of this.pages()) {
const origin = page.mainFrame().origin(); const origin = page.mainFrame().origin();
@ -597,6 +607,8 @@ export abstract class BrowserContext extends SdkObject {
continue; continue;
try { try {
const storage = await page.mainFrame().nonStallingEvaluateInExistingContext(`(${_collectStorageScript.toString()})()`, 'utility'); const storage = await page.mainFrame().nonStallingEvaluateInExistingContext(`(${_collectStorageScript.toString()})()`, 'utility');
if (storage.indexedDB?.length)
serializeRecords(storage.indexedDB);
if (storage.localStorage.length || storage.indexedDB?.length) if (storage.localStorage.length || storage.indexedDB?.length)
result.origins.push({ origin, localStorage: storage.localStorage, indexedDB: storage.indexedDB } as channels.OriginStorage); result.origins.push({ origin, localStorage: storage.localStorage, indexedDB: storage.indexedDB } as channels.OriginStorage);
originsToSave.delete(origin); originsToSave.delete(origin);
@ -617,6 +629,8 @@ export abstract class BrowserContext extends SdkObject {
const frame = page.mainFrame(); const frame = page.mainFrame();
await frame.goto(internalMetadata, origin); await frame.goto(internalMetadata, origin);
const storage = await frame.evaluateExpression(`(${_collectStorageScript.toString()})()`, { world: 'utility' }); const storage = await frame.evaluateExpression(`(${_collectStorageScript.toString()})()`, { world: 'utility' });
if (storage.indexedDB?.length)
serializeRecords(storage.indexedDB);
if (storage.localStorage.length || storage.indexedDB?.length) if (storage.localStorage.length || storage.indexedDB?.length)
result.origins.push({ origin, localStorage: storage.localStorage, indexedDB: storage.indexedDB } as channels.OriginStorage); result.origins.push({ origin, localStorage: storage.localStorage, indexedDB: storage.indexedDB } as channels.OriginStorage);
} }
@ -682,6 +696,13 @@ export abstract class BrowserContext extends SdkObject {
const frame = page.mainFrame(); const frame = page.mainFrame();
await frame.goto(metadata, originState.origin); await frame.goto(metadata, originState.origin);
for (const dbInfo of (originState.indexedDB || [])) {
for (const store of dbInfo.stores) {
for (const record of store.records)
record.value = utilitySerializers.parseEvaluationResultValue(JSON.parse(record.value));
}
}
async function _restoreStorageState(originState: channels.OriginStorage) { async function _restoreStorageState(originState: channels.OriginStorage) {
for (const { name, value } of (originState.localStorage || [])) for (const { name, value } of (originState.localStorage || []))
localStorage.setItem(name, value); localStorage.setItem(name, value);
@ -704,7 +725,7 @@ export abstract class BrowserContext extends SdkObject {
const objectStore = transaction.objectStore(store.name); const objectStore = transaction.objectStore(store.name);
return store.records.map(record => new Promise((resolve, reject) => { return store.records.map(record => new Promise((resolve, reject) => {
const request = objectStore.add( const request = objectStore.add(
JSON.parse(record.value), // TODO: use better serialization record.value as any, // protocol says string, but this got deserialized above
objectStore.keyPath === null ? record.key : undefined objectStore.keyPath === null ? record.key : undefined
); );
request.addEventListener('success', resolve); request.addEventListener('success', resolve);

View file

@ -341,13 +341,16 @@ it('should support IndexedDB', async ({ page, contextFactory }) => {
records: [ records: [
{ {
value: JSON.stringify({ value: JSON.stringify({
taskTitle: 'Pet the cat', o: [
hours: '1', { k: 'taskTitle', v: 'Pet the cat' },
minutes: '1', { k: 'hours', v: '1' },
day: '01', { k: 'minutes', v: '1' },
month: 'January', { k: 'day', v: '01' },
year: '2025', { k: 'month', v: 'January' },
notified: 'no', { k: 'year', v: '2025' },
{ k: 'notified', v: 'no' }
],
id: 1
}), }),
}, },
], ],