chore: setup -> test.projectSetup (#19932)

* Changed `setup` to `test.projectSetup`
* Only `test.projectSetup.only` is supported on the new method
* test.* methods except for before/after/Each/All hooks can be called
inside the project setup files
This commit is contained in:
Yury Semikhatsky 2023-01-09 11:21:48 -08:00 committed by GitHub
parent e3d615e9f2
commit a39a97f0ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 184 additions and 158 deletions

View File

@ -1174,6 +1174,22 @@ Test title.
Test function that takes one or two arguments: an object with fixtures and optional [TestInfo].
## method: Test.projectSetup
* since: v1.30
Declares a project setup function. The function will be run before all other tests in the same project and if it fails the project execution will be aborted.
### param: Test.projectSetup.title
* since: v1.30
- `title` <[string]>
Project setup title.
### param: Test.projectSetup.testFunction
* since: v1.30
- `testFunction` <[function]\([Fixtures], [TestInfo]\)>
Project setup function that takes one or two arguments: an object with fixtures and optional [TestInfo].
## method: Test.setTimeout

View File

@ -23,7 +23,7 @@ import { removeFolders } from 'playwright-core/lib/utils/fileUtils';
import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, ScreenshotMode, TestInfo, TestType, TraceMode, VideoMode } from '../types/test';
import { store as _baseStore } from './store';
import type { TestInfoImpl } from './testInfo';
import { rootTestType, _setProjectSetup } from './testType';
import { rootTestType } from './testType';
import { type ContextReuseMode } from './types';
export { expect } from './expect';
export { addRunnerPlugin as _addRunnerPlugin } from './plugins';
@ -634,7 +634,5 @@ function normalizeScreenshotMode(screenshot: PlaywrightWorkerOptions['screenshot
const kTracingStarted = Symbol('kTracingStarted');
export const test = _baseTest.extend<TestFixtures, WorkerFixtures>(playwrightFixtures);
export const setup = _baseTest.extend<TestFixtures, WorkerFixtures>(playwrightFixtures);
_setProjectSetup(setup, true);
export default test;

View File

@ -26,8 +26,6 @@ const testTypeSymbol = Symbol('testType');
export class TestTypeImpl {
readonly fixtures: FixturesWithLocation[];
readonly test: TestType<any, any>;
// Wether the test is 'setup' which should only be called inside project setup files.
_projectSetup: boolean = false;
constructor(fixtures: FixturesWithLocation[]) {
this.fixtures = fixtures;
@ -57,6 +55,8 @@ export class TestTypeImpl {
test.step = wrapFunctionWithLocation(this._step.bind(this));
test.use = wrapFunctionWithLocation(this._use.bind(this));
test.extend = wrapFunctionWithLocation(this._extend.bind(this));
test.projectSetup = wrapFunctionWithLocation(this._createTest.bind(this, 'projectSetup'));
(test.projectSetup as any).only = wrapFunctionWithLocation(this._createTest.bind(this, 'projectSetupOnly'));
test._extendTest = wrapFunctionWithLocation(this._extendTest.bind(this));
test.info = () => {
const result = currentTestInfo();
@ -67,7 +67,7 @@ export class TestTypeImpl {
this.test = test;
}
private _currentSuite(location: Location, title: string): Suite | undefined {
private _currentSuite(location: Location, title: string, allowedContext: 'test' | 'projectSetup' | 'any'): Suite | undefined {
const suite = currentlyLoadingFileSuite();
if (!suite) {
addFatalError([
@ -80,18 +80,28 @@ export class TestTypeImpl {
].join('\n'), location);
return;
}
if (this._projectSetup !== suite._isProjectSetup) {
if (this._projectSetup)
addFatalError(`${title} is called in a file which is not a part of project setup.`, location);
else
addFatalError(`${title} is called in a project setup file (use 'setup' instead of 'test').`, location);
}
if (allowedContext === 'projectSetup' && !suite._isProjectSetup)
addFatalError(`${title} is only allowed in a project setup file.`, location);
else if (allowedContext === 'test' && suite._isProjectSetup)
addFatalError(`${title} is not allowed in a project setup file.`, location);
return suite;
}
private _createTest(type: 'default' | 'only' | 'skip' | 'fixme', location: Location, title: string, fn: Function) {
private _createTest(type: 'default' | 'only' | 'skip' | 'fixme' | 'projectSetup' | 'projectSetupOnly', location: Location, title: string, fn: Function) {
throwIfRunningInsideJest();
const suite = this._currentSuite(location, this._projectSetup ? 'setup()' : 'test()');
let functionTitle = 'test()';
let allowedContext: 'test' | 'projectSetup' | 'any' = 'any';
switch (type) {
case 'projectSetup':
case 'projectSetupOnly':
functionTitle = 'test.projectSetup()';
allowedContext = 'projectSetup';
break;
case 'default':
allowedContext = 'test';
break;
}
const suite = this._currentSuite(location, functionTitle, allowedContext);
if (!suite)
return;
const test = new TestCase(title, fn, this, location);
@ -99,7 +109,7 @@ export class TestTypeImpl {
test._isProjectSetup = suite._isProjectSetup;
suite._addTest(test);
if (type === 'only')
if (type === 'only' || type === 'projectSetupOnly')
test._only = true;
if (type === 'skip' || type === 'fixme') {
test.annotations.push({ type });
@ -113,7 +123,7 @@ export class TestTypeImpl {
private _describe(type: 'default' | 'only' | 'serial' | 'serial.only' | 'parallel' | 'parallel.only' | 'skip' | 'fixme', location: Location, title: string | Function, fn?: Function) {
throwIfRunningInsideJest();
const suite = this._currentSuite(location, this._projectSetup ? 'setup.describe()' : 'test.describe()');
const suite = this._currentSuite(location, 'test.describe()', 'any');
if (!suite)
return;
@ -150,7 +160,7 @@ export class TestTypeImpl {
}
private _hook(name: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll', location: Location, fn: Function) {
const suite = this._currentSuite(location, `${this._projectSetup ? 'setup' : 'test'}.${name}()`);
const suite = this._currentSuite(location, `test.${name}()`, 'test');
if (!suite)
return;
suite._hooks.push({ type: name, fn, location });
@ -158,7 +168,7 @@ export class TestTypeImpl {
private _configure(location: Location, options: { mode?: 'parallel' | 'serial', retries?: number, timeout?: number }) {
throwIfRunningInsideJest();
const suite = this._currentSuite(location, `${this._projectSetup ? 'setup' : 'test'}.describe.configure()`);
const suite = this._currentSuite(location, `test.describe.configure()`, 'any');
if (!suite)
return;
@ -225,7 +235,7 @@ export class TestTypeImpl {
}
private _use(location: Location, fixtures: Fixtures) {
const suite = this._currentSuite(location, `${this._projectSetup ? 'setup' : 'test'}.use()`);
const suite = this._currentSuite(location, `test.use()`, 'any');
if (!suite)
return;
suite._use.push({ fixtures, location });
@ -234,7 +244,7 @@ export class TestTypeImpl {
private async _step<T>(location: Location, title: string, body: () => Promise<T>): Promise<T> {
const testInfo = currentTestInfo();
if (!testInfo) {
addFatalError(`${this._projectSetup ? 'setup' : 'test'}.step() can only be called from a test`, location);
addFatalError(`test.step() can only be called from a test`, location);
return undefined as any;
}
const step = testInfo._addStep({
@ -281,11 +291,4 @@ function throwIfRunningInsideJest() {
}
}
export function _setProjectSetup(test: TestType<any, any>, projectSetup: boolean) {
const testTypeImpl = (test as any)[testTypeSymbol] as TestTypeImpl;
if (!testTypeImpl)
throw new Error(`Argument is not a TestType`);
testTypeImpl._projectSetup = projectSetup;
}
export const rootTestType = new TestTypeImpl([]);

View File

@ -29,8 +29,8 @@ function createConfigWithProjects(names: string[], testInfo: TestInfo, projectTe
await new Promise(f => setTimeout(f, 100));
});`;
files[`${name}/${name}.setup.ts`] = `
const { setup } = pwt;
setup('${name} setup', async () => {
const { test } = pwt;
test.projectSetup('${name} setup', async () => {
await new Promise(f => setTimeout(f, 100));
});`;
}
@ -142,8 +142,8 @@ test('should stop project if setup fails', async ({ runGroups }, testInfo) => {
};
const configWithFiles = createConfigWithProjects(['a', 'b', 'c'], testInfo, projectTemplates);
configWithFiles[`a/a.setup.ts`] = `
const { setup, expect } = pwt;
setup('a setup', async () => {
const { test, expect } = pwt;
test.projectSetup('a setup', async () => {
expect(1).toBe(2);
});`;
@ -179,9 +179,9 @@ test('should run setup in each project shard', async ({ runGroups }, testInfo) =
test('test2', async () => { });
`,
'c.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
setup('setup2', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
test.projectSetup('setup2', async () => { });
`,
};
@ -233,14 +233,14 @@ test('should run setup only for projects that have tests in the shard', async ({
test('test2', async () => { });
`,
'p1.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
setup('setup2', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
test.projectSetup('setup2', async () => { });
`,
'p2.setup.ts': `
const { setup } = pwt;
setup('setup3', async () => { });
setup('setup4', async () => { });
const { test } = pwt;
test.projectSetup('setup3', async () => { });
test.projectSetup('setup4', async () => { });
`,
};
@ -347,20 +347,20 @@ test('list-files should enumerate setup files in same group', async ({ runComman
]
};`,
'a1.setup.ts': `
const { setup } = pwt;
setup('test1', async () => { });
const { test } = pwt;
test.projectSetup('test1', async () => { });
`,
'a2.setup.ts': `
const { setup } = pwt;
setup('test1', async () => { });
const { test } = pwt;
test.projectSetup('test1', async () => { });
`,
'a.test.ts': `
const { test } = pwt;
test('test2', async () => { });
`,
'b.setup.ts': `
const { setup } = pwt;
setup('test3', async () => { });
const { test } = pwt;
test.projectSetup('test3', async () => { });
`,
'b.test.ts': `
const { test } = pwt;
@ -394,20 +394,20 @@ test('test --list should enumerate setup tests as regular ones', async ({ runCom
]
};`,
'a1.setup.ts': `
const { setup } = pwt;
setup('test1', async () => { });
const { test } = pwt;
test.projectSetup('test1', async () => { });
`,
'a2.setup.ts': `
const { setup } = pwt;
setup('test1', async () => { });
const { test } = pwt;
test.projectSetup('test1', async () => { });
`,
'a.test.ts': `
const { test } = pwt;
test('test2', async () => { });
`,
'b.setup.ts': `
const { setup } = pwt;
setup('test3', async () => { });
const { test } = pwt;
test.projectSetup('test3', async () => { });
`,
'b.test.ts': `
const { test } = pwt;
@ -419,9 +419,9 @@ test('test --list should enumerate setup tests as regular ones', async ({ runCom
expect(exitCode).toBe(0);
expect(output).toContain(`Listing tests:
[p1] a.test.ts:6:7 test2
[p1] a1.setup.ts:5:7 test1
[p1] a2.setup.ts:5:7 test1
[p2] b.setup.ts:5:7 test3
[p1] a1.setup.ts:5:12 test1
[p1] a2.setup.ts:5:12 test1
[p2] b.setup.ts:5:12 test3
[p2] b.test.ts:6:7 test4
Total: 5 tests in 5 files`);
});
@ -445,17 +445,17 @@ test('should allow .only in setup files', async ({ runGroups }, testInfo) => {
test('test4', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup.only('setup1', async () => { });
setup('setup2', async () => { });
setup.only('setup3', async () => { });
const { test } = pwt;
test.projectSetup.only('setup1', async () => { });
test.projectSetup('setup2', async () => { });
test.projectSetup.only('setup3', async () => { });
`,
};
const { exitCode, passed, timeline, output } = await runGroups(files);
expect(output).toContain('Running 2 tests using 1 worker');
expect(output).toContain('[p1] a.setup.ts:5:13 setup1');
expect(output).toContain('[p1] a.setup.ts:7:13 setup3');
expect(output).toContain('[p1] a.setup.ts:5:25 setup1');
expect(output).toContain('[p1] a.setup.ts:7:25 setup3');
expect(fileNames(timeline)).toEqual(['a.setup.ts']);
expect(exitCode).toBe(0);
expect(passed).toBe(2);
@ -480,19 +480,19 @@ test('should allow describe.only in setup files', async ({ runGroups }, testInfo
test('test4', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup.describe.only('main', () => {
setup('setup1', async () => { });
setup('setup2', async () => { });
const { test } = pwt;
test.describe.only('main', () => {
test.projectSetup('setup1', async () => { });
test.projectSetup('setup2', async () => { });
});
setup('setup3', async () => { });
test.projectSetup('setup3', async () => { });
`,
};
const { exitCode, passed, timeline, output } = await runGroups(files);
expect(output).toContain('Running 2 tests using 1 worker');
expect(output).toContain('[p1] a.setup.ts:6:9 main setup1');
expect(output).toContain('[p1] a.setup.ts:7:9 main setup2');
expect(output).toContain('[p1] a.setup.ts:6:14 main setup1');
expect(output).toContain('[p1] a.setup.ts:7:14 main setup2');
expect(fileNames(timeline)).toEqual(['a.setup.ts']);
expect(exitCode).toBe(0);
expect(passed).toBe(2);
@ -517,19 +517,19 @@ test('should filter describe line in setup files', async ({ runGroups }, testInf
test('test4', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup.describe('main', () => {
setup('setup1', async () => { });
setup('setup2', async () => { });
const { test } = pwt;
test.describe('main', () => {
test.projectSetup('setup1', async () => { });
test.projectSetup('setup2', async () => { });
});
setup('setup3', async () => { });
test.projectSetup('setup3', async () => { });
`,
};
const { exitCode, passed, timeline, output } = await runGroups(files, undefined, undefined, { additionalArgs: ['a.setup.ts:5'] });
expect(output).toContain('Running 2 tests using 1 worker');
expect(output).toContain('[p1] a.setup.ts:6:9 main setup1');
expect(output).toContain('[p1] a.setup.ts:7:9 main setup2');
expect(output).toContain('[p1] a.setup.ts:6:14 main setup1');
expect(output).toContain('[p1] a.setup.ts:7:14 main setup2');
expect(fileNames(timeline)).toEqual(['a.setup.ts']);
expect(exitCode).toBe(0);
expect(passed).toBe(2);
@ -554,16 +554,16 @@ test('should allow .only in both setup and test files', async ({ runGroups }, te
test('test4', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup.only('setup1', async () => { });
setup('setup2', async () => { });
setup('setup3', async () => { });
const { test } = pwt;
test.projectSetup.only('setup1', async () => { });
test.projectSetup('setup2', async () => { });
test.projectSetup('setup3', async () => { });
`,
};
const { exitCode, output } = await runGroups(files);
expect(exitCode).toBe(0);
expect(output).toContain('[p1] a.setup.ts:5:13 setup1');
expect(output).toContain('[p1] a.setup.ts:5:25 setup1');
expect(output).toContain('[p1] a.test.ts:7:12 test2');
});
@ -586,13 +586,13 @@ test('should run full setup when there is test.only', async ({ runGroups }, test
test('test4', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
setup('setup2', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
test.projectSetup('setup2', async () => { });
`,
'b.setup.ts': `
const { setup } = pwt;
setup('setup3', async () => { });
const { test } = pwt;
test.projectSetup('setup3', async () => { });
`,
};
@ -600,9 +600,9 @@ test('should run full setup when there is test.only', async ({ runGroups }, test
expect(exitCode).toBe(0);
expect(passed).toBe(4);
expect(output).toContain('Running 4 tests using 2 workers');
expect(output).toContain('[p1] b.setup.ts:5:7 setup3');
expect(output).toContain('[p1] a.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:6:7 setup2');
expect(output).toContain('[p1] b.setup.ts:5:12 setup3');
expect(output).toContain('[p1] a.setup.ts:5:12 setup1');
expect(output).toContain('[p1] a.setup.ts:6:12 setup2');
expect(output).toContain('[p1] a.test.ts:6:12 test1');
});
@ -628,13 +628,13 @@ test('should allow filtering setup by file:line', async ({ runGroups }, testInfo
test('test3', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
setup('setup2', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
test.projectSetup('setup2', async () => { });
`,
'b.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
`,
'b.test.ts': `
const { test } = pwt;
@ -647,16 +647,16 @@ test('should allow filtering setup by file:line', async ({ runGroups }, testInfo
{
const { exitCode, passed, output } = await runGroups(files, undefined, undefined, { additionalArgs: ['.*setup.ts$'] });
expect(output).toContain('Running 3 tests using 2 workers');
expect(output).toContain('[p1] a.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:6:7 setup2');
expect(output).toContain('[p2] b.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:5:12 setup1');
expect(output).toContain('[p1] a.setup.ts:6:12 setup2');
expect(output).toContain('[p2] b.setup.ts:5:12 setup1');
expect(exitCode).toBe(0);
expect(passed).toBe(3);
}
{
const { exitCode, passed, output } = await runGroups(files, undefined, undefined, { additionalArgs: ['.*a.setup.ts:5'] });
expect(output).toContain('Running 1 test using 1 worker');
expect(output).toContain('[p1] a.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:5:12 setup1');
expect(exitCode).toBe(0);
expect(passed).toBe(1);
}
@ -680,13 +680,13 @@ test('should support filters matching both setup and test', async ({ runGroups }
test('test3', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
setup('setup2', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
test.projectSetup('setup2', async () => { });
`,
'b.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
`,
'b.test.ts': `
const { test } = pwt;
@ -697,8 +697,8 @@ test('should support filters matching both setup and test', async ({ runGroups }
const { exitCode, output } = await runGroups(files, undefined, undefined, { additionalArgs: ['.*a.(setup|test).ts$'] });
expect(exitCode).toBe(0);
expect(output).toContain('Running 5 tests using 1 worker');
expect(output).toContain('[p1] a.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:6:7 setup2');
expect(output).toContain('[p1] a.setup.ts:5:12 setup1');
expect(output).toContain('[p1] a.setup.ts:6:12 setup2');
expect(output).toContain('[p1] a.test.ts:6:7 test1');
expect(output).toContain('[p1] a.test.ts:7:7 test2');
expect(output).toContain('[p1] a.test.ts:8:7 test3');
@ -726,12 +726,12 @@ test('should run setup for a project if tests match only in another project', as
test('test1', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
`,
'b.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
`,
'b.test.ts': `
const { test } = pwt;
@ -742,9 +742,9 @@ test('should run setup for a project if tests match only in another project', as
const { exitCode, output } = await runGroups(files, undefined, undefined, { additionalArgs: ['.*a.test.ts$'] });
expect(exitCode).toBe(0);
expect(output).toContain('Running 3 tests using 2 workers');
expect(output).toContain('[p1] a.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:5:12 setup1');
expect(output).toContain('[p1] a.test.ts:6:7 test1');
expect(output).toContain('[p2] b.setup.ts:5:7 setup1');
expect(output).toContain('[p2] b.setup.ts:5:12 setup1');
});
test('should run all setup files if only tests match filter', async ({ runGroups }, testInfo) => {
@ -765,22 +765,22 @@ test('should run all setup files if only tests match filter', async ({ runGroups
test('test3', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
setup('setup2', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
test.projectSetup('setup2', async () => { });
`,
'b.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
`,
};
const { exitCode, output } = await runGroups(files, undefined, undefined, { additionalArgs: ['a.test.ts:7'] });
expect(exitCode).toBe(0);
expect(output).toContain('Running 4 tests using 2 workers');
expect(output).toContain('[p1] a.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:6:7 setup2');
expect(output).toContain('[p1] b.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:5:12 setup1');
expect(output).toContain('[p1] a.setup.ts:6:12 setup2');
expect(output).toContain('[p1] b.setup.ts:5:12 setup1');
expect(output).toContain('[p1] a.test.ts:7:7 test2');
});
@ -802,22 +802,22 @@ test('should run all setup files if only tests match grep filter', async ({ runG
test('test3', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
setup('setup2', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
test.projectSetup('setup2', async () => { });
`,
'b.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
`,
};
const { exitCode, output } = await runGroups(files, undefined, undefined, { additionalArgs: ['--grep', '.*test2$'] });
expect(exitCode).toBe(0);
expect(output).toContain('Running 4 tests using 2 workers');
expect(output).toContain('[p1] a.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:6:7 setup2');
expect(output).toContain('[p1] b.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:5:12 setup1');
expect(output).toContain('[p1] a.setup.ts:6:12 setup2');
expect(output).toContain('[p1] b.setup.ts:5:12 setup1');
expect(output).toContain('[p1] a.test.ts:7:7 test2');
});
@ -840,21 +840,21 @@ test('should apply project.grep filter to both setup and tests', async ({ runGro
test('foo', async () => { });
`,
'a.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
setup('setup2', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
test.projectSetup('setup2', async () => { });
`,
'b.setup.ts': `
const { setup } = pwt;
setup('setup1', async () => { });
setup('foo', async () => { });
const { test } = pwt;
test.projectSetup('setup1', async () => { });
test.projectSetup('foo', async () => { });
`,
};
const { exitCode, output } = await runGroups(files);
expect(exitCode).toBe(0);
expect(output).toContain('[p1] a.setup.ts:5:7 setup1');
expect(output).toContain('[p1] a.setup.ts:6:7 setup2');
expect(output).toContain('[p1] a.setup.ts:5:12 setup1');
expect(output).toContain('[p1] a.setup.ts:6:12 setup2');
expect(output).toContain('[p1] a.test.ts:6:7 test1');
expect(output).toContain('[p1] a.test.ts:7:7 test2');
});
@ -862,28 +862,37 @@ test('should apply project.grep filter to both setup and tests', async ({ runGro
test('should prohibit setup in test files', async ({ runGroups }, testInfo) => {
const files = {
'a.test.ts': `
const { setup, test } = pwt;
setup('test1', async () => { });
const { test } = pwt;
test.projectSetup('test1', async () => { });
test('test2', async () => { });
`,
};
const { exitCode, output } = await runGroups(files);
expect(exitCode).toBe(1);
expect(output).toContain('setup() is called in a file which is not a part of project setup.');
expect(output).toContain('test.projectSetup() is only allowed in a project setup file.');
});
test('should prohibit setup hooks in test files', async ({ runGroups }, testInfo) => {
test('should prohibit beforeAll hooks in setup files', async ({ runGroups }, testInfo) => {
const files = {
'a.test.ts': `
const { setup } = pwt;
setup.beforeAll(async () => { });
'playwright.config.ts': `
module.exports = {
projects: [
{
name: 'p1',
setupMatch: /.*.setup.ts/,
},
]
};`,
'a.setup.ts': `
const { test } = pwt;
test.beforeAll(async () => { });
`,
};
const { exitCode, output } = await runGroups(files);
expect(exitCode).toBe(1);
expect(output).toContain('setup.beforeAll() is called in a file which is not a part of project setup');
expect(output).toContain('test.beforeAll() is not allowed in a project setup file');
});
test('should prohibit test in setup files', async ({ runGroups }, testInfo) => {
@ -905,7 +914,7 @@ test('should prohibit test in setup files', async ({ runGroups }, testInfo) => {
const { exitCode, output } = await runGroups(files);
expect(exitCode).toBe(1);
expect(output).toContain('test() is called in a project setup file');
expect(output).toContain('test() is not allowed in a project setup file');
});
test('should prohibit test hooks in setup files', async ({ runGroups }, testInfo) => {
@ -927,5 +936,5 @@ test('should prohibit test hooks in setup files', async ({ runGroups }, testInfo
const { exitCode, output } = await runGroups(files);
expect(exitCode).toBe(1);
expect(output).toContain('test.beforeEach() is called in a project setup file');
expect(output).toContain('test.beforeEach() is not allowed in a project setup file');
});

View File

@ -54,8 +54,8 @@ test('should share store state between project setup and tests', async ({ runInl
};
`,
'store.setup.ts': `
const { setup, expect, store } = pwt;
setup('should initialize store', async ({ }) => {
const { test, expect, store } = pwt;
test.projectSetup('should initialize store', async ({ }) => {
expect(await store.get('number')).toBe(undefined);
await store.set('number', 2022)
expect(await store.get('number')).toBe(2022);
@ -135,15 +135,15 @@ test('should isolate store state between projects', async ({ runInlineTest }) =>
};
`,
'store.setup.ts': `
const { setup, expect, store } = pwt;
setup('should initialize store', async ({ }) => {
const { test, expect, store } = pwt;
test.projectSetup('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 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);
await store.set('name', 'str-' + test.info().project.name)
expect(await store.get('name')).toBe('str-' + test.info().project.name);
});
`,
'a.test.ts': `
@ -182,8 +182,8 @@ test('should load context storageState from store', async ({ runInlineTest, serv
};
`,
'store.setup.ts': `
const { setup, expect, store } = pwt;
setup('should save storageState', async ({ page, context }) => {
const { test, expect, store } = pwt;
test.projectSetup('should save storageState', async ({ page, context }) => {
expect(await store.get('user')).toBe(undefined);
await page.goto('${server.PREFIX}/setcookie.html');
const state = await page.context().storageState();
@ -234,11 +234,11 @@ test('should load storageStateName specified in the project config from store',
};
`,
'store.setup.ts': `
const { setup, expect, store } = pwt;
setup.use({
const { test, expect, store } = pwt;
test.use({
storageStateName: ({}, use) => use(undefined),
})
setup('should save storageState', async ({ page, context }) => {
test.projectSetup('should save storageState', async ({ page, context }) => {
expect(await store.get('stateInStorage')).toBe(undefined);
await page.goto('${server.PREFIX}/setcookie.html');
const state = await page.context().storageState();
@ -278,11 +278,11 @@ test('should load storageStateName specified in the global config from store', a
};
`,
'store.setup.ts': `
const { setup, expect, store } = pwt;
setup.use({
const { test, expect, store } = pwt;
test.use({
storageStateName: ({}, use) => use(undefined),
})
setup('should save storageStateName', async ({ page, context }) => {
test.projectSetup('should save storageStateName', async ({ page, context }) => {
expect(await store.get('stateInStorage')).toBe(undefined);
await page.goto('${server.PREFIX}/setcookie.html');
const state = await page.context().storageState();