diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index 5ff432ec60..647fae802e 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -28,7 +28,7 @@ import { Worker } from './worker'; import { Events } from './events'; import { TimeoutSettings } from '../common/timeoutSettings'; import { Waiter } from './waiter'; -import type { Headers, WaitForEventOptions, BrowserContextOptions, StorageState, LaunchOptions } from './types'; +import type { Headers, WaitForEventOptions, BrowserContextOptions, StorageState, LaunchOptions, StorageStateWithIndexedDB } from './types'; import { type URLMatch, headersObjectToArray, isRegExp, isString, urlMatchesEqual, mkdirIfNeeded } from '../utils'; import type * as api from '../../types/types'; import type * as structs from '../../types/structs'; @@ -425,7 +425,7 @@ export class BrowserContext extends ChannelOwner }); } - async storageState(options: { path?: string } = {}): Promise { + async storageState(options: { path?: string } = {}): Promise { const state = await this._channel.storageState(); if (options.path) { await mkdirIfNeeded(options.path); diff --git a/packages/playwright-core/src/client/types.ts b/packages/playwright-core/src/client/types.ts index 11049b2111..50632bf596 100644 --- a/packages/playwright-core/src/client/types.ts +++ b/packages/playwright-core/src/client/types.ts @@ -39,6 +39,10 @@ export type StorageState = { cookies: channels.NetworkCookie[], origins: channels.OriginStorage[] }; +export type StorageStateWithIndexedDB = { + cookies: channels.NetworkCookie[], + origins: channels.OriginStorageWithRequiredIndexedDB[] +}; export type SetStorageState = { cookies?: channels.SetNetworkCookie[], origins?: channels.OriginStorage[] diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index 0db440269c..1986be8b93 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -164,6 +164,11 @@ scheme.IndexedDBDatabase = tObject({ })), }); scheme.OriginStorage = tObject({ + origin: tString, + localStorage: tArray(tType('NameValue')), + indexedDB: tOptional(tArray(tType('IndexedDBDatabase'))), +}); +scheme.OriginStorageWithRequiredIndexedDB = tObject({ origin: tString, localStorage: tArray(tType('NameValue')), indexedDB: tArray(tType('IndexedDBDatabase')), @@ -985,7 +990,7 @@ scheme.BrowserContextSetOfflineResult = tOptional(tObject({})); scheme.BrowserContextStorageStateParams = tOptional(tObject({})); scheme.BrowserContextStorageStateResult = tObject({ cookies: tArray(tType('NetworkCookie')), - origins: tArray(tType('OriginStorage')), + origins: tArray(tType('OriginStorageWithRequiredIndexedDB')), }); scheme.BrowserContextPauseParams = tOptional(tObject({})); scheme.BrowserContextPauseResult = tOptional(tObject({})); diff --git a/packages/playwright-core/src/server/browserContext.ts b/packages/playwright-core/src/server/browserContext.ts index 29e7411676..f97d48f54a 100644 --- a/packages/playwright-core/src/server/browserContext.ts +++ b/packages/playwright-core/src/server/browserContext.ts @@ -600,7 +600,7 @@ export abstract class BrowserContext extends SdkObject { const storage = await page.mainFrame().nonStallingEvaluateInExistingContext(`(${_collectStorageScript.toString()})()`, 'utility'); serializeRecords(storage.indexedDB); 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.OriginStorageWithRequiredIndexedDB); originsToSave.delete(origin); } catch { // When failed on the live page, we'll retry on the blank page below. @@ -621,7 +621,7 @@ export abstract class BrowserContext extends SdkObject { const storage = await frame.evaluateExpression(`(${_collectStorageScript.toString()})()`, { world: 'utility' }); serializeRecords(storage.indexedDB); 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.OriginStorageWithRequiredIndexedDB); } await page.close(internalMetadata); } @@ -696,7 +696,7 @@ export abstract class BrowserContext extends SdkObject { for (const { name, value } of (originState.localStorage || [])) localStorage.setItem(name, value); - await Promise.all(originState.indexedDB.map(async dbInfo => { + await Promise.all((originState.indexedDB ?? []).map(async dbInfo => { await new Promise((resolve, reject) => { const openRequest = indexedDB.open(dbInfo.name, dbInfo.version); openRequest.addEventListener('upgradeneeded', () => { diff --git a/packages/protocol/src/channels.d.ts b/packages/protocol/src/channels.d.ts index e2c53e4e99..954f0096c8 100644 --- a/packages/protocol/src/channels.d.ts +++ b/packages/protocol/src/channels.d.ts @@ -294,6 +294,12 @@ export type IndexedDBDatabase = { }; export type OriginStorage = { + origin: string, + localStorage: NameValue[], + indexedDB?: IndexedDBDatabase[], +}; + +export type OriginStorageWithRequiredIndexedDB = { origin: string, localStorage: NameValue[], indexedDB: IndexedDBDatabase[], @@ -1787,7 +1793,7 @@ export type BrowserContextStorageStateParams = {}; export type BrowserContextStorageStateOptions = {}; export type BrowserContextStorageStateResult = { cookies: NetworkCookie[], - origins: OriginStorage[], + origins: OriginStorageWithRequiredIndexedDB[], }; export type BrowserContextPauseParams = {}; export type BrowserContextPauseOptions = {}; diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index 3b416c4526..f8210c558e 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -255,6 +255,17 @@ IndexedDBDatabase: unique: boolean OriginStorage: + type: object + properties: + origin: string + localStorage: + type: array + items: NameValue + indexedDB: + type: array? + items: IndexedDBDatabase + +OriginStorageWithRequiredIndexedDB: type: object properties: origin: string @@ -1217,7 +1228,7 @@ BrowserContext: items: NetworkCookie origins: type: array - items: OriginStorage + items: OriginStorageWithRequiredIndexedDB pause: experimental: True