chore: hide TestProject.setup and TestInfo.storage (#18800)

This commit is contained in:
Yury Semikhatsky 2022-11-14 17:03:01 -08:00 коммит произвёл GitHub
Родитель 6258ed53f0
Коммит 6deba5dc21
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 57 добавлений и 209 удалений

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

@ -1,36 +0,0 @@
# class: Storage
* since: v1.28
* langs: js
Playwright Test provides a [`method: TestInfo.storage`] object for passing values between project setup and tests.
TODO: examples
## async method: Storage.get
* since: v1.28
- returns: <[any]>
Get named item from the storage. Returns undefined if there is no value with given name.
### param: Storage.get.name
* since: v1.28
- `name` <[string]>
Item name.
## async method: Storage.set
* since: v1.28
Set value to the storage.
### 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. Passing `undefined` deletes the entry with given name.

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

@ -505,12 +505,6 @@ Output written to `process.stderr` or `console.error` 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
* since: v1.10
- type: <[int]>

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

@ -202,14 +202,6 @@ Learn more about [automatic screenshots](../test-configuration.md#automatic-scre
## property: TestOptions.storageState = %%-js-python-context-option-storage-state-%%
* since: v1.10
## property: TestOptions.storageStateName
* since: v1.28
- type: <[string]>
Name of the [Storage] entry that should be used to initialize [`property: TestOptions.storageState`]. The value must be
written to the storage before creatiion 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.
## property: TestOptions.testIdAttribute
* since: v1.27

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

@ -162,12 +162,6 @@ Metadata that will be put directly to the test report serialized as JSON.
Project name is visible in the report and during test execution.
## property: TestProject.setup
* since: v1.28
- type: ?<[string]|[RegExp]|[Array]<[string]|[RegExp]>>
Project setup files that would be executed before all tests in the project. If project setup fails the tests in this project will be skipped. All project setup files will run in every shard if the project is sharded.
## property: TestProject.snapshotDir
* since: v1.10
- type: ?<[string]>

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

@ -49,6 +49,7 @@ type TestFixtures = PlaywrightTestArgs & PlaywrightTestOptions & {
};
type WorkerFixtures = PlaywrightWorkerArgs & PlaywrightWorkerOptions & {
_browserOptions: LaunchOptions;
_storageStateName: string | undefined;
_artifactsDir: () => string;
_snapshotSuffix: string;
};
@ -151,7 +152,7 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
permissions: [({ contextOptions }, use) => use(contextOptions.permissions), { option: true }],
proxy: [({ contextOptions }, use) => use(contextOptions.proxy), { option: true }],
storageState: [({ contextOptions }, use) => use(contextOptions.storageState), { option: true }],
storageStateName: [undefined, { option: true }],
_storageStateName: [undefined, { option: true, scope: 'worker' }],
timezoneId: [({ contextOptions }, use) => use(contextOptions.timezoneId), { option: true }],
userAgent: [({ contextOptions }, use) => use(contextOptions.userAgent), { option: true }],
viewport: [({ contextOptions }, use) => use(contextOptions.viewport === undefined ? { width: 1280, height: 720 } : contextOptions.viewport), { option: true }],
@ -181,7 +182,7 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
permissions,
proxy,
storageState,
storageStateName,
_storageStateName,
viewport,
timezoneId,
userAgent,
@ -220,10 +221,10 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
options.permissions = permissions;
if (proxy !== undefined)
options.proxy = proxy;
if (storageStateName !== undefined) {
const value = await test.info().storage().get(storageStateName);
if (_storageStateName !== undefined) {
const value = await (test.info() as TestInfoImpl)._storage().get(_storageStateName);
if (!value)
throw new Error(`Cannot find value in the storage for storageStateName: "${storageStateName}"`);
throw new Error(`Cannot find value in the storage for storageStateName: "${_storageStateName}"`);
options.storageState = value as any;
} else if (storageState !== undefined) {
options.storageState = storageState;

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

@ -274,7 +274,7 @@ export class Loader {
const outputDir = takeFirst(projectConfig.outputDir, config.outputDir, path.join(throwawayArtifactsPath, 'test-results'));
const snapshotDir = takeFirst(projectConfig.snapshotDir, config.snapshotDir, testDir);
const name = takeFirst(projectConfig.name, config.name, '');
const _setup = takeFirst(projectConfig.setup, []);
const _setup = takeFirst((projectConfig as any)._setup, []);
const defaultSnapshotPathTemplate = '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}';
const snapshotPathTemplate = takeFirst(projectConfig.snapshotPathTemplate, config.snapshotPathTemplate, defaultSnapshotPathTemplate);
@ -614,7 +614,7 @@ function validateProject(file: string, project: Project, title: string) {
throw errorWithFile(file, `${title}.testDir must be a string`);
}
for (const prop of ['testIgnore', 'testMatch', 'setup'] as const) {
for (const prop of ['testIgnore', 'testMatch'] as const) {
if (prop in project && project[prop] !== undefined) {
const value = project[prop];
if (Array.isArray(value)) {

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

@ -17,7 +17,7 @@
import fs from 'fs';
import path from 'path';
import { monotonicTime } from 'playwright-core/lib/utils';
import type { Storage, TestError, TestInfo, TestStatus } from '../types/test';
import type { TestError, TestInfo, TestStatus } from '../types/test';
import type { WorkerInitParams } from './ipc';
import type { Loader } from './loader';
import type { TestCase } from './test';
@ -60,7 +60,7 @@ export class TestInfoImpl implements TestInfo {
readonly snapshotDir: string;
errors: TestError[] = [];
currentStep: TestStepInternal | undefined;
private readonly _storage: JsonStorage;
private readonly _testStorage: JsonStorage;
get error(): TestError | undefined {
return this.errors[0];
@ -108,7 +108,7 @@ export class TestInfoImpl implements TestInfo {
this.expectedStatus = test.expectedStatus;
this._timeoutManager = new TimeoutManager(this.project.timeout);
this._storage = new JsonStorage(this);
this._testStorage = new JsonStorage(this);
this.outputDir = (() => {
const relativeTestFilePath = path.relative(this.project.testDir, test._requireFile.replace(/\.(spec|test)\.(js|ts|mjs)$/, ''));
@ -281,12 +281,12 @@ export class TestInfoImpl implements TestInfo {
this._timeoutManager.setTimeout(timeout);
}
storage() {
return this._storage;
_storage() {
return this._testStorage;
}
}
class JsonStorage implements Storage {
class JsonStorage {
constructor(private _testInfo: TestInfoImpl) {
}

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

@ -1849,11 +1849,6 @@ export interface TestInfo {
*/
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
* [various timeouts](https://playwright.dev/docs/test-timeouts).
@ -2782,24 +2777,6 @@ type ConnectOptions = {
timeout?: number;
};
/**
* 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
*/
export interface Storage {
/**
* Get named item from the storage. 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.
* @param name Item name.
* @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>;
}
/**
* Playwright Test provides many options to configure test environment, [Browser], [BrowserContext] and more.
*
@ -3034,15 +3011,6 @@ export interface PlaywrightTestOptions {
* Either a path to the file with saved storage, or an object with the following fields:
*/
storageState: StorageState | undefined;
/**
* Name of the [Storage] 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 storage before creatiion 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 and
* [testOptions.storageState](https://playwright.dev/docs/api/class-testoptions#test-options-storage-state) are specified,
* this property will always take precedence.
*/
storageStateName: string | undefined;
/**
* Changes the timezone of the context. See
* [ICU's metaZones.txt](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1)
@ -4555,12 +4523,6 @@ interface TestProject {
*/
name?: string;
/**
* Project setup files that would be executed before all tests in the project. If project setup fails the tests in this
* project will be skipped. All project setup files will run in every shard if the project is sharded.
*/
setup?: string|RegExp|Array<string|RegExp>;
/**
* The base directory, relative to the config file, for snapshot files created with `toMatchSnapshot`. Defaults to
* [testProject.testDir](https://playwright.dev/docs/api/class-testproject#test-project-test-dir).

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

@ -480,41 +480,3 @@ test('should have correct types for the config', async ({ runTSC }) => {
});
expect(result.exitCode).toBe(0);
});
test('should throw when project.setup has wrong type', async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = {
projects: [
{ name: 'a', setup: 100 },
],
};
`,
'a.test.ts': `
const { test } = pwt;
test('pass', async () => {});
`
});
expect(result.exitCode).toBe(1);
expect(result.output).toContain(`Error: playwright.config.ts: config.projects[0].setup must be a string or a RegExp`);
});
test('should throw when project.setup has wrong array type', async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = {
projects: [
{ name: 'a', setup: [/100/, 100] },
],
};
`,
'a.test.ts': `
const { test } = pwt;
test('pass', async () => {});
`
});
expect(result.exitCode).toBe(1);
expect(result.output).toContain(`Error: playwright.config.ts: config.projects[0].setup[1] must be a string or a RegExp`);
});

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

@ -98,7 +98,7 @@ function expectFilesRunBefore(timeline: Timeline, before: string[], after: strin
test('should work for one project', async ({ runGroups }, testInfo) => {
const projectTemplates = {
'a': {
setup: ['**/*.setup.ts']
_setup: ['**/*.setup.ts']
},
};
const configWithFiles = createConfigWithProjects(['a'], testInfo, projectTemplates);
@ -114,13 +114,13 @@ a > a${path.sep}a.spec.ts > a test [end]`);
test('should work for several projects', async ({ runGroups }, testInfo) => {
const projectTemplates = {
'a': {
setup: ['**/*.setup.ts']
_setup: ['**/*.setup.ts']
},
'b': {
setup: /.*b.setup.ts/
_setup: /.*b.setup.ts/
},
'c': {
setup: '**/c.setup.ts'
_setup: '**/c.setup.ts'
},
};
const configWithFiles = createConfigWithProjects(['a', 'b', 'c'], testInfo, projectTemplates);
@ -134,10 +134,10 @@ test('should work for several projects', async ({ runGroups }, testInfo) => {
test('should stop project if setup fails', async ({ runGroups }, testInfo) => {
const projectTemplates = {
'a': {
setup: ['**/*.setup.ts']
_setup: ['**/*.setup.ts']
},
'b': {
setup: /.*b.setup.ts/
_setup: /.*b.setup.ts/
},
};
const configWithFiles = createConfigWithProjects(['a', 'b', 'c'], testInfo, projectTemplates);
@ -162,7 +162,7 @@ test('should run setup in each project shard', async ({ runGroups }, testInfo) =
projects: [
{
name: 'p1',
setup: /.*.setup.ts/,
_setup: /.*.setup.ts/,
},
]
};`,
@ -210,12 +210,12 @@ test('should run setup only for projects that have tests in the shard', async ({
projects: [
{
name: 'p1',
setup: /.*p1.setup.ts$/,
_setup: /.*p1.setup.ts$/,
testMatch: /.*a.test.ts/,
},
{
name: 'p2',
setup: /.*p2.setup.ts$/,
_setup: /.*p2.setup.ts$/,
testMatch: /.*b.test.ts/,
},
]
@ -265,10 +265,10 @@ test('should run setup only for projects that have tests in the shard', async ({
test('--project only runs setup from that project;', async ({ runGroups }, testInfo) => {
const projectTemplates = {
'a': {
setup: /.*a.setup.ts/
_setup: /.*a.setup.ts/
},
'b': {
setup: /.*b.setup.ts/
_setup: /.*b.setup.ts/
},
};
const configWithFiles = createConfigWithProjects(['a', 'b', 'c'], testInfo, projectTemplates);
@ -285,7 +285,7 @@ test('same file cannot be a setup and a test in the same project', async ({ runG
projects: [
{
name: 'p1',
setup: /.*a.test.ts$/,
_setup: /.*a.test.ts$/,
testMatch: /.*a.test.ts$/,
},
]
@ -308,12 +308,12 @@ test('same file cannot be a setup and a test in different projects', async ({ ru
projects: [
{
name: 'p1',
setup: /.*a.test.ts$/,
_setup: /.*a.test.ts$/,
testMatch: /.*noMatch.test.ts$/,
},
{
name: 'p2',
setup: /.*noMatch.test.ts$/,
_setup: /.*noMatch.test.ts$/,
testMatch: /.*a.test.ts$/
},
]

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

@ -24,14 +24,14 @@ test('should provide storage fixture', async ({ runInlineTest }) => {
'a.test.ts': `
const { test } = pwt;
test('should store number', async ({ }) => {
const storage = test.info().storage();
const storage = test.info()._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 ({ }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(storage).toBeTruthy();
expect(await storage.get('object')).toBe(undefined);
await storage.set('object', { 'a': 2022 })
@ -50,7 +50,7 @@ test('should share storage state between project setup and tests', async ({ runI
projects: [
{
name: 'p1',
setup: /.*storage.setup.ts/
_setup: /.*storage.setup.ts/
}
]
};
@ -58,7 +58,7 @@ test('should share storage state between project setup and tests', async ({ runI
'storage.setup.ts': `
const { test, expect } = pwt;
test('should initialize storage', async ({ }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(await storage.get('number')).toBe(undefined);
await storage.set('number', 2022)
expect(await storage.get('number')).toBe(2022);
@ -71,7 +71,7 @@ test('should share storage state between project setup and tests', async ({ runI
'a.test.ts': `
const { test } = pwt;
test('should get data from setup', async ({ }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(await storage.get('number')).toBe(2022);
expect(await storage.get('object')).toEqual({ 'a': 2022 });
});
@ -79,7 +79,7 @@ test('should share storage state between project setup and tests', async ({ runI
'b.test.ts': `
const { test } = pwt;
test('should get data from setup', async ({ }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(await storage.get('number')).toBe(2022);
expect(await storage.get('object')).toEqual({ 'a': 2022 });
});
@ -97,7 +97,7 @@ test('should persist storage state between project runs', async ({ runInlineTest
'a.test.ts': `
const { test } = pwt;
test('should have no data on first run', async ({ }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(await storage.get('number')).toBe(undefined);
await storage.set('number', 2022)
expect(await storage.get('object')).toBe(undefined);
@ -107,7 +107,7 @@ test('should persist storage state between project runs', async ({ runInlineTest
'b.test.ts': `
const { test } = pwt;
test('should get data from previous run', async ({ }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(await storage.get('number')).toBe(2022);
expect(await storage.get('object')).toEqual({ 'a': 2022 });
});
@ -132,11 +132,11 @@ test('should isolate storage state between projects', async ({ runInlineTest })
projects: [
{
name: 'p1',
setup: /.*storage.setup.ts/
_setup: /.*storage.setup.ts/
},
{
name: 'p2',
setup: /.*storage.setup.ts/
_setup: /.*storage.setup.ts/
}
]
};
@ -144,7 +144,7 @@ test('should isolate storage state between projects', async ({ runInlineTest })
'storage.setup.ts': `
const { test, expect } = pwt;
test('should initialize storage', async ({ }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(await storage.get('number')).toBe(undefined);
await storage.set('number', 2022)
expect(await storage.get('number')).toBe(2022);
@ -157,7 +157,7 @@ test('should isolate storage state between projects', async ({ runInlineTest })
'a.test.ts': `
const { test } = pwt;
test('should get data from setup', async ({ }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(await storage.get('number')).toBe(2022);
expect(await storage.get('name')).toBe('str-' + test.info().project.name);
});
@ -165,7 +165,7 @@ test('should isolate storage state between projects', async ({ runInlineTest })
'b.test.ts': `
const { test } = pwt;
test('should get data from setup', async ({ }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(await storage.get('number')).toBe(2022);
expect(await storage.get('name')).toBe('str-' + test.info().project.name);
});
@ -186,7 +186,7 @@ test('should load context storageState from storage', async ({ runInlineTest, se
projects: [
{
name: 'p1',
setup: /.*storage.setup.ts/
_setup: /.*storage.setup.ts/
}
]
};
@ -194,7 +194,7 @@ test('should load context storageState from storage', async ({ runInlineTest, se
'storage.setup.ts': `
const { test, expect } = pwt;
test('should save storageState', async ({ page, context }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(await storage.get('user')).toBe(undefined);
await page.goto('${server.PREFIX}/setcookie.html');
const state = await page.context().storageState();
@ -204,7 +204,7 @@ test('should load context storageState from storage', async ({ runInlineTest, se
'a.test.ts': `
const { test } = pwt;
test.use({
storageStateName: 'user'
_storageStateName: 'user'
})
test('should get data from setup', async ({ page }) => {
await page.goto('${server.EMPTY_PAGE}');
@ -225,7 +225,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 storage', async ({ runInlineTest, server }) => {
server.setRoute('/setcookie.html', (req, res) => {
res.setHeader('Set-Cookie', ['a=v1']);
res.end();
@ -236,9 +236,9 @@ test('should load storageStateName specified in the project config from storage'
projects: [
{
name: 'p1',
setup: /.*storage.setup.ts/,
_setup: /.*storage.setup.ts/,
use: {
storageStateName: 'stateInStorage',
_storageStateName: 'stateInStorage',
},
}
]
@ -247,10 +247,10 @@ test('should load storageStateName specified in the project config from storage'
'storage.setup.ts': `
const { test, expect } = pwt;
test.use({
storageStateName: ({}, use) => use(undefined),
_storageStateName: ({}, use) => use(undefined),
})
test('should save storageState', async ({ page, context }) => {
const storage = test.info().storage();
const storage = test.info()._storage();
expect(await storage.get('stateInStorage')).toBe(undefined);
await page.goto('${server.PREFIX}/setcookie.html');
const state = await page.context().storageState();
@ -270,7 +270,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 storage', async ({ runInlineTest, server }) => {
server.setRoute('/setcookie.html', (req, res) => {
res.setHeader('Set-Cookie', ['a=v1']);
res.end();
@ -279,12 +279,12 @@ test('should load storageStateName specified in the global config from storage',
'playwright.config.js': `
module.exports = {
use: {
storageStateName: 'stateInStorage',
_storageStateName: 'stateInStorage',
},
projects: [
{
name: 'p1',
setup: /.*storage.setup.ts/,
_setup: /.*storage.setup.ts/,
}
]
};
@ -292,10 +292,10 @@ test('should load storageStateName specified in the global config from storage',
'storage.setup.ts': `
const { test, expect } = pwt;
test.use({
storageStateName: ({}, use) => use(undefined),
_storageStateName: ({}, use) => use(undefined),
})
test('should save storageStateName', async ({ page, context }) => {
const storage = test.info().storage();
test('should save _storageStateName', async ({ page, context }) => {
const storage = test.info()._storage();
expect(await storage.get('stateInStorage')).toBe(undefined);
await page.goto('${server.PREFIX}/setcookie.html');
const state = await page.context().storageState();
@ -315,7 +315,7 @@ test('should load storageStateName specified in the global config from storage',
expect(result.passed).toBe(2);
});
test('should throw on unknown storageStateName value', async ({ runInlineTest, server }) => {
test('should throw on unknown _storageStateName value', async ({ runInlineTest, server }) => {
const result = await runInlineTest({
'playwright.config.js': `
module.exports = {
@ -323,7 +323,7 @@ test('should throw on unknown storageStateName value', async ({ runInlineTest, s
{
name: 'p1',
use: {
storageStateName: 'stateInStorage',
_storageStateName: 'stateInStorage',
},
}
]

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

@ -188,18 +188,3 @@ test('config should allow void/empty options', async ({ runTSC }) => {
});
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);
});

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

@ -196,11 +196,6 @@ type ConnectOptions = {
timeout?: number;
};
export 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;
@ -233,7 +228,6 @@ export interface PlaywrightTestOptions {
permissions: string[] | undefined;
proxy: Proxy | undefined;
storageState: StorageState | undefined;
storageStateName: string | undefined;
timezoneId: string | undefined;
userAgent: string | undefined;
viewport: ViewportSize | null | undefined;