docs
This commit is contained in:
parent
e26bd2a0c0
commit
da0ad1ef75
|
|
@ -1511,8 +1511,25 @@ Whether to emulate network being offline for the browser context.
|
||||||
- `localStorage` <[Array]<[Object]>>
|
- `localStorage` <[Array]<[Object]>>
|
||||||
- `name` <[string]>
|
- `name` <[string]>
|
||||||
- `value` <[string]>
|
- `value` <[string]>
|
||||||
|
- `indexedDB` <[Array]<[Object]>>
|
||||||
|
- `name` <[string]>
|
||||||
|
- `version` <[int]>
|
||||||
|
- `stores` <[Array]<[Object]>>
|
||||||
|
- `name` <[string]>
|
||||||
|
- `keyPath` ?<[string]>
|
||||||
|
- `keyPathArray` ?<[Array]<[string]>>
|
||||||
|
- `autoIncrement` <[boolean]>
|
||||||
|
- `indexes` <[Array]<[Object]>>
|
||||||
|
- `name` <[string]>
|
||||||
|
- `keyPath` ?<[string]>
|
||||||
|
- `keyPathArray` ?<[Array]<[string]>>
|
||||||
|
- `unique` <[boolean]>
|
||||||
|
- `multiEntry` <[boolean]>
|
||||||
|
- `records` <[Array]<[Object]>>
|
||||||
|
- `key` ?<[string]>
|
||||||
|
- `value` <[string]>
|
||||||
|
|
||||||
Returns storage state for this browser context, contains current cookies and local storage snapshot.
|
Returns storage state for this browser context, contains current cookies, local storage snapshot and IndexedDB snapshot.
|
||||||
|
|
||||||
## async method: BrowserContext.storageState
|
## async method: BrowserContext.storageState
|
||||||
* since: v1.8
|
* since: v1.8
|
||||||
|
|
|
||||||
|
|
@ -265,7 +265,22 @@ Specify environment variables that will be visible to the browser. Defaults to `
|
||||||
- `name` <[string]>
|
- `name` <[string]>
|
||||||
- `value` <[string]>
|
- `value` <[string]>
|
||||||
- `indexedDB` ?<[Array]<[Object]>>
|
- `indexedDB` ?<[Array]<[Object]>>
|
||||||
- `name` <[string]> TODO: document more
|
- `name` <[string]>
|
||||||
|
- `version` <[int]>
|
||||||
|
- `stores` <[Array]<[Object]>>
|
||||||
|
- `name` <[string]>
|
||||||
|
- `keyPath` ?<[string]>
|
||||||
|
- `keyPathArray` ?<[Array]<[string]>>
|
||||||
|
- `autoIncrement` <[boolean]>
|
||||||
|
- `indexes` <[Array]<[Object]>>
|
||||||
|
- `name` <[string]>
|
||||||
|
- `keyPath` ?<[string]>
|
||||||
|
- `keyPathArray` ?<[Array]<[string]>>
|
||||||
|
- `unique` <[boolean]>
|
||||||
|
- `multiEntry` <[boolean]>
|
||||||
|
- `records` <[Array]<[Object]>>
|
||||||
|
- `key` ?<[string]>
|
||||||
|
- `value` <[string]>
|
||||||
|
|
||||||
Learn more about [storage state and auth](../auth.md).
|
Learn more about [storage state and auth](../auth.md).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -325,7 +325,7 @@ pwsh bin/Debug/netX/playwright.ps1 codegen --timezone="Europe/Rome" --geolocatio
|
||||||
|
|
||||||
### Preserve authenticated state
|
### Preserve authenticated state
|
||||||
|
|
||||||
Run `codegen` with `--save-storage` to save [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) and [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) at the end of the session. This is useful to separately record an authentication step and reuse it later when recording more tests.
|
Run `codegen` with `--save-storage` to save [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) and [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) data at the end of the session. This is useful to separately record an authentication step and reuse it later when recording more tests.
|
||||||
|
|
||||||
```bash js
|
```bash js
|
||||||
npx playwright codegen github.com/microsoft/playwright --save-storage=auth.json
|
npx playwright codegen github.com/microsoft/playwright --save-storage=auth.json
|
||||||
|
|
@ -375,7 +375,7 @@ Make sure you only use the `auth.json` locally as it contains sensitive informat
|
||||||
|
|
||||||
#### Load authenticated state
|
#### Load authenticated state
|
||||||
|
|
||||||
Run with `--load-storage` to consume the previously loaded storage from the `auth.json`. This way, all [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) and [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) will be restored, bringing most web apps to the authenticated state without the need to login again. This means you can continue generating tests from the logged in state.
|
Run with `--load-storage` to consume the previously loaded storage from the `auth.json`. This way, all [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) and [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) data will be restored, bringing most web apps to the authenticated state without the need to login again. This means you can continue generating tests from the logged in state.
|
||||||
|
|
||||||
```bash js
|
```bash js
|
||||||
npx playwright codegen --load-storage=auth.json github.com/microsoft/playwright
|
npx playwright codegen --load-storage=auth.json github.com/microsoft/playwright
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ scheme.IndexedDBDatabase = tObject({
|
||||||
scheme.OriginStorage = tObject({
|
scheme.OriginStorage = tObject({
|
||||||
origin: tString,
|
origin: tString,
|
||||||
localStorage: tArray(tType('NameValue')),
|
localStorage: tArray(tType('NameValue')),
|
||||||
indexedDB: tOptional(tArray(tType('IndexedDBDatabase'))),
|
indexedDB: tArray(tType('IndexedDBDatabase')),
|
||||||
});
|
});
|
||||||
scheme.SerializedError = tObject({
|
scheme.SerializedError = tObject({
|
||||||
error: tOptional(tObject({
|
error: tOptional(tObject({
|
||||||
|
|
|
||||||
|
|
@ -515,20 +515,16 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
const originsToSave = new Set(this._origins);
|
const originsToSave = new Set(this._origins);
|
||||||
|
|
||||||
async function _collectStorageScript() {
|
async function _collectStorageScript() {
|
||||||
async function _collectDatabase(dbInfo: IDBDatabaseInfo) {
|
|
||||||
if (!dbInfo.name)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let db: IDBDatabase;
|
const idbResult = await Promise.all((await indexedDB.databases()).map(async dbInfo => {
|
||||||
try {
|
if (!dbInfo.name)
|
||||||
db = await new Promise((resolve, reject) => {
|
throw new Error('Database name is empty');
|
||||||
const request = indexedDB.open(dbInfo.name!);
|
|
||||||
request.onerror = reject;
|
const db = await new Promise<IDBDatabase>((resolve, reject) => {
|
||||||
request.onsuccess = () => resolve(request.result);
|
const request = indexedDB.open(dbInfo.name!);
|
||||||
});
|
request.onerror = reject;
|
||||||
} catch {
|
request.onsuccess = () => resolve(request.result);
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
const transaction = db.transaction(db.objectStoreNames, 'readonly');
|
const transaction = db.transaction(db.objectStoreNames, 'readonly');
|
||||||
const stores = await Promise.all([...db.objectStoreNames].map(async storeName => {
|
const stores = await Promise.all([...db.objectStoreNames].map(async storeName => {
|
||||||
|
|
@ -540,22 +536,19 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
});
|
});
|
||||||
|
|
||||||
const records = await Promise.all(keys.map(async key => {
|
const records = await Promise.all(keys.map(async key => {
|
||||||
const record = await new Promise<any[]>((resolve, reject) => {
|
const record = await new Promise<any>((resolve, reject) => {
|
||||||
const request = objectStore.get(key);
|
const request = objectStore.get(key);
|
||||||
request.addEventListener('success', () => resolve(request.result));
|
request.addEventListener('success', () => resolve(request.result));
|
||||||
request.addEventListener('error', reject);
|
request.addEventListener('error', reject);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!record)
|
|
||||||
return;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
key: objectStore.keyPath === null ? key.toString() : undefined,
|
key: objectStore.keyPath === null ? key.toString() : undefined,
|
||||||
value: record
|
value: record
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const indexes = await Promise.all([...objectStore.indexNames].map(async indexName => {
|
const indexes = [...objectStore.indexNames].map(indexName => {
|
||||||
const index = objectStore.index(indexName);
|
const index = objectStore.index(indexName);
|
||||||
return {
|
return {
|
||||||
name: index.name,
|
name: index.name,
|
||||||
|
|
@ -564,7 +557,7 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
multiEntry: index.multiEntry,
|
multiEntry: index.multiEntry,
|
||||||
unique: index.unique,
|
unique: index.unique,
|
||||||
};
|
};
|
||||||
}));
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: storeName,
|
name: storeName,
|
||||||
|
|
@ -581,13 +574,11 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
version: dbInfo.version,
|
version: dbInfo.version,
|
||||||
stores,
|
stores,
|
||||||
};
|
};
|
||||||
}
|
}));
|
||||||
|
|
||||||
const idbResult = await Promise.all((await indexedDB.databases()).map(_collectDatabase).filter(Boolean));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
localStorage: Object.keys(localStorage).map(name => ({ name, value: localStorage.getItem(name) })),
|
localStorage: Object.keys(localStorage).map(name => ({ name, value: localStorage.getItem(name) })),
|
||||||
indexedDB: idbResult.length ? idbResult : undefined,
|
indexedDB: idbResult,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -607,8 +598,7 @@ 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);
|
||||||
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);
|
||||||
|
|
@ -629,9 +619,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);
|
||||||
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);
|
||||||
}
|
}
|
||||||
await page.close(internalMetadata);
|
await page.close(internalMetadata);
|
||||||
|
|
@ -707,7 +696,7 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
for (const { name, value } of (originState.localStorage || []))
|
for (const { name, value } of (originState.localStorage || []))
|
||||||
localStorage.setItem(name, value);
|
localStorage.setItem(name, value);
|
||||||
|
|
||||||
await Promise.all((originState.indexedDB || []).map(async dbInfo => {
|
await Promise.all(originState.indexedDB.map(async dbInfo => {
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
const openRequest = indexedDB.open(dbInfo.name, dbInfo.version);
|
const openRequest = indexedDB.open(dbInfo.name, dbInfo.version);
|
||||||
openRequest.addEventListener('upgradeneeded', () => {
|
openRequest.addEventListener('upgradeneeded', () => {
|
||||||
|
|
|
||||||
103
packages/playwright-core/types/types.d.ts
vendored
103
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -9260,7 +9260,8 @@ export interface BrowserContext {
|
||||||
setOffline(offline: boolean): Promise<void>;
|
setOffline(offline: boolean): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns storage state for this browser context, contains current cookies and local storage snapshot.
|
* Returns storage state for this browser context, contains current cookies, local storage snapshot and IndexedDB
|
||||||
|
* snapshot.
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
storageState(options?: {
|
storageState(options?: {
|
||||||
|
|
@ -9301,6 +9302,40 @@ export interface BrowserContext {
|
||||||
|
|
||||||
value: string;
|
value: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
indexedDB: Array<{
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
version: number;
|
||||||
|
|
||||||
|
stores: Array<{
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
keyPath?: string;
|
||||||
|
|
||||||
|
keyPathArray?: Array<string>;
|
||||||
|
|
||||||
|
autoIncrement: boolean;
|
||||||
|
|
||||||
|
indexes: Array<{
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
keyPath?: string;
|
||||||
|
|
||||||
|
keyPathArray?: Array<string>;
|
||||||
|
|
||||||
|
unique: boolean;
|
||||||
|
|
||||||
|
multiEntry: boolean;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
records: Array<{
|
||||||
|
key?: string;
|
||||||
|
|
||||||
|
value: string;
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
}>;
|
}>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
@ -10062,10 +10097,37 @@ export interface Browser {
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
indexedDB?: Array<{
|
indexedDB?: Array<{
|
||||||
/**
|
|
||||||
* TODO: document more
|
|
||||||
*/
|
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
|
version: number;
|
||||||
|
|
||||||
|
stores: Array<{
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
keyPath?: string;
|
||||||
|
|
||||||
|
keyPathArray?: Array<string>;
|
||||||
|
|
||||||
|
autoIncrement: boolean;
|
||||||
|
|
||||||
|
indexes: Array<{
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
keyPath?: string;
|
||||||
|
|
||||||
|
keyPathArray?: Array<string>;
|
||||||
|
|
||||||
|
unique: boolean;
|
||||||
|
|
||||||
|
multiEntry: boolean;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
records: Array<{
|
||||||
|
key?: string;
|
||||||
|
|
||||||
|
value: string;
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
}>;
|
}>;
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
|
|
@ -22236,10 +22298,37 @@ export interface BrowserContextOptions {
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
indexedDB?: Array<{
|
indexedDB?: Array<{
|
||||||
/**
|
|
||||||
* TODO: document more
|
|
||||||
*/
|
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
|
version: number;
|
||||||
|
|
||||||
|
stores: Array<{
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
keyPath?: string;
|
||||||
|
|
||||||
|
keyPathArray?: Array<string>;
|
||||||
|
|
||||||
|
autoIncrement: boolean;
|
||||||
|
|
||||||
|
indexes: Array<{
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
keyPath?: string;
|
||||||
|
|
||||||
|
keyPathArray?: Array<string>;
|
||||||
|
|
||||||
|
unique: boolean;
|
||||||
|
|
||||||
|
multiEntry: boolean;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
records: Array<{
|
||||||
|
key?: string;
|
||||||
|
|
||||||
|
value: string;
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
}>;
|
}>;
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
2
packages/protocol/src/channels.d.ts
vendored
2
packages/protocol/src/channels.d.ts
vendored
|
|
@ -296,7 +296,7 @@ export type IndexedDBDatabase = {
|
||||||
export type OriginStorage = {
|
export type OriginStorage = {
|
||||||
origin: string,
|
origin: string,
|
||||||
localStorage: NameValue[],
|
localStorage: NameValue[],
|
||||||
indexedDB?: IndexedDBDatabase[],
|
indexedDB: IndexedDBDatabase[],
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SerializedError = {
|
export type SerializedError = {
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,7 @@ OriginStorage:
|
||||||
type: array
|
type: array
|
||||||
items: NameValue
|
items: NameValue
|
||||||
indexedDB:
|
indexedDB:
|
||||||
type: array?
|
type: array
|
||||||
items: IndexedDBDatabase
|
items: IndexedDBDatabase
|
||||||
|
|
||||||
SerializedError:
|
SerializedError:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue