mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat(runner): change storage fixture to TestInfo.storage() (#18584)
This commit is contained in:
parent
a9c15a25f8
commit
25dc0bfacb
@ -128,9 +128,3 @@ test('basic test', async ({ request }) => {
|
|||||||
// ...
|
// ...
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## property: Fixtures.storage
|
|
||||||
* since: v1.28
|
|
||||||
- type: <[Storage]>
|
|
||||||
|
|
||||||
[Storage] is shared between all tests in the same run.
|
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
* since: v1.28
|
* since: v1.28
|
||||||
* langs: js
|
* langs: js
|
||||||
|
|
||||||
Playwright Test provides a `storage` fixture for passing values between project setup and tests.
|
Playwright Test provides a [`method: TestInfo.storage`] object for passing values between project setup and tests.
|
||||||
TODO: examples
|
TODO: examples
|
||||||
|
|
||||||
## method: Storage.get
|
## async method: Storage.get
|
||||||
* since: v1.28
|
* since: v1.28
|
||||||
- returns: <[any]>
|
- returns: <[any]>
|
||||||
|
|
||||||
Get named item from the store.
|
Get named item from the storage. Returns undefined if there is no value with given name.
|
||||||
|
|
||||||
### param: Storage.get.name
|
### param: Storage.get.name
|
||||||
* since: v1.28
|
* since: v1.28
|
||||||
@ -17,10 +17,10 @@ Get named item from the store.
|
|||||||
|
|
||||||
Item name.
|
Item name.
|
||||||
|
|
||||||
## method: Storage.set
|
## async method: Storage.set
|
||||||
* since: v1.28
|
* since: v1.28
|
||||||
|
|
||||||
Set value to the store.
|
Set value to the storage.
|
||||||
|
|
||||||
### param: Storage.set.name
|
### param: Storage.set.name
|
||||||
* since: v1.28
|
* since: v1.28
|
||||||
@ -32,5 +32,5 @@ Item name.
|
|||||||
* since: v1.28
|
* since: v1.28
|
||||||
- `value` <[any]>
|
- `value` <[any]>
|
||||||
|
|
||||||
Item value. The value must be serializable to JSON.
|
Item value. The value must be serializable to JSON. Passing `undefined` deletes the entry with given name.
|
||||||
|
|
||||||
|
@ -498,6 +498,12 @@ Output written to `process.stderr` or `console.error` during the test execution.
|
|||||||
|
|
||||||
Output written to `process.stdout` or `console.log` during the test execution.
|
Output written to `process.stdout` or `console.log` during the test execution.
|
||||||
|
|
||||||
|
## method: TestInfo.storage
|
||||||
|
* since: v1.28
|
||||||
|
- returns: <[Storage]>
|
||||||
|
|
||||||
|
Returns a [Storage] instance for the currently running project.
|
||||||
|
|
||||||
## property: TestInfo.timeout
|
## property: TestInfo.timeout
|
||||||
* since: v1.10
|
* since: v1.10
|
||||||
- type: <[int]>
|
- type: <[int]>
|
||||||
|
@ -24,7 +24,6 @@ import { removeFolders } from 'playwright-core/lib/utils/fileUtils';
|
|||||||
import type { PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo, TestType, TraceMode, VideoMode } from '../types/test';
|
import type { PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo, TestType, TraceMode, VideoMode } from '../types/test';
|
||||||
import type { TestInfoImpl } from './testInfo';
|
import type { TestInfoImpl } from './testInfo';
|
||||||
import { rootTestType } from './testType';
|
import { rootTestType } from './testType';
|
||||||
import { sanitizeForFilePath, trimLongString } from './util';
|
|
||||||
export { expect } from './expect';
|
export { expect } from './expect';
|
||||||
export { addRunnerPlugin as _addRunnerPlugin } from './plugins';
|
export { addRunnerPlugin as _addRunnerPlugin } from './plugins';
|
||||||
export const _baseTest: TestType<{}, {}> = rootTestType.test;
|
export const _baseTest: TestType<{}, {}> = rootTestType.test;
|
||||||
@ -136,35 +135,6 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
|||||||
await browser.close();
|
await browser.close();
|
||||||
}, { scope: 'worker', timeout: 0 }],
|
}, { 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 }],
|
acceptDownloads: [({ contextOptions }, use) => use(contextOptions.acceptDownloads ?? true), { option: true }],
|
||||||
bypassCSP: [({ contextOptions }, use) => use(contextOptions.bypassCSP), { option: true }],
|
bypassCSP: [({ contextOptions }, use) => use(contextOptions.bypassCSP), { option: true }],
|
||||||
colorScheme: [({ contextOptions }, use) => use(contextOptions.colorScheme), { option: true }],
|
colorScheme: [({ contextOptions }, use) => use(contextOptions.colorScheme), { option: true }],
|
||||||
@ -216,7 +186,6 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
|||||||
baseURL,
|
baseURL,
|
||||||
contextOptions,
|
contextOptions,
|
||||||
serviceWorkers,
|
serviceWorkers,
|
||||||
storage,
|
|
||||||
}, use) => {
|
}, use) => {
|
||||||
const options: BrowserContextOptions = {};
|
const options: BrowserContextOptions = {};
|
||||||
if (acceptDownloads !== undefined)
|
if (acceptDownloads !== undefined)
|
||||||
@ -252,7 +221,7 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
|||||||
if (storageState !== undefined) {
|
if (storageState !== undefined) {
|
||||||
options.storageState = storageState;
|
options.storageState = storageState;
|
||||||
if (typeof storageState === 'string') {
|
if (typeof storageState === 'string') {
|
||||||
const value = await storage.get(storageState);
|
const value = await test.info().storage().get(storageState);
|
||||||
if (value)
|
if (value)
|
||||||
options.storageState = value as any;
|
options.storageState = value as any;
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,7 @@ export class Loader {
|
|||||||
config.snapshotDir = path.resolve(configDir, config.snapshotDir);
|
config.snapshotDir = path.resolve(configDir, config.snapshotDir);
|
||||||
|
|
||||||
this._fullConfig._configDir = configDir;
|
this._fullConfig._configDir = configDir;
|
||||||
|
this._fullConfig._storageDir = path.resolve(configDir, '.playwright-storage');
|
||||||
this._fullConfig.configFile = this._configFile;
|
this._fullConfig.configFile = this._configFile;
|
||||||
this._fullConfig.rootDir = config.testDir || this._configDir;
|
this._fullConfig.rootDir = config.testDir || this._configDir;
|
||||||
this._fullConfig._globalOutputDir = takeFirst(config.outputDir, throwawayArtifactsPath, baseFullConfig._globalOutputDir);
|
this._fullConfig._globalOutputDir = takeFirst(config.outputDir, throwawayArtifactsPath, baseFullConfig._globalOutputDir);
|
||||||
@ -669,6 +670,7 @@ export const baseFullConfig: FullConfigInternal = {
|
|||||||
_webServers: [],
|
_webServers: [],
|
||||||
_globalOutputDir: path.resolve(process.cwd()),
|
_globalOutputDir: path.resolve(process.cwd()),
|
||||||
_configDir: '',
|
_configDir: '',
|
||||||
|
_storageDir: '',
|
||||||
_maxConcurrentTestGroups: 0,
|
_maxConcurrentTestGroups: 0,
|
||||||
_ignoreSnapshots: false,
|
_ignoreSnapshots: false,
|
||||||
_workerIsolation: 'isolate-pools',
|
_workerIsolation: 'isolate-pools',
|
||||||
|
@ -16,15 +16,14 @@
|
|||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import type { TestError, TestInfo, TestStatus } from '../types/test';
|
import { monotonicTime } from 'playwright-core/lib/utils';
|
||||||
import type { FullConfigInternal, FullProjectInternal } from './types';
|
import type { Storage, TestError, TestInfo, TestStatus } from '../types/test';
|
||||||
import type { WorkerInitParams } from './ipc';
|
import type { WorkerInitParams } from './ipc';
|
||||||
import type { Loader } from './loader';
|
import type { Loader } from './loader';
|
||||||
import type { TestCase } from './test';
|
import type { TestCase } from './test';
|
||||||
import { TimeoutManager } from './timeoutManager';
|
import { TimeoutManager } from './timeoutManager';
|
||||||
import type { Annotation, TestStepInternal } from './types';
|
import type { Annotation, FullConfigInternal, FullProjectInternal, TestStepInternal } from './types';
|
||||||
import { addSuffixToFilePath, getContainedPath, normalizeAndSaveAttachment, sanitizeForFilePath, serializeError, trimLongString } from './util';
|
import { addSuffixToFilePath, getContainedPath, normalizeAndSaveAttachment, sanitizeForFilePath, serializeError, trimLongString } from './util';
|
||||||
import { monotonicTime } from 'playwright-core/lib/utils';
|
|
||||||
|
|
||||||
export class TestInfoImpl implements TestInfo {
|
export class TestInfoImpl implements TestInfo {
|
||||||
private _addStepImpl: (data: Omit<TestStepInternal, 'complete'>) => TestStepInternal;
|
private _addStepImpl: (data: Omit<TestStepInternal, 'complete'>) => TestStepInternal;
|
||||||
@ -62,6 +61,7 @@ export class TestInfoImpl implements TestInfo {
|
|||||||
readonly snapshotDir: string;
|
readonly snapshotDir: string;
|
||||||
errors: TestError[] = [];
|
errors: TestError[] = [];
|
||||||
currentStep: TestStepInternal | undefined;
|
currentStep: TestStepInternal | undefined;
|
||||||
|
private readonly _storage: JsonStorage;
|
||||||
|
|
||||||
get error(): TestError | undefined {
|
get error(): TestError | undefined {
|
||||||
return this.errors[0];
|
return this.errors[0];
|
||||||
@ -109,6 +109,7 @@ export class TestInfoImpl implements TestInfo {
|
|||||||
this.expectedStatus = test.expectedStatus;
|
this.expectedStatus = test.expectedStatus;
|
||||||
|
|
||||||
this._timeoutManager = new TimeoutManager(this.project.timeout);
|
this._timeoutManager = new TimeoutManager(this.project.timeout);
|
||||||
|
this._storage = new JsonStorage(this);
|
||||||
|
|
||||||
this.outputDir = (() => {
|
this.outputDir = (() => {
|
||||||
const relativeTestFilePath = path.relative(this.project.testDir, test._requireFile.replace(/\.(spec|test)\.(js|ts|mjs)$/, ''));
|
const relativeTestFilePath = path.relative(this.project.testDir, test._requireFile.replace(/\.(spec|test)\.(js|ts|mjs)$/, ''));
|
||||||
@ -279,6 +280,41 @@ export class TestInfoImpl implements TestInfo {
|
|||||||
setTimeout(timeout: number) {
|
setTimeout(timeout: number) {
|
||||||
this._timeoutManager.setTimeout(timeout);
|
this._timeoutManager.setTimeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
storage() {
|
||||||
|
return this._storage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class JsonStorage implements Storage {
|
||||||
|
constructor(private _testInfo: TestInfoImpl) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private _toFilePath(name: string) {
|
||||||
|
const fileName = sanitizeForFilePath(trimLongString(name)) + '.json';
|
||||||
|
return path.join(this._testInfo.config._storageDir, this._testInfo.project._id, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
async get<T>(name: string) {
|
||||||
|
const file = this._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 = this._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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SkipError extends Error {
|
class SkipError extends Error {
|
||||||
|
@ -45,6 +45,7 @@ export interface TestStepInternal {
|
|||||||
export interface FullConfigInternal extends FullConfigPublic {
|
export interface FullConfigInternal extends FullConfigPublic {
|
||||||
_globalOutputDir: string;
|
_globalOutputDir: string;
|
||||||
_configDir: string;
|
_configDir: string;
|
||||||
|
_storageDir: string;
|
||||||
_maxConcurrentTestGroups: number;
|
_maxConcurrentTestGroups: number;
|
||||||
_ignoreSnapshots: boolean;
|
_ignoreSnapshots: boolean;
|
||||||
_workerIsolation: WorkerIsolation;
|
_workerIsolation: WorkerIsolation;
|
||||||
|
20
packages/playwright-test/types/test.d.ts
vendored
20
packages/playwright-test/types/test.d.ts
vendored
@ -1740,6 +1740,11 @@ export interface TestInfo {
|
|||||||
*/
|
*/
|
||||||
stdout: Array<string|Buffer>;
|
stdout: Array<string|Buffer>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a [Storage] instance for the currently running project.
|
||||||
|
*/
|
||||||
|
storage(): Storage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timeout in milliseconds for the currently running test. Zero means no timeout. Learn more about
|
* Timeout in milliseconds for the currently running test. Zero means no timeout. Learn more about
|
||||||
* [various timeouts](https://playwright.dev/docs/test-timeouts).
|
* [various timeouts](https://playwright.dev/docs/test-timeouts).
|
||||||
@ -2693,18 +2698,19 @@ type ConnectOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Playwright Test provides a `storage` fixture for passing values between project setup and tests. TODO: examples
|
* Playwright Test provides a [testInfo.storage()](https://playwright.dev/docs/api/class-testinfo#test-info-storage) object
|
||||||
|
* for passing values between project setup and tests. TODO: examples
|
||||||
*/
|
*/
|
||||||
interface Storage {
|
export interface Storage {
|
||||||
/**
|
/**
|
||||||
* Get named item from the store.
|
* Get named item from the storage. Returns undefined if there is no value with given name.
|
||||||
* @param name Item name.
|
* @param name Item name.
|
||||||
*/
|
*/
|
||||||
get<T>(name: string): Promise<T | undefined>;
|
get<T>(name: string): Promise<T | undefined>;
|
||||||
/**
|
/**
|
||||||
* Set value to the store.
|
* Set value to the storage.
|
||||||
* @param name Item name.
|
* @param name Item name.
|
||||||
* @param value Item value. The value must be serializable to JSON.
|
* @param value Item value. The value must be serializable to JSON. Passing `undefined` deletes the entry with given name.
|
||||||
*/
|
*/
|
||||||
set<T>(name: string, value: T | undefined): Promise<void>;
|
set<T>(name: string, value: T | undefined): Promise<void>;
|
||||||
}
|
}
|
||||||
@ -3045,10 +3051,6 @@ export interface PlaywrightWorkerArgs {
|
|||||||
* Learn how to [configure browser](https://playwright.dev/docs/test-configuration) and see [available options][TestOptions].
|
* Learn how to [configure browser](https://playwright.dev/docs/test-configuration) and see [available options][TestOptions].
|
||||||
*/
|
*/
|
||||||
browser: Browser;
|
browser: Browser;
|
||||||
/**
|
|
||||||
* [Storage] is shared between all tests in the same run.
|
|
||||||
*/
|
|
||||||
storage: Storage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,13 +23,15 @@ test('should provide storage fixture', async ({ runInlineTest }) => {
|
|||||||
`,
|
`,
|
||||||
'a.test.ts': `
|
'a.test.ts': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
test('should store number', async ({ storage }) => {
|
test('should store number', async ({ }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(storage).toBeTruthy();
|
expect(storage).toBeTruthy();
|
||||||
expect(await storage.get('number')).toBe(undefined);
|
expect(await storage.get('number')).toBe(undefined);
|
||||||
await storage.set('number', 2022)
|
await storage.set('number', 2022)
|
||||||
expect(await storage.get('number')).toBe(2022);
|
expect(await storage.get('number')).toBe(2022);
|
||||||
});
|
});
|
||||||
test('should store object', async ({ storage }) => {
|
test('should store object', async ({ }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(storage).toBeTruthy();
|
expect(storage).toBeTruthy();
|
||||||
expect(await storage.get('object')).toBe(undefined);
|
expect(await storage.get('object')).toBe(undefined);
|
||||||
await storage.set('object', { 'a': 2022 })
|
await storage.set('object', { 'a': 2022 })
|
||||||
@ -41,7 +43,6 @@ test('should provide storage fixture', async ({ runInlineTest }) => {
|
|||||||
expect(result.passed).toBe(2);
|
expect(result.passed).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('should share storage state between project setup and tests', async ({ runInlineTest }) => {
|
test('should share storage state between project setup and tests', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'playwright.config.js': `
|
'playwright.config.js': `
|
||||||
@ -56,7 +57,8 @@ test('should share storage state between project setup and tests', async ({ runI
|
|||||||
`,
|
`,
|
||||||
'storage.setup.ts': `
|
'storage.setup.ts': `
|
||||||
const { test, expect } = pwt;
|
const { test, expect } = pwt;
|
||||||
test('should initialize storage', async ({ storage }) => {
|
test('should initialize storage', async ({ }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(await storage.get('number')).toBe(undefined);
|
expect(await storage.get('number')).toBe(undefined);
|
||||||
await storage.set('number', 2022)
|
await storage.set('number', 2022)
|
||||||
expect(await storage.get('number')).toBe(2022);
|
expect(await storage.get('number')).toBe(2022);
|
||||||
@ -68,14 +70,16 @@ test('should share storage state between project setup and tests', async ({ runI
|
|||||||
`,
|
`,
|
||||||
'a.test.ts': `
|
'a.test.ts': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
test('should get data from setup', async ({ storage }) => {
|
test('should get data from setup', async ({ }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(await storage.get('number')).toBe(2022);
|
expect(await storage.get('number')).toBe(2022);
|
||||||
expect(await storage.get('object')).toEqual({ 'a': 2022 });
|
expect(await storage.get('object')).toEqual({ 'a': 2022 });
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'b.test.ts': `
|
'b.test.ts': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
test('should get data from setup', async ({ storage }) => {
|
test('should get data from setup', async ({ }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(await storage.get('number')).toBe(2022);
|
expect(await storage.get('number')).toBe(2022);
|
||||||
expect(await storage.get('object')).toEqual({ 'a': 2022 });
|
expect(await storage.get('object')).toEqual({ 'a': 2022 });
|
||||||
});
|
});
|
||||||
@ -85,6 +89,41 @@ test('should share storage state between project setup and tests', async ({ runI
|
|||||||
expect(result.passed).toBe(3);
|
expect(result.passed).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should persist storage state between project runs', async ({ runInlineTest }) => {
|
||||||
|
const files = {
|
||||||
|
'playwright.config.js': `
|
||||||
|
module.exports = { };
|
||||||
|
`,
|
||||||
|
'a.test.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('should have no data on first run', async ({ }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
|
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 })
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'b.test.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('should get data from previous run', async ({ }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
|
expect(await storage.get('number')).toBe(2022);
|
||||||
|
expect(await storage.get('object')).toEqual({ 'a': 2022 });
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
{
|
||||||
|
const result = await runInlineTest(files, { grep: 'should have no data on first run' });
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const result = await runInlineTest(files, { grep: 'should get data from previous run' });
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('should isolate storage state between projects', async ({ runInlineTest }) => {
|
test('should isolate storage state between projects', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
@ -104,28 +143,31 @@ test('should isolate storage state between projects', async ({ runInlineTest })
|
|||||||
`,
|
`,
|
||||||
'storage.setup.ts': `
|
'storage.setup.ts': `
|
||||||
const { test, expect } = pwt;
|
const { test, expect } = pwt;
|
||||||
test('should initialize storage', async ({ storage }, testInfo) => {
|
test('should initialize storage', async ({ }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(await storage.get('number')).toBe(undefined);
|
expect(await storage.get('number')).toBe(undefined);
|
||||||
await storage.set('number', 2022)
|
await storage.set('number', 2022)
|
||||||
expect(await storage.get('number')).toBe(2022);
|
expect(await storage.get('number')).toBe(2022);
|
||||||
|
|
||||||
expect(await storage.get('name')).toBe(undefined);
|
expect(await storage.get('name')).toBe(undefined);
|
||||||
await storage.set('name', 'str-' + testInfo.project.name)
|
await storage.set('name', 'str-' + test.info().project.name)
|
||||||
expect(await storage.get('name')).toBe('str-' + testInfo.project.name);
|
expect(await storage.get('name')).toBe('str-' + test.info().project.name);
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'a.test.ts': `
|
'a.test.ts': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
test('should get data from setup', async ({ storage }, testInfo) => {
|
test('should get data from setup', async ({ }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(await storage.get('number')).toBe(2022);
|
expect(await storage.get('number')).toBe(2022);
|
||||||
expect(await storage.get('name')).toBe('str-' + testInfo.project.name);
|
expect(await storage.get('name')).toBe('str-' + test.info().project.name);
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'b.test.ts': `
|
'b.test.ts': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
test('should get data from setup', async ({ storage }, testInfo) => {
|
test('should get data from setup', async ({ }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(await storage.get('number')).toBe(2022);
|
expect(await storage.get('number')).toBe(2022);
|
||||||
expect(await storage.get('name')).toBe('str-' + testInfo.project.name);
|
expect(await storage.get('name')).toBe('str-' + test.info().project.name);
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
}, { workers: 2 });
|
}, { workers: 2 });
|
||||||
@ -133,7 +175,6 @@ test('should isolate storage state between projects', async ({ runInlineTest })
|
|||||||
expect(result.passed).toBe(6);
|
expect(result.passed).toBe(6);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
test('should load context storageState from storage', async ({ runInlineTest, server }) => {
|
test('should load context storageState from storage', async ({ runInlineTest, server }) => {
|
||||||
server.setRoute('/setcookie.html', (req, res) => {
|
server.setRoute('/setcookie.html', (req, res) => {
|
||||||
res.setHeader('Set-Cookie', ['a=v1']);
|
res.setHeader('Set-Cookie', ['a=v1']);
|
||||||
@ -152,7 +193,8 @@ test('should load context storageState from storage', async ({ runInlineTest, se
|
|||||||
`,
|
`,
|
||||||
'storage.setup.ts': `
|
'storage.setup.ts': `
|
||||||
const { test, expect } = pwt;
|
const { test, expect } = pwt;
|
||||||
test('should save storageState', async ({ page, context, storage }, testInfo) => {
|
test('should save storageState', async ({ page, context }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(await storage.get('user')).toBe(undefined);
|
expect(await storage.get('user')).toBe(undefined);
|
||||||
await page.goto('${server.PREFIX}/setcookie.html');
|
await page.goto('${server.PREFIX}/setcookie.html');
|
||||||
const state = await page.context().storageState();
|
const state = await page.context().storageState();
|
||||||
@ -164,7 +206,7 @@ test('should load context storageState from storage', async ({ runInlineTest, se
|
|||||||
test.use({
|
test.use({
|
||||||
storageState: 'user'
|
storageState: 'user'
|
||||||
})
|
})
|
||||||
test('should get data from setup', async ({ page }, testInfo) => {
|
test('should get data from setup', async ({ page }) => {
|
||||||
await page.goto('${server.EMPTY_PAGE}');
|
await page.goto('${server.EMPTY_PAGE}');
|
||||||
const cookies = await page.evaluate(() => document.cookie);
|
const cookies = await page.evaluate(() => document.cookie);
|
||||||
expect(cookies).toBe('a=v1');
|
expect(cookies).toBe('a=v1');
|
||||||
@ -172,7 +214,7 @@ test('should load context storageState from storage', async ({ runInlineTest, se
|
|||||||
`,
|
`,
|
||||||
'b.test.ts': `
|
'b.test.ts': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
test('should not get data from setup if not configured', async ({ page }, testInfo) => {
|
test('should not get data from setup if not configured', async ({ page }) => {
|
||||||
await page.goto('${server.EMPTY_PAGE}');
|
await page.goto('${server.EMPTY_PAGE}');
|
||||||
const cookies = await page.evaluate(() => document.cookie);
|
const cookies = await page.evaluate(() => document.cookie);
|
||||||
expect(cookies).toBe('');
|
expect(cookies).toBe('');
|
||||||
@ -207,17 +249,17 @@ test('should load storageState specified in the project config from storage', as
|
|||||||
test.reset({
|
test.reset({
|
||||||
storageState: 'default'
|
storageState: 'default'
|
||||||
})
|
})
|
||||||
test('should save storageState', async ({ page, context, storage }, testInfo) => {
|
test('should save storageState', async ({ page, context }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(await storage.get('stateInStorage')).toBe(undefined);
|
expect(await storage.get('stateInStorage')).toBe(undefined);
|
||||||
await page.goto('${server.PREFIX}/setcookie.html');
|
await page.goto('${server.PREFIX}/setcookie.html');
|
||||||
const state = await page.context().storageState();
|
const state = await page.context().storageState();
|
||||||
await storage.set('stateInStorage', state);
|
await storage.set('stateInStorage', state);
|
||||||
console.log('project setup state = ' + state);
|
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'a.test.ts': `
|
'a.test.ts': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
test('should get data from setup', async ({ page, storage }, testInfo) => {
|
test('should get data from setup', async ({ page }) => {
|
||||||
await page.goto('${server.EMPTY_PAGE}');
|
await page.goto('${server.EMPTY_PAGE}');
|
||||||
const cookies = await page.evaluate(() => document.cookie);
|
const cookies = await page.evaluate(() => document.cookie);
|
||||||
expect(cookies).toBe('a=v1');
|
expect(cookies).toBe('a=v1');
|
||||||
@ -252,17 +294,17 @@ test('should load storageState specified in the global config from storage', asy
|
|||||||
test.reset({
|
test.reset({
|
||||||
storageState: 'default'
|
storageState: 'default'
|
||||||
})
|
})
|
||||||
test('should save storageState', async ({ page, context, storage }, testInfo) => {
|
test('should save storageState', async ({ page, context }) => {
|
||||||
|
const storage = test.info().storage();
|
||||||
expect(await storage.get('stateInStorage')).toBe(undefined);
|
expect(await storage.get('stateInStorage')).toBe(undefined);
|
||||||
await page.goto('${server.PREFIX}/setcookie.html');
|
await page.goto('${server.PREFIX}/setcookie.html');
|
||||||
const state = await page.context().storageState();
|
const state = await page.context().storageState();
|
||||||
await storage.set('stateInStorage', state);
|
await storage.set('stateInStorage', state);
|
||||||
console.log('project setup state = ' + state);
|
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'a.test.ts': `
|
'a.test.ts': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
test('should get data from setup', async ({ page, storage }, testInfo) => {
|
test('should get data from setup', async ({ page }) => {
|
||||||
await page.goto('${server.EMPTY_PAGE}');
|
await page.goto('${server.EMPTY_PAGE}');
|
||||||
const cookies = await page.evaluate(() => document.cookie);
|
const cookies = await page.evaluate(() => document.cookie);
|
||||||
expect(cookies).toBe('a=v1');
|
expect(cookies).toBe('a=v1');
|
||||||
|
@ -195,3 +195,18 @@ test('config should allow void/empty options', async ({ runTSC }) => {
|
|||||||
});
|
});
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should provide storage interface', async ({ runTSC }) => {
|
||||||
|
const result = await runTSC({
|
||||||
|
'a.spec.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('my test', async () => {
|
||||||
|
await test.info().storage().set('foo', 'bar');
|
||||||
|
const val = await test.info().storage().get('foo');
|
||||||
|
// @ts-expect-error
|
||||||
|
await test.info().storage().unknown();
|
||||||
|
});
|
||||||
|
`
|
||||||
|
});
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
});
|
||||||
|
3
utils/generate_types/overrides-test.d.ts
vendored
3
utils/generate_types/overrides-test.d.ts
vendored
@ -198,7 +198,7 @@ type ConnectOptions = {
|
|||||||
timeout?: number;
|
timeout?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Storage {
|
export interface Storage {
|
||||||
get<T>(name: string): Promise<T | undefined>;
|
get<T>(name: string): Promise<T | undefined>;
|
||||||
set<T>(name: string, value: T | undefined): Promise<void>;
|
set<T>(name: string, value: T | undefined): Promise<void>;
|
||||||
}
|
}
|
||||||
@ -250,7 +250,6 @@ export interface PlaywrightTestOptions {
|
|||||||
export interface PlaywrightWorkerArgs {
|
export interface PlaywrightWorkerArgs {
|
||||||
playwright: typeof import('playwright-core');
|
playwright: typeof import('playwright-core');
|
||||||
browser: Browser;
|
browser: Browser;
|
||||||
storage: Storage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlaywrightTestArgs {
|
export interface PlaywrightTestArgs {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user