chore: TestStorage => TestStore (#19308)
This commit is contained in:
Родитель
405d6267dc
Коммит
1b3e53697b
|
@ -177,13 +177,13 @@ in only once per project and then skip the log in step for all of the tests.
|
|||
|
||||
Web apps use cookie-based or token-based authentication, where authenticated state is stored as [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) or in [local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage). Playwright provides [browserContext.storageState([options])](https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state) method that can be used to retrieve storage state from authenticated contexts and then create new contexts with prepopulated state.
|
||||
|
||||
You can run authentication steps once during the project [`property: TestProject.setup`] phase and save the context state into [TestStorage]. The stored value can later be reused to automatically restore authenticated context state in every test of the project. This way the login will run once per project before all tests.
|
||||
You can run authentication steps once during the project [`property: TestProject.setup`] phase and save the context state into [TestStore]. The stored value can later be reused to automatically restore authenticated context state in every test of the project. This way the login will run once per project before all tests.
|
||||
|
||||
Create a setup test that performs login and saves the context state into project storage:
|
||||
Create a setup test that performs login and saves the context state into project store:
|
||||
|
||||
```js tab=js-js
|
||||
// github-login.setup.js
|
||||
const { setup, storage } = require('@playwright/test');
|
||||
const { setup, store } = require('@playwright/test');
|
||||
|
||||
setup('sign in', async ({ page, context }) => {
|
||||
await page.goto('https://github.com/login');
|
||||
|
@ -193,13 +193,13 @@ setup('sign in', async ({ page, context }) => {
|
|||
|
||||
// Save signed-in state to an entry named 'github-test-user'.
|
||||
const contextState = await context.storageState();
|
||||
await storage.set('github-test-user', contextState)
|
||||
await store.set('github-test-user', contextState)
|
||||
});
|
||||
```
|
||||
|
||||
```js tab=js-ts
|
||||
// github-login.setup.ts
|
||||
import { setup, storage } from '@playwright/setup';
|
||||
import { setup, store } from '@playwright/setup';
|
||||
|
||||
setup('sign in', async ({ page, context }) => {
|
||||
await page.goto('https://github.com/login');
|
||||
|
@ -209,7 +209,7 @@ setup('sign in', async ({ page, context }) => {
|
|||
|
||||
// Save signed-in state to an entry named 'github-test-user'.
|
||||
const contextState = await context.storageState();
|
||||
await storage.set('github-test-user', contextState)
|
||||
await store.set('github-test-user', contextState)
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -276,33 +276,33 @@ test('test', async ({ page }) => {
|
|||
### Reusing signed in state between test runs
|
||||
* langs: js
|
||||
|
||||
When you set an entry on [TestStorage] Playwright will store it in a separate file under `.playwright-storage/`. Playwright does not delete those files automatically. You can leverage this fact to persist storage state between test runs and only sign in if the entry is not in the storage yet.
|
||||
When you set an entry on [TestStore] Playwright will store it in a separate file under `.playwright-store/`. Playwright does not delete those files automatically. You can leverage this fact to persist storage state between test runs and only sign in if the entry is not in the store yet.
|
||||
|
||||
```js tab=js-js
|
||||
// github-login.setup.js
|
||||
const { setup, storage } = require('@playwright/test');
|
||||
const { setup, store } = require('@playwright/test');
|
||||
|
||||
setup('sign in', async ({ page, context }) => {
|
||||
if (storage.get('github-test-user'))
|
||||
return;
|
||||
// ... login here ...
|
||||
await storage.set('github-test-user', await context.storageState());
|
||||
await store.set('github-test-user', await context.storageState());
|
||||
});
|
||||
```
|
||||
|
||||
```js tab=js-ts
|
||||
// github-login.setup.ts
|
||||
import { setup, storage } from '@playwright/test';
|
||||
import { setup, store } from '@playwright/test';
|
||||
|
||||
setup('sign in', async ({ page, context }) => {
|
||||
if (storage.get('github-test-user'))
|
||||
return;
|
||||
// ... login here ...
|
||||
await storage.set('github-test-user', await context.storageState());
|
||||
await store.set('github-test-user', await context.storageState());
|
||||
});
|
||||
```
|
||||
|
||||
You may need to periodically update the storage state entry if your app requires you to re-authenticate after some amount of time. For example, if your app prompts you to sign in every week even if you're on the same computer/browser, you'll need to update saved storage state at least this often. You can simply delete `.playwright-storage/` directory to clear the storage and run the tests again so that they populate it.
|
||||
You may need to periodically update the storage state entry if your app requires you to re-authenticate after some amount of time. For example, if your app prompts you to sign in every week even if you're on the same computer/browser, you'll need to update saved storage state at least this often. You can simply delete `.playwright-store/` directory to clear the store and run the tests again so that they populate it.
|
||||
|
||||
### Sign in via API request
|
||||
* langs: js
|
||||
|
@ -311,7 +311,7 @@ If your web application supports signing in via API, you can use [APIRequestCont
|
|||
|
||||
```js tab=js-js
|
||||
// github-login.setup.js
|
||||
const { setup, storage } = require('@playwright/test');
|
||||
const { setup, store } = require('@playwright/test');
|
||||
|
||||
setup('sign in', async ({ request }) => {
|
||||
await request.post('https://github.com/login', {
|
||||
|
@ -322,13 +322,13 @@ setup('sign in', async ({ request }) => {
|
|||
});
|
||||
// Save signed-in state to an entry named 'github-test-user'.
|
||||
const contextState = await request.storageState();
|
||||
await storage.set('github-test-user', contextState)
|
||||
await store.set('github-test-user', contextState)
|
||||
});
|
||||
```
|
||||
|
||||
```js tab=js-ts
|
||||
// github-login.setup.ts
|
||||
import { setup, storage } from '@playwright/test';
|
||||
import { setup, store } from '@playwright/test';
|
||||
|
||||
setup('sign in', async ({ request }) => {
|
||||
await request.post('https://github.com/login', {
|
||||
|
@ -339,7 +339,7 @@ setup('sign in', async ({ request }) => {
|
|||
});
|
||||
// Save signed-in state to an entry named 'github-test-user'.
|
||||
const contextState = await request.storageState();
|
||||
await storage.set('github-test-user', contextState)
|
||||
await store.set('github-test-user', contextState)
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -352,7 +352,7 @@ In this example we [override `storageState` fixture](./test-fixtures.md#overridi
|
|||
|
||||
```js tab=js-js
|
||||
// login-fixture.js
|
||||
const { test: base, storage } = require('@playwright/test');
|
||||
const { test: base, store } = require('@playwright/test');
|
||||
|
||||
const users = [
|
||||
{ username: 'user-1', password: 'password-1' },
|
||||
|
@ -362,7 +362,7 @@ const users = [
|
|||
|
||||
exports.test = base.extend({
|
||||
// Sign in corresponding user during test worker startup and save the state
|
||||
// to storage.
|
||||
// to store.
|
||||
login: [async ({ browser }, use) => {
|
||||
const page = await browser.newPage();
|
||||
await page.goto('https://github.com/login');
|
||||
|
@ -373,8 +373,8 @@ exports.test = base.extend({
|
|||
await page.getByText('Sign in').click();
|
||||
|
||||
const contextState = await page.context().storageState();
|
||||
// Store with worker-specific key.
|
||||
await storage.set(`test-user-${index}`, contextState);
|
||||
// Save with a worker-specific key.
|
||||
await store.set(`test-user-${index}`, contextState);
|
||||
|
||||
await page.close();
|
||||
await use();
|
||||
|
@ -382,7 +382,7 @@ exports.test = base.extend({
|
|||
});
|
||||
|
||||
exports.expect = base.expect;
|
||||
exporta.storage = base.storage;
|
||||
exporta.store = base.store;
|
||||
|
||||
// example.spec.js
|
||||
const { test, expect } = require('./login-fixture');
|
||||
|
@ -399,7 +399,7 @@ test('test', async ({ page }) => {
|
|||
|
||||
```js tab=js-ts
|
||||
// login-fixture.ts
|
||||
import { test as base, storage } from '@playwright/test';
|
||||
import { test as base, store } from '@playwright/test';
|
||||
|
||||
const users = [
|
||||
{ username: 'user-1', password: 'password-1' },
|
||||
|
@ -409,7 +409,7 @@ const users = [
|
|||
|
||||
export const test = base.extend<{ login: void }>({
|
||||
// Sign in corresponding user during test worker startup and save the state
|
||||
// to storage.
|
||||
// to the store.
|
||||
login: [async ({ browser }, use) => {
|
||||
const page = await browser.newPage();
|
||||
await page.goto('https://github.com/login');
|
||||
|
@ -420,8 +420,8 @@ export const test = base.extend<{ login: void }>({
|
|||
await page.getByText('Sign in').click();
|
||||
|
||||
const contextState = await page.context().storageState();
|
||||
// Store with worker-specific key.
|
||||
await storage.set(`test-user-${index}`, contextState);
|
||||
// Save with a worker-specific key.
|
||||
await store.set(`test-user-${index}`, contextState);
|
||||
|
||||
await page.close();
|
||||
await use();
|
||||
|
@ -449,7 +449,7 @@ Sometimes you have more than one signed-in user in your end to end tests. You ca
|
|||
|
||||
```js tab=js-js
|
||||
// login.setup.js
|
||||
const { setup, storage } = require('@playwright/test');
|
||||
const { setup, store } = require('@playwright/test');
|
||||
|
||||
// Run all logins in parallel.
|
||||
setup.describe.configure({
|
||||
|
@ -462,7 +462,7 @@ setup(`login as regular user`, async ({ page }) => {
|
|||
|
||||
const contextState = await page.context().storageState();
|
||||
// Save the user state.
|
||||
await storage.set(`user`, contextState);
|
||||
await store.set(`user`, contextState);
|
||||
});
|
||||
|
||||
setup(`login as admin`, async ({ page }) => {
|
||||
|
@ -471,13 +471,13 @@ setup(`login as admin`, async ({ page }) => {
|
|||
|
||||
const contextState = await page.context().storageState();
|
||||
// Save the admin state.
|
||||
await storage.set(`admin`, contextState);
|
||||
await store.set(`admin`, contextState);
|
||||
});
|
||||
```
|
||||
|
||||
```js tab=js-ts
|
||||
// login.setup.ts
|
||||
import { setup, storage } from '@playwright/test';
|
||||
import { setup, store } from '@playwright/test';
|
||||
|
||||
// Run all logins in parallel.
|
||||
setup.describe.configure({
|
||||
|
@ -490,7 +490,7 @@ setup(`login as regular user`, async ({ page }) => {
|
|||
|
||||
const contextState = await page.context().storageState();
|
||||
// Save the user state.
|
||||
await storage.set(`user`, contextState);
|
||||
await store.set(`user`, contextState);
|
||||
});
|
||||
|
||||
setup(`login as admin`, async ({ page }) => {
|
||||
|
@ -499,7 +499,7 @@ setup(`login as admin`, async ({ page }) => {
|
|||
|
||||
const contextState = await page.context().storageState();
|
||||
// Save the admin state.
|
||||
await storage.set(`admin`, contextState);
|
||||
await store.set(`admin`, contextState);
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -547,15 +547,15 @@ test.describe(() => {
|
|||
If you need to test how multiple authenticated roles interact together, use multiple [BrowserContext]s and [Page]s with different storage states in the same test. Any of the methods above to create multiple storage state entries would work.
|
||||
|
||||
```js tab=js-ts
|
||||
import { test, storage } from '@playwright/test';
|
||||
import { test, store } from '@playwright/test';
|
||||
|
||||
test('admin and user', async ({ browser }) => {
|
||||
// adminContext and all pages inside, including adminPage, are signed in as "admin".
|
||||
const adminContext = await browser.newContext({ storageState: await storage.get('admin') });
|
||||
const adminContext = await browser.newContext({ storageState: await store.get('admin') });
|
||||
const adminPage = await adminContext.newPage();
|
||||
|
||||
// userContext and all pages inside, including userPage, are signed in as "user".
|
||||
const userContext = await browser.newContext({ storageState: await storage.get('user') });
|
||||
const userContext = await browser.newContext({ storageState: await store.get('user') });
|
||||
const userPage = await userContext.newPage();
|
||||
|
||||
// ... interact with both adminPage and userPage ...
|
||||
|
@ -563,15 +563,15 @@ test('admin and user', async ({ browser }) => {
|
|||
```
|
||||
|
||||
```js tab=js-js
|
||||
const { test, storage } = require('@playwright/test');
|
||||
const { test, store } = require('@playwright/test');
|
||||
|
||||
test('admin and user', async ({ browser }) => {
|
||||
// adminContext and all pages inside, including adminPage, are signed in as "admin".
|
||||
const adminContext = await browser.newContext({ storageState: await storage.get('admin') });
|
||||
const adminContext = await browser.newContext({ storageState: await store.get('admin') });
|
||||
const adminPage = await adminContext.newPage();
|
||||
|
||||
// userContext and all pages inside, including userPage, are signed in as "user".
|
||||
const userContext = await browser.newContext({ storageState: await storage.get('user') });
|
||||
const userContext = await browser.newContext({ storageState: await store.get('user') });
|
||||
const userPage = await userContext.newPage();
|
||||
|
||||
// ... interact with both adminPage and userPage ...
|
||||
|
@ -588,7 +588,7 @@ Below is an example that [creates fixtures](./test-fixtures.md#creating-a-fixtur
|
|||
```js tab=js-ts
|
||||
// fixtures.ts
|
||||
import { test as base, Page, Browser, Locator } from '@playwright/test';
|
||||
export { expect, storage } from '@playwright/test';
|
||||
export { expect, store } from '@playwright/test';
|
||||
|
||||
// Page Object Model for the "admin" page.
|
||||
// Here you can add locators and helper methods specific to the admin page.
|
||||
|
@ -601,7 +601,7 @@ class AdminPage {
|
|||
}
|
||||
|
||||
static async create(browser: Browser) {
|
||||
const context = await browser.newContext({ storageState: await storage.get('admin') });
|
||||
const context = await browser.newContext({ storageState: await store.get('admin') });
|
||||
const page = await context.newPage();
|
||||
return new AdminPage(page);
|
||||
}
|
||||
|
@ -622,7 +622,7 @@ class UserPage {
|
|||
}
|
||||
|
||||
static async create(browser: Browser) {
|
||||
const context = await browser.newContext({ storageState: await storage.get('user') });
|
||||
const context = await browser.newContext({ storageState: await store.get('user') });
|
||||
const page = await context.newPage();
|
||||
return new UserPage(page);
|
||||
}
|
||||
|
@ -659,7 +659,7 @@ test('admin and user', async ({ adminPage, userPage }) => {
|
|||
|
||||
```js tab=js-js
|
||||
// fixtures.js
|
||||
const { test: base, storage } = require('@playwright/test');
|
||||
const { test: base, store } = require('@playwright/test');
|
||||
|
||||
// Page Object Model for the "admin" page.
|
||||
// Here you can add locators and helper methods specific to the admin page.
|
||||
|
@ -670,7 +670,7 @@ class AdminPage {
|
|||
}
|
||||
|
||||
static async create(browser) {
|
||||
const context = await browser.newContext({ storageState: await storage.get('admin') });
|
||||
const context = await browser.newContext({ storageState: await store.get('admin') });
|
||||
const page = await context.newPage();
|
||||
return new AdminPage(page);
|
||||
}
|
||||
|
@ -687,7 +687,7 @@ class UserPage {
|
|||
}
|
||||
|
||||
static async create(browser) {
|
||||
const context = await browser.newContext({ storageState: await storage.get('user') });
|
||||
const context = await browser.newContext({ storageState: await store.get('user') });
|
||||
const page = await context.newPage();
|
||||
return new UserPage(page);
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ Learn more about [automatic screenshots](../test-configuration.md#automatic-scre
|
|||
* since: v1.29
|
||||
- type: <[string]>
|
||||
|
||||
Name of the [TestStorage] entry that should be used to initialize [`property: TestOptions.storageState`]. The value must be
|
||||
Name of the [TestStore] entry that should be used to initialize [`property: TestOptions.storageState`]. The value must be
|
||||
written to the test storage before creation of a browser context that uses it (usually in [`property: TestProject.setup`]). If both
|
||||
this property and [`property: TestOptions.storageState`] are specified, this property will always take precedence.
|
||||
|
||||
|
|
|
@ -1,54 +1,54 @@
|
|||
# class: TestStorage
|
||||
# class: TestStore
|
||||
* since: v1.29
|
||||
* langs: js
|
||||
|
||||
Playwright Test provides a global `storage` object for passing values between project setup and tests. It is
|
||||
an error to call storage methods outside of setup and tests.
|
||||
Playwright Test provides a global `store` object for passing values between project setup and tests. It is
|
||||
an error to call store methods outside of setup and tests.
|
||||
|
||||
```js tab=js-js
|
||||
const { setup, storage } = require('@playwright/test');
|
||||
const { setup, store } = require('@playwright/test');
|
||||
|
||||
setup('sign in', async ({ page, context }) => {
|
||||
// Save signed-in state to an entry named 'github-test-user'.
|
||||
const contextState = await context.storageState();
|
||||
await storage.set('test-user', contextState)
|
||||
await store.set('test-user', contextState)
|
||||
});
|
||||
```
|
||||
|
||||
```js tab=js-ts
|
||||
import { setup, storage } from '@playwright/test';
|
||||
import { setup, store } from '@playwright/test';
|
||||
|
||||
setup('sign in', async ({ page, context }) => {
|
||||
// Save signed-in state to an entry named 'github-test-user'.
|
||||
const contextState = await context.storageState();
|
||||
await storage.set('test-user', contextState)
|
||||
await store.set('test-user', contextState)
|
||||
});
|
||||
```
|
||||
|
||||
## async method: TestStorage.get
|
||||
## async method: TestStore.get
|
||||
* since: v1.29
|
||||
- returns: <[any]>
|
||||
|
||||
Get named item from the storage. Returns undefined if there is no value with given name.
|
||||
Get named item from the store. Returns undefined if there is no value with given name.
|
||||
|
||||
### param: TestStorage.get.name
|
||||
### param: TestStore.get.name
|
||||
* since: v1.29
|
||||
- `name` <[string]>
|
||||
|
||||
Item name.
|
||||
|
||||
## async method: TestStorage.set
|
||||
## async method: TestStore.set
|
||||
* since: v1.29
|
||||
|
||||
Set value to the storage.
|
||||
Set value to the store.
|
||||
|
||||
### param: TestStorage.set.name
|
||||
### param: TestStore.set.name
|
||||
* since: v1.29
|
||||
- `name` <[string]>
|
||||
|
||||
Item name.
|
||||
|
||||
### param: TestStorage.set.value
|
||||
### param: TestStore.set.value
|
||||
* since: v1.29
|
||||
- `value` <[any]>
|
||||
|
|
@ -22,13 +22,13 @@ import * as outOfProcess from 'playwright-core/lib/outofprocess';
|
|||
import { createGuid, debugMode } from 'playwright-core/lib/utils';
|
||||
import { removeFolders } from 'playwright-core/lib/utils/fileUtils';
|
||||
import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo, TestType, TraceMode, VideoMode } from '../types/test';
|
||||
import { storage as _baseStorage } from './storage';
|
||||
import { store as _baseStore } from './store';
|
||||
import type { TestInfoImpl } from './testInfo';
|
||||
import { rootTestType, _setProjectSetup } from './testType';
|
||||
export { expect } from './expect';
|
||||
export { addRunnerPlugin as _addRunnerPlugin } from './plugins';
|
||||
export const _baseTest: TestType<{}, {}> = rootTestType.test;
|
||||
export const storage = _baseStorage;
|
||||
export const store = _baseStore;
|
||||
|
||||
if ((process as any)['__pw_initiator__']) {
|
||||
const originalStackTraceLimit = Error.stackTraceLimit;
|
||||
|
@ -223,9 +223,9 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
|||
if (proxy !== undefined)
|
||||
options.proxy = proxy;
|
||||
if (storageStateName !== undefined) {
|
||||
const value = await storage.get(storageStateName);
|
||||
const value = await store.get(storageStateName);
|
||||
if (!value)
|
||||
throw new Error(`Cannot find value in the storage for storageStateName: "${storageStateName}"`);
|
||||
throw new Error(`Cannot find value in the store for storageStateName: "${storageStateName}"`);
|
||||
options.storageState = value as any;
|
||||
} else if (storageState !== undefined) {
|
||||
options.storageState = storageState;
|
||||
|
|
|
@ -119,7 +119,7 @@ export class Loader {
|
|||
config.snapshotDir = path.resolve(configDir, config.snapshotDir);
|
||||
|
||||
this._fullConfig._configDir = configDir;
|
||||
this._fullConfig._storageDir = path.resolve(configDir, '.playwright-storage');
|
||||
this._fullConfig._storeDir = path.resolve(configDir, '.playwright-store');
|
||||
this._fullConfig.configFile = this._configFile;
|
||||
this._fullConfig.rootDir = config.testDir || this._configDir;
|
||||
this._fullConfig._globalOutputDir = takeFirst(config.outputDir, throwawayArtifactsPath, baseFullConfig._globalOutputDir);
|
||||
|
@ -665,7 +665,7 @@ export const baseFullConfig: FullConfigInternal = {
|
|||
_webServers: [],
|
||||
_globalOutputDir: path.resolve(process.cwd()),
|
||||
_configDir: '',
|
||||
_storageDir: '',
|
||||
_storeDir: '',
|
||||
_maxConcurrentTestGroups: 0,
|
||||
_ignoreSnapshots: false,
|
||||
_workerIsolation: 'isolate-pools',
|
||||
|
|
|
@ -16,17 +16,17 @@
|
|||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import type { TestStorage } from '../types/test';
|
||||
import type { TestStore } from '../types/test';
|
||||
import { currentTestInfo } from './globals';
|
||||
import { sanitizeForFilePath, trimLongString } from './util';
|
||||
|
||||
class JsonStorage implements TestStorage {
|
||||
class JsonStore implements TestStore {
|
||||
private _toFilePath(name: string) {
|
||||
const testInfo = currentTestInfo();
|
||||
if (!testInfo)
|
||||
throw new Error('storage can only be called while test is running');
|
||||
throw new Error('store can only be called while test is running');
|
||||
const fileName = sanitizeForFilePath(trimLongString(name)) + '.json';
|
||||
return path.join(testInfo.config._storageDir, testInfo.project._id, fileName);
|
||||
return path.join(testInfo.config._storeDir, testInfo.project._id, fileName);
|
||||
}
|
||||
|
||||
async get<T>(name: string) {
|
||||
|
@ -51,4 +51,4 @@ class JsonStorage implements TestStorage {
|
|||
}
|
||||
}
|
||||
|
||||
export const storage = new JsonStorage();
|
||||
export const store = new JsonStore();
|
|
@ -44,7 +44,7 @@ export interface TestStepInternal {
|
|||
export interface FullConfigInternal extends FullConfigPublic {
|
||||
_globalOutputDir: string;
|
||||
_configDir: string;
|
||||
_storageDir: string;
|
||||
_storeDir: string;
|
||||
_maxConcurrentTestGroups: number;
|
||||
_ignoreSnapshots: boolean;
|
||||
_workerIsolation: WorkerIsolation;
|
||||
|
|
|
@ -2844,28 +2844,28 @@ type ConnectOptions = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Playwright Test provides a global `storage` object for passing values between project setup and tests. It is an
|
||||
* error to call storage methods outside of setup and tests.
|
||||
* Playwright Test provides a global `store` object for passing values between project setup and tests. It is an error
|
||||
* to call store methods outside of setup and tests.
|
||||
*
|
||||
* ```js
|
||||
* import { setup, storage } from '@playwright/test';
|
||||
* import { setup, store } from '@playwright/test';
|
||||
*
|
||||
* setup('sign in', async ({ page, context }) => {
|
||||
* // Save signed-in state to an entry named 'github-test-user'.
|
||||
* const contextState = await context.storageState();
|
||||
* await storage.set('test-user', contextState)
|
||||
* await store.set('test-user', contextState)
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
export interface TestStorage {
|
||||
export interface TestStore {
|
||||
/**
|
||||
* Get named item from the storage. Returns undefined if there is no value with given name.
|
||||
* Get named item from the store. Returns undefined if there is no value with given name.
|
||||
* @param name Item name.
|
||||
*/
|
||||
get<T>(name: string): Promise<T | undefined>;
|
||||
/**
|
||||
* Set value to the storage.
|
||||
* Set value to the store.
|
||||
* @param name Item name.
|
||||
* @param value Item value. The value must be serializable to JSON. Passing `undefined` deletes the entry with given name.
|
||||
*/
|
||||
|
@ -3108,7 +3108,7 @@ export interface PlaywrightTestOptions {
|
|||
*/
|
||||
storageState: StorageState | undefined;
|
||||
/**
|
||||
* Name of the [TestStorage] entry that should be used to initialize
|
||||
* Name of the [TestStore] entry that should be used to initialize
|
||||
* [testOptions.storageState](https://playwright.dev/docs/api/class-testoptions#test-options-storage-state). The value
|
||||
* must be written to the test storage before creation of a browser context that uses it (usually in
|
||||
* [testProject.setup](https://playwright.dev/docs/api/class-testproject#test-project-setup)). If both this property
|
||||
|
@ -3393,7 +3393,7 @@ export default test;
|
|||
|
||||
export const _baseTest: TestType<{}, {}>;
|
||||
export const expect: Expect;
|
||||
export const storage: TestStorage;
|
||||
export const store: TestStore;
|
||||
|
||||
// This is required to not export everything by default. See https://github.com/Microsoft/TypeScript/issues/19545#issuecomment-340490459
|
||||
export {};
|
||||
|
|
|
@ -16,24 +16,24 @@
|
|||
|
||||
import { expect, test } from './playwright-test-fixtures';
|
||||
|
||||
test('should provide storage fixture', async ({ runInlineTest }) => {
|
||||
test('should provide store fixture', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.js': `
|
||||
module.exports = {};
|
||||
`,
|
||||
'a.test.ts': `
|
||||
const { test, storage } = pwt;
|
||||
const { test, store } = pwt;
|
||||
test('should store number', async ({ }) => {
|
||||
expect(storage).toBeTruthy();
|
||||
expect(await storage.get('number')).toBe(undefined);
|
||||
await storage.set('number', 2022)
|
||||
expect(await storage.get('number')).toBe(2022);
|
||||
expect(store).toBeTruthy();
|
||||
expect(await store.get('number')).toBe(undefined);
|
||||
await store.set('number', 2022)
|
||||
expect(await store.get('number')).toBe(2022);
|
||||
});
|
||||
test('should store object', async ({ }) => {
|
||||
expect(storage).toBeTruthy();
|
||||
expect(await storage.get('object')).toBe(undefined);
|
||||
await storage.set('object', { 'a': 2022 })
|
||||
expect(await storage.get('object')).toEqual({ 'a': 2022 });
|
||||
expect(store).toBeTruthy();
|
||||
expect(await store.get('object')).toBe(undefined);
|
||||
await store.set('object', { 'a': 2022 })
|
||||
expect(await store.get('object')).toEqual({ 'a': 2022 });
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
@ -41,42 +41,42 @@ test('should provide storage fixture', async ({ runInlineTest }) => {
|
|||
expect(result.passed).toBe(2);
|
||||
});
|
||||
|
||||
test('should share storage state between project setup and tests', async ({ runInlineTest }) => {
|
||||
test('should share store state between project setup and tests', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.js': `
|
||||
module.exports = {
|
||||
projects: [
|
||||
{
|
||||
name: 'p1',
|
||||
setup: /.*storage.setup.ts/
|
||||
setup: /.*store.setup.ts/
|
||||
}
|
||||
]
|
||||
};
|
||||
`,
|
||||
'storage.setup.ts': `
|
||||
const { setup, expect, storage } = pwt;
|
||||
setup('should initialize storage', async ({ }) => {
|
||||
expect(await storage.get('number')).toBe(undefined);
|
||||
await storage.set('number', 2022)
|
||||
expect(await storage.get('number')).toBe(2022);
|
||||
'store.setup.ts': `
|
||||
const { setup, expect, store } = pwt;
|
||||
setup('should initialize store', async ({ }) => {
|
||||
expect(await store.get('number')).toBe(undefined);
|
||||
await store.set('number', 2022)
|
||||
expect(await store.get('number')).toBe(2022);
|
||||
|
||||
expect(await storage.get('object')).toBe(undefined);
|
||||
await storage.set('object', { 'a': 2022 })
|
||||
expect(await storage.get('object')).toEqual({ 'a': 2022 });
|
||||
expect(await store.get('object')).toBe(undefined);
|
||||
await store.set('object', { 'a': 2022 })
|
||||
expect(await store.get('object')).toEqual({ 'a': 2022 });
|
||||
});
|
||||
`,
|
||||
'a.test.ts': `
|
||||
const { test, storage } = pwt;
|
||||
const { test, store } = pwt;
|
||||
test('should get data from setup', async ({ }) => {
|
||||
expect(await storage.get('number')).toBe(2022);
|
||||
expect(await storage.get('object')).toEqual({ 'a': 2022 });
|
||||
expect(await store.get('number')).toBe(2022);
|
||||
expect(await store.get('object')).toEqual({ 'a': 2022 });
|
||||
});
|
||||
`,
|
||||
'b.test.ts': `
|
||||
const { test, storage } = pwt;
|
||||
const { test, store } = pwt;
|
||||
test('should get data from setup', async ({ }) => {
|
||||
expect(await storage.get('number')).toBe(2022);
|
||||
expect(await storage.get('object')).toEqual({ 'a': 2022 });
|
||||
expect(await store.get('number')).toBe(2022);
|
||||
expect(await store.get('object')).toEqual({ 'a': 2022 });
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
@ -84,25 +84,25 @@ test('should share storage state between project setup and tests', async ({ runI
|
|||
expect(result.passed).toBe(3);
|
||||
});
|
||||
|
||||
test('should persist storage state between project runs', async ({ runInlineTest }) => {
|
||||
test('should persist store state between project runs', async ({ runInlineTest }) => {
|
||||
const files = {
|
||||
'playwright.config.js': `
|
||||
module.exports = { };
|
||||
`,
|
||||
'a.test.ts': `
|
||||
const { test, storage } = pwt;
|
||||
const { test, store } = pwt;
|
||||
test('should have no data on first run', async ({ }) => {
|
||||
expect(await storage.get('number')).toBe(undefined);
|
||||
await storage.set('number', 2022)
|
||||
expect(await storage.get('object')).toBe(undefined);
|
||||
await storage.set('object', { 'a': 2022 })
|
||||
expect(await store.get('number')).toBe(undefined);
|
||||
await store.set('number', 2022)
|
||||
expect(await store.get('object')).toBe(undefined);
|
||||
await store.set('object', { 'a': 2022 })
|
||||
});
|
||||
`,
|
||||
'b.test.ts': `
|
||||
const { test, storage } = pwt;
|
||||
const { test, store } = pwt;
|
||||
test('should get data from previous run', async ({ }) => {
|
||||
expect(await storage.get('number')).toBe(2022);
|
||||
expect(await storage.get('object')).toEqual({ 'a': 2022 });
|
||||
expect(await store.get('number')).toBe(2022);
|
||||
expect(await store.get('object')).toEqual({ 'a': 2022 });
|
||||
});
|
||||
`,
|
||||
};
|
||||
|
@ -118,46 +118,46 @@ test('should persist storage state between project runs', async ({ runInlineTest
|
|||
}
|
||||
});
|
||||
|
||||
test('should isolate storage state between projects', async ({ runInlineTest }) => {
|
||||
test('should isolate store state between projects', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.js': `
|
||||
module.exports = {
|
||||
projects: [
|
||||
{
|
||||
name: 'p1',
|
||||
setup: /.*storage.setup.ts/
|
||||
setup: /.*store.setup.ts/
|
||||
},
|
||||
{
|
||||
name: 'p2',
|
||||
setup: /.*storage.setup.ts/
|
||||
setup: /.*store.setup.ts/
|
||||
}
|
||||
]
|
||||
};
|
||||
`,
|
||||
'storage.setup.ts': `
|
||||
const { setup, expect, storage } = pwt;
|
||||
setup('should initialize storage', async ({ }) => {
|
||||
expect(await storage.get('number')).toBe(undefined);
|
||||
await storage.set('number', 2022)
|
||||
expect(await storage.get('number')).toBe(2022);
|
||||
'store.setup.ts': `
|
||||
const { setup, expect, store } = pwt;
|
||||
setup('should initialize store', async ({ }) => {
|
||||
expect(await store.get('number')).toBe(undefined);
|
||||
await store.set('number', 2022)
|
||||
expect(await store.get('number')).toBe(2022);
|
||||
|
||||
expect(await storage.get('name')).toBe(undefined);
|
||||
await storage.set('name', 'str-' + setup.info().project.name)
|
||||
expect(await storage.get('name')).toBe('str-' + setup.info().project.name);
|
||||
expect(await store.get('name')).toBe(undefined);
|
||||
await store.set('name', 'str-' + setup.info().project.name)
|
||||
expect(await store.get('name')).toBe('str-' + setup.info().project.name);
|
||||
});
|
||||
`,
|
||||
'a.test.ts': `
|
||||
const { test, storage } = pwt;
|
||||
const { test, store } = pwt;
|
||||
test('should get data from setup', async ({ }) => {
|
||||
expect(await storage.get('number')).toBe(2022);
|
||||
expect(await storage.get('name')).toBe('str-' + test.info().project.name);
|
||||
expect(await store.get('number')).toBe(2022);
|
||||
expect(await store.get('name')).toBe('str-' + test.info().project.name);
|
||||
});
|
||||
`,
|
||||
'b.test.ts': `
|
||||
const { test, storage } = pwt;
|
||||
const { test, store } = pwt;
|
||||
test('should get data from setup', async ({ }) => {
|
||||
expect(await storage.get('number')).toBe(2022);
|
||||
expect(await storage.get('name')).toBe('str-' + test.info().project.name);
|
||||
expect(await store.get('number')).toBe(2022);
|
||||
expect(await store.get('name')).toBe('str-' + test.info().project.name);
|
||||
});
|
||||
`,
|
||||
}, { workers: 2 });
|
||||
|
@ -165,7 +165,7 @@ test('should isolate storage state between projects', async ({ runInlineTest })
|
|||
expect(result.passed).toBe(6);
|
||||
});
|
||||
|
||||
test('should load context storageState from storage', async ({ runInlineTest, server }) => {
|
||||
test('should load context storageState from store', async ({ runInlineTest, server }) => {
|
||||
server.setRoute('/setcookie.html', (req, res) => {
|
||||
res.setHeader('Set-Cookie', ['a=v1']);
|
||||
res.end();
|
||||
|
@ -176,18 +176,18 @@ test('should load context storageState from storage', async ({ runInlineTest, se
|
|||
projects: [
|
||||
{
|
||||
name: 'p1',
|
||||
setup: /.*storage.setup.ts/
|
||||
setup: /.*store.setup.ts/
|
||||
}
|
||||
]
|
||||
};
|
||||
`,
|
||||
'storage.setup.ts': `
|
||||
const { setup, expect, storage } = pwt;
|
||||
'store.setup.ts': `
|
||||
const { setup, expect, store } = pwt;
|
||||
setup('should save storageState', async ({ page, context }) => {
|
||||
expect(await storage.get('user')).toBe(undefined);
|
||||
expect(await store.get('user')).toBe(undefined);
|
||||
await page.goto('${server.PREFIX}/setcookie.html');
|
||||
const state = await page.context().storageState();
|
||||
await storage.set('user', state);
|
||||
await store.set('user', state);
|
||||
});
|
||||
`,
|
||||
'a.test.ts': `
|
||||
|
@ -214,7 +214,7 @@ test('should load context storageState from storage', async ({ runInlineTest, se
|
|||
expect(result.passed).toBe(3);
|
||||
});
|
||||
|
||||
test('should load storageStateName specified in the project config from storage', async ({ runInlineTest, server }) => {
|
||||
test('should load storageStateName specified in the project config from store', async ({ runInlineTest, server }) => {
|
||||
server.setRoute('/setcookie.html', (req, res) => {
|
||||
res.setHeader('Set-Cookie', ['a=v1']);
|
||||
res.end();
|
||||
|
@ -225,7 +225,7 @@ test('should load storageStateName specified in the project config from storage'
|
|||
projects: [
|
||||
{
|
||||
name: 'p1',
|
||||
setup: /.*storage.setup.ts/,
|
||||
setup: /.*store.setup.ts/,
|
||||
use: {
|
||||
storageStateName: 'stateInStorage',
|
||||
},
|
||||
|
@ -233,16 +233,16 @@ test('should load storageStateName specified in the project config from storage'
|
|||
]
|
||||
};
|
||||
`,
|
||||
'storage.setup.ts': `
|
||||
const { setup, expect, storage } = pwt;
|
||||
'store.setup.ts': `
|
||||
const { setup, expect, store } = pwt;
|
||||
setup.use({
|
||||
storageStateName: ({}, use) => use(undefined),
|
||||
})
|
||||
setup('should save storageState', async ({ page, context }) => {
|
||||
expect(await storage.get('stateInStorage')).toBe(undefined);
|
||||
expect(await store.get('stateInStorage')).toBe(undefined);
|
||||
await page.goto('${server.PREFIX}/setcookie.html');
|
||||
const state = await page.context().storageState();
|
||||
await storage.set('stateInStorage', state);
|
||||
await store.set('stateInStorage', state);
|
||||
});
|
||||
`,
|
||||
'a.test.ts': `
|
||||
|
@ -258,7 +258,7 @@ test('should load storageStateName specified in the project config from storage'
|
|||
expect(result.passed).toBe(2);
|
||||
});
|
||||
|
||||
test('should load storageStateName specified in the global config from storage', async ({ runInlineTest, server }) => {
|
||||
test('should load storageStateName specified in the global config from store', async ({ runInlineTest, server }) => {
|
||||
server.setRoute('/setcookie.html', (req, res) => {
|
||||
res.setHeader('Set-Cookie', ['a=v1']);
|
||||
res.end();
|
||||
|
@ -272,21 +272,21 @@ test('should load storageStateName specified in the global config from storage',
|
|||
projects: [
|
||||
{
|
||||
name: 'p1',
|
||||
setup: /.*storage.setup.ts/,
|
||||
setup: /.*store.setup.ts/,
|
||||
}
|
||||
]
|
||||
};
|
||||
`,
|
||||
'storage.setup.ts': `
|
||||
const { setup, expect, storage } = pwt;
|
||||
'store.setup.ts': `
|
||||
const { setup, expect, store } = pwt;
|
||||
setup.use({
|
||||
storageStateName: ({}, use) => use(undefined),
|
||||
})
|
||||
setup('should save storageStateName', async ({ page, context }) => {
|
||||
expect(await storage.get('stateInStorage')).toBe(undefined);
|
||||
expect(await store.get('stateInStorage')).toBe(undefined);
|
||||
await page.goto('${server.PREFIX}/setcookie.html');
|
||||
const state = await page.context().storageState();
|
||||
await storage.set('stateInStorage', state);
|
||||
await store.set('stateInStorage', state);
|
||||
});
|
||||
`,
|
||||
'a.test.ts': `
|
||||
|
@ -324,5 +324,5 @@ test('should throw on unknown storageStateName value', async ({ runInlineTest, s
|
|||
}, { workers: 1 });
|
||||
expect(result.exitCode).toBe(1);
|
||||
expect(result.passed).toBe(0);
|
||||
expect(result.output).toContain('Error: Cannot find value in the storage for storageStateName: "stateInStorage"');
|
||||
expect(result.output).toContain('Error: Cannot find value in the store for storageStateName: "stateInStorage"');
|
||||
});
|
|
@ -189,15 +189,15 @@ test('config should allow void/empty options', async ({ runTSC }) => {
|
|||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test('should provide storage interface', async ({ runTSC }) => {
|
||||
test('should provide store interface', async ({ runTSC }) => {
|
||||
const result = await runTSC({
|
||||
'a.spec.ts': `
|
||||
const { test, storage } = pwt;
|
||||
const { test, store } = pwt;
|
||||
test('my test', async () => {
|
||||
await storage.set('foo', 'bar');
|
||||
const val = await storage.get('foo');
|
||||
await store.set('foo', 'bar');
|
||||
const val = await store.get('foo');
|
||||
// @ts-expect-error
|
||||
await storage.unknown();
|
||||
await store.unknown();
|
||||
});
|
||||
`
|
||||
});
|
||||
|
|
|
@ -196,7 +196,7 @@ type ConnectOptions = {
|
|||
timeout?: number;
|
||||
};
|
||||
|
||||
export interface TestStorage {
|
||||
export interface TestStore {
|
||||
get<T>(name: string): Promise<T | undefined>;
|
||||
set<T>(name: string, value: T | undefined): Promise<void>;
|
||||
}
|
||||
|
@ -350,7 +350,7 @@ export default test;
|
|||
|
||||
export const _baseTest: TestType<{}, {}>;
|
||||
export const expect: Expect;
|
||||
export const storage: TestStorage;
|
||||
export const store: TestStore;
|
||||
|
||||
// This is required to not export everything by default. See https://github.com/Microsoft/TypeScript/issues/19545#issuecomment-340490459
|
||||
export {};
|
||||
|
|
Загрузка…
Ссылка в новой задаче