This commit is contained in:
Yury Semikhatsky 2022-11-02 20:22:35 -07:00 коммит произвёл GitHub
Родитель 20f2e0049c
Коммит 45aa82242d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 226 добавлений и 9 удалений

Просмотреть файл

@ -128,3 +128,9 @@ test('basic test', async ({ request }) => {
// ...
});
```
## property: Fixtures.storage
* since: v1.28
- type: <[Storage]>
[Storage] is shared between all tests in the same run.

Просмотреть файл

@ -0,0 +1,36 @@
# class: Storage
* since: v1.28
* langs: js
Playwright Test provides a `storage` fixture for passing values between project setup and tests.
TODO: examples
## method: Storage.get
* since: v1.28
- returns: <[any]>
Get named item from the store.
### param: Storage.get.name
* since: v1.28
- `name` <[string]>
Item name.
## method: Storage.set
* since: v1.28
Set value to the store.
### param: Storage.set.name
* since: v1.28
- `name` <[string]>
Item name.
### param: Storage.set.value
* since: v1.28
- `value` <[any]>
Item value. The value must be serializable to JSON.

Просмотреть файл

@ -16,17 +16,18 @@
import * as fs from 'fs';
import * as path from 'path';
import type { LaunchOptions, BrowserContextOptions, Page, BrowserContext, Video, APIRequestContext, Tracing } from 'playwright-core';
import type { TestType, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo, VideoMode, TraceMode } from '../types/test';
import { rootTestType } from './testType';
import type { APIRequestContext, BrowserContext, BrowserContextOptions, LaunchOptions, Page, Tracing, Video } from 'playwright-core';
import * as playwrightLibrary from 'playwright-core';
import * as outOfProcess from 'playwright-core/lib/outofprocess';
import { createGuid, debugMode } from 'playwright-core/lib/utils';
import { removeFolders } from 'playwright-core/lib/utils/fileUtils';
export { expect } from './expect';
export const _baseTest: TestType<{}, {}> = rootTestType.test;
export { addRunnerPlugin as _addRunnerPlugin } from './plugins';
import * as outOfProcess from 'playwright-core/lib/outofprocess';
import * as playwrightLibrary from 'playwright-core';
import type { PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo, TestType, TraceMode, VideoMode } from '../types/test';
import type { TestInfoImpl } from './testInfo';
import { rootTestType } from './testType';
import { sanitizeForFilePath, trimLongString } from './util';
export { expect } from './expect';
export { addRunnerPlugin as _addRunnerPlugin } from './plugins';
export const _baseTest: TestType<{}, {}> = rootTestType.test;
if ((process as any)['__pw_initiator__']) {
const originalStackTraceLimit = Error.stackTraceLimit;
@ -127,7 +128,7 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
}
}, { scope: 'worker', auto: true }],
browser: [async ({ playwright, browserName }, use) => {
browser: [async ({ playwright, browserName }, use, testInfo) => {
if (!['chromium', 'firefox', 'webkit'].includes(browserName))
throw new Error(`Unexpected browserName "${browserName}", must be one of "chromium", "firefox" or "webkit"`);
const browser = await playwright[browserName].launch();
@ -135,6 +136,35 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
await browser.close();
}, { scope: 'worker', timeout: 0 }],
storage: [async ({ }, use, testInfo) => {
const toFilePath = (name: string) => {
const fileName = sanitizeForFilePath(trimLongString(name)) + '.json';
return path.join(testInfo.project.outputDir, '.playwright-storage', (testInfo as TestInfoImpl).project._id, fileName);
};
const storage = {
async get<T>(name: string) {
const file = toFilePath(name);
try {
const data = (await fs.promises.readFile(file)).toString('utf-8');
return JSON.parse(data) as T;
} catch (e) {
return undefined;
}
},
async set<T>(name: string, value: T | undefined) {
const file = toFilePath(name);
if (value === undefined) {
await fs.promises.rm(file, { force: true });
return;
}
const data = JSON.stringify(value, undefined, 2);
await fs.promises.mkdir(path.dirname(file), { recursive: true });
await fs.promises.writeFile(file, data);
}
};
await use(storage);
}, { scope: 'worker' }],
acceptDownloads: [({ contextOptions }, use) => use(contextOptions.acceptDownloads ?? true), { option: true }],
bypassCSP: [({ contextOptions }, use) => use(contextOptions.bypassCSP), { option: true }],
colorScheme: [({ contextOptions }, use) => use(contextOptions.colorScheme), { option: true }],

21
packages/playwright-test/types/test.d.ts поставляемый
Просмотреть файл

@ -2668,6 +2668,23 @@ type ConnectOptions = {
timeout?: number;
};
/**
* Playwright Test provides a `storage` fixture for passing values between project setup and tests. TODO: examples
*/
interface Storage {
/**
* Get named item from the store.
* @param name Item name.
*/
get<T>(name: string): Promise<T | undefined>;
/**
* Set value to the store.
* @param name Item name.
* @param value Item value. The value must be serializable to JSON.
*/
set<T>(name: string, value: T | undefined): Promise<void>;
}
/**
* Playwright Test provides many options to configure test environment, [Browser], [BrowserContext] and more.
*
@ -3004,6 +3021,10 @@ export interface PlaywrightWorkerArgs {
* Learn how to [configure browser](https://playwright.dev/docs/test-configuration) and see [available options][TestOptions].
*/
browser: Browser;
/**
* [Storage] is shared between all tests in the same run.
*/
storage: Storage;
}
/**

Просмотреть файл

@ -600,3 +600,121 @@ test('should pass fixture defaults to tests', async ({ runInlineTest }) => {
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1);
});
test('should provide storage fixture', async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.js': `
module.exports = {};
`,
'a.test.ts': `
const { test } = pwt;
test('should store number', async ({ storage }) => {
expect(storage).toBeTruthy();
expect(await storage.get('number')).toBe(undefined);
await storage.set('number', 2022)
expect(await storage.get('number')).toBe(2022);
});
test('should store object', async ({ storage }) => {
expect(storage).toBeTruthy();
expect(await storage.get('object')).toBe(undefined);
await storage.set('object', { 'a': 2022 })
expect(await storage.get('object')).toEqual({ 'a': 2022 });
});
`,
}, { workers: 1 });
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(2);
});
test('should share storage state between project setup and tests', async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.js': `
module.exports = {
projects: [
{
name: 'p1',
setup: /.*storage.setup.ts/
}
]
};
`,
'storage.setup.ts': `
const { test, expect } = pwt;
test('should initialize storage', async ({ storage }) => {
expect(await storage.get('number')).toBe(undefined);
await storage.set('number', 2022)
expect(await storage.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 });
});
`,
'a.test.ts': `
const { test } = pwt;
test('should get data from setup', async ({ storage }) => {
expect(await storage.get('number')).toBe(2022);
expect(await storage.get('object')).toEqual({ 'a': 2022 });
});
`,
'b.test.ts': `
const { test } = pwt;
test('should get data from setup', async ({ storage }) => {
expect(await storage.get('number')).toBe(2022);
expect(await storage.get('object')).toEqual({ 'a': 2022 });
});
`,
}, { workers: 1 });
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(3);
});
test('should isolate storage state between projects', async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.js': `
module.exports = {
projects: [
{
name: 'p1',
setup: /.*storage.setup.ts/
},
{
name: 'p2',
setup: /.*storage.setup.ts/
}
]
};
`,
'storage.setup.ts': `
const { test, expect } = pwt;
test('should initialize storage', async ({ storage }, testInfo) => {
expect(await storage.get('number')).toBe(undefined);
await storage.set('number', 2022)
expect(await storage.get('number')).toBe(2022);
expect(await storage.get('name')).toBe(undefined);
await storage.set('name', 'str-' + testInfo.project.name)
expect(await storage.get('name')).toBe('str-' + testInfo.project.name);
});
`,
'a.test.ts': `
const { test } = pwt;
test('should get data from setup', async ({ storage }, testInfo) => {
expect(await storage.get('number')).toBe(2022);
expect(await storage.get('name')).toBe('str-' + testInfo.project.name);
});
`,
'b.test.ts': `
const { test } = pwt;
test('should get data from setup', async ({ storage }, testInfo) => {
expect(await storage.get('number')).toBe(2022);
expect(await storage.get('name')).toBe('str-' + testInfo.project.name);
});
`,
}, { workers: 2 });
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(6);
});

6
utils/generate_types/overrides-test.d.ts поставляемый
Просмотреть файл

@ -196,6 +196,11 @@ type ConnectOptions = {
timeout?: number;
};
interface Storage {
get<T>(name: string): Promise<T | undefined>;
set<T>(name: string, value: T | undefined): Promise<void>;
}
export interface PlaywrightWorkerOptions {
browserName: BrowserName;
defaultBrowserType: BrowserName;
@ -243,6 +248,7 @@ export interface PlaywrightTestOptions {
export interface PlaywrightWorkerArgs {
playwright: typeof import('playwright-core');
browser: Browser;
storage: Storage;
}
export interface PlaywrightTestArgs {