From e26bd2a0c010ee65cb81a277873e2aefabb5619d Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Tue, 4 Feb 2025 10:34:55 +0100 Subject: [PATCH] use proper ser/de --- .../src/server/browserContext.ts | 25 +++++++++++++++++-- .../browsercontext-storage-state.spec.ts | 17 +++++++------ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/packages/playwright-core/src/server/browserContext.ts b/packages/playwright-core/src/server/browserContext.ts index 8733c620b6..2879ad51f5 100644 --- a/packages/playwright-core/src/server/browserContext.ts +++ b/packages/playwright-core/src/server/browserContext.ts @@ -43,6 +43,7 @@ import type { Artifact } from './artifact'; import { Clock } from './clock'; import type { ClientCertificatesProxy } from './socksClientCertificatesInterceptor'; import { RecorderApp } from './recorder/recorderApp'; +import * as utilitySerializers from './isomorphic/utilityScriptSerializers'; export abstract class BrowserContext extends SdkObject { static Events = { @@ -550,7 +551,7 @@ export abstract class BrowserContext extends SdkObject { return { 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. for (const page of this.pages()) { const origin = page.mainFrame().origin(); @@ -597,6 +607,8 @@ export abstract class BrowserContext extends SdkObject { continue; try { const storage = await page.mainFrame().nonStallingEvaluateInExistingContext(`(${_collectStorageScript.toString()})()`, 'utility'); + if (storage.indexedDB?.length) + serializeRecords(storage.indexedDB); if (storage.localStorage.length || storage.indexedDB?.length) result.origins.push({ origin, localStorage: storage.localStorage, indexedDB: storage.indexedDB } as channels.OriginStorage); originsToSave.delete(origin); @@ -617,6 +629,8 @@ export abstract class BrowserContext extends SdkObject { const frame = page.mainFrame(); await frame.goto(internalMetadata, origin); const storage = await frame.evaluateExpression(`(${_collectStorageScript.toString()})()`, { world: 'utility' }); + if (storage.indexedDB?.length) + serializeRecords(storage.indexedDB); if (storage.localStorage.length || storage.indexedDB?.length) 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(); 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) { for (const { name, value } of (originState.localStorage || [])) localStorage.setItem(name, value); @@ -704,7 +725,7 @@ export abstract class BrowserContext extends SdkObject { const objectStore = transaction.objectStore(store.name); return store.records.map(record => new Promise((resolve, reject) => { 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 ); request.addEventListener('success', resolve); diff --git a/tests/library/browsercontext-storage-state.spec.ts b/tests/library/browsercontext-storage-state.spec.ts index 335c1fedbe..40a7dc0fb1 100644 --- a/tests/library/browsercontext-storage-state.spec.ts +++ b/tests/library/browsercontext-storage-state.spec.ts @@ -341,13 +341,16 @@ it('should support IndexedDB', async ({ page, contextFactory }) => { records: [ { value: JSON.stringify({ - taskTitle: 'Pet the cat', - hours: '1', - minutes: '1', - day: '01', - month: 'January', - year: '2025', - notified: 'no', + o: [ + { k: 'taskTitle', v: 'Pet the cat' }, + { k: 'hours', v: '1' }, + { k: 'minutes', v: '1' }, + { k: 'day', v: '01' }, + { k: 'month', v: 'January' }, + { k: 'year', v: '2025' }, + { k: 'notified', v: 'no' } + ], + id: 1 }), }, ],