mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-13 17:14:02 +03:00
feat: use setup() instead of test() for project setup (#19281)
This commit is contained in:
parent
81c8620bfe
commit
f9ef18912d
@ -32,6 +32,7 @@ export type TestGroup = {
|
||||
projectId: string;
|
||||
tests: TestCase[];
|
||||
watchMode: boolean;
|
||||
isProjectSetup: boolean;
|
||||
};
|
||||
|
||||
type TestResultData = {
|
||||
@ -567,6 +568,7 @@ class Worker extends EventEmitter {
|
||||
return { testId: test.id, retry: test.results.length };
|
||||
}),
|
||||
watchMode: testGroup.watchMode,
|
||||
projectSetup: testGroup.isProjectSetup,
|
||||
};
|
||||
this.send({ method: 'run', params: runPayload });
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ 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';
|
||||
import type { PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo, TestType, TraceMode, VideoMode } from '../types/test';
|
||||
import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo, TestType, TraceMode, VideoMode } from '../types/test';
|
||||
import type { TestInfoImpl } from './testInfo';
|
||||
import { rootTestType } from './testType';
|
||||
import { rootTestType, _setProjectSetup } from './testType';
|
||||
export { expect } from './expect';
|
||||
export { addRunnerPlugin as _addRunnerPlugin } from './plugins';
|
||||
export const _baseTest: TestType<{}, {}> = rootTestType.test;
|
||||
@ -53,7 +53,7 @@ type WorkerFixtures = PlaywrightWorkerArgs & PlaywrightWorkerOptions & {
|
||||
_snapshotSuffix: string;
|
||||
};
|
||||
|
||||
export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
||||
const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||
defaultBrowserType: ['chromium', { scope: 'worker', option: true }],
|
||||
browserName: [({ defaultBrowserType }, use) => use(defaultBrowserType), { scope: 'worker', option: true }],
|
||||
playwright: [async ({ }, use) => {
|
||||
@ -627,4 +627,8 @@ export function shouldCaptureTrace(traceMode: TraceMode, testInfo: TestInfo) {
|
||||
|
||||
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;
|
||||
|
@ -96,6 +96,7 @@ export type RunPayload = {
|
||||
file: string;
|
||||
entries: TestEntry[];
|
||||
watchMode: boolean;
|
||||
projectSetup: boolean;
|
||||
};
|
||||
|
||||
export type DonePayload = {
|
||||
|
@ -180,11 +180,12 @@ export class Loader {
|
||||
}
|
||||
}
|
||||
|
||||
async loadTestFile(file: string, environment: 'runner' | 'worker') {
|
||||
async loadTestFile(file: string, environment: 'runner' | 'worker', projectSetup: boolean) {
|
||||
if (cachedFileSuites.has(file))
|
||||
return cachedFileSuites.get(file)!;
|
||||
const suite = new Suite(path.relative(this._fullConfig.rootDir, file) || path.basename(file), 'file');
|
||||
suite._requireFile = file;
|
||||
suite._isProjectSetup = projectSetup;
|
||||
suite.location = { file, line: 0, column: 0 };
|
||||
|
||||
setCurrentlyLoadingFileSuite(suite);
|
||||
|
@ -280,7 +280,7 @@ export class Runner {
|
||||
const projects = this._collectProjects(options.projectFilter);
|
||||
const { filesByProject, setupFiles } = await this._collectFiles(projects, options.testFileFilters);
|
||||
|
||||
let result = await this._createFilteredRootSuite(options, filesByProject, new Set(), !!setupFiles.size);
|
||||
let result = await this._createFilteredRootSuite(options, filesByProject, new Set(), !!setupFiles.size, setupFiles);
|
||||
if (setupFiles.size) {
|
||||
const allTests = result.rootSuite.allTests();
|
||||
const tests = allTests.filter(test => !setupFiles.has(test._requireFile));
|
||||
@ -289,7 +289,7 @@ export class Runner {
|
||||
// - if the filter also matches some of the setup tests, we'll run only
|
||||
// that maching subset of setup tests.
|
||||
if (tests.length > 0 && tests.length === allTests.length)
|
||||
result = await this._createFilteredRootSuite(options, filesByProject, setupFiles, false);
|
||||
result = await this._createFilteredRootSuite(options, filesByProject, setupFiles, false, setupFiles);
|
||||
}
|
||||
|
||||
fatalErrors.push(...result.fatalErrors);
|
||||
@ -307,7 +307,7 @@ export class Runner {
|
||||
return { rootSuite, projectSetupGroups, testGroups };
|
||||
}
|
||||
|
||||
private async _createFilteredRootSuite(options: RunOptions, filesByProject: Map<FullProjectInternal, string[]>, doNotFilterFiles: Set<string>, shouldCloneTests: boolean): Promise<{rootSuite: Suite, fatalErrors: TestError[]}> {
|
||||
private async _createFilteredRootSuite(options: RunOptions, filesByProject: Map<FullProjectInternal, string[]>, doNotFilterFiles: Set<string>, shouldCloneTests: boolean, setupFiles: Set<string>): Promise<{rootSuite: Suite, fatalErrors: TestError[]}> {
|
||||
const config = this._loader.fullConfig();
|
||||
const fatalErrors: TestError[] = [];
|
||||
const allTestFiles = new Set<string>();
|
||||
@ -317,7 +317,7 @@ export class Runner {
|
||||
// Add all tests.
|
||||
const preprocessRoot = new Suite('', 'root');
|
||||
for (const file of allTestFiles) {
|
||||
const fileSuite = await this._loader.loadTestFile(file, 'runner');
|
||||
const fileSuite = await this._loader.loadTestFile(file, 'runner', setupFiles.has(file));
|
||||
if (fileSuite._loadError)
|
||||
fatalErrors.push(fileSuite._loadError);
|
||||
// We have to clone only if there maybe subsequent calls of this method.
|
||||
@ -824,6 +824,7 @@ function createTestGroups(projectSuites: Suite[], workers: number): TestGroup[]
|
||||
projectId: test._projectId,
|
||||
tests: [],
|
||||
watchMode: false,
|
||||
isProjectSetup: test._isProjectSetup,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,7 @@ class Base {
|
||||
title: string;
|
||||
_only = false;
|
||||
_requireFile: string = '';
|
||||
_isProjectSetup: boolean = false;
|
||||
|
||||
constructor(title: string) {
|
||||
this.title = title;
|
||||
@ -120,6 +121,7 @@ export class Suite extends Base implements reporterTypes.Suite {
|
||||
suite._only = this._only;
|
||||
suite.location = this.location;
|
||||
suite._requireFile = this._requireFile;
|
||||
suite._isProjectSetup = this._isProjectSetup;
|
||||
suite._use = this._use.slice();
|
||||
suite._hooks = this._hooks.slice();
|
||||
suite._timeout = this._timeout;
|
||||
@ -191,6 +193,7 @@ export class TestCase extends Base implements reporterTypes.TestCase {
|
||||
const test = new TestCase(this.title, this.fn, this._testType, this.location);
|
||||
test._only = this._only;
|
||||
test._requireFile = this._requireFile;
|
||||
test._isProjectSetup = this._isProjectSetup;
|
||||
test.expectedStatus = this.expectedStatus;
|
||||
test.annotations = this.annotations.slice();
|
||||
test._annotateWithInheritence = this._annotateWithInheritence;
|
||||
|
@ -26,6 +26,8 @@ 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;
|
||||
@ -77,14 +79,20 @@ export class TestTypeImpl {
|
||||
` when one of the dependencies in your package.json depends on @playwright/test.`,
|
||||
].join('\n'));
|
||||
}
|
||||
if (this._projectSetup !== suite._isProjectSetup) {
|
||||
if (this._projectSetup)
|
||||
throw errorWithLocation(location, `${title} is called in a file which is not a part of project setup.`);
|
||||
throw errorWithLocation(location, `${title} is called in a project setup file (use 'setup' instead of 'test').`);
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
private _createTest(type: 'default' | 'only' | 'skip' | 'fixme', location: Location, title: string, fn: Function) {
|
||||
throwIfRunningInsideJest();
|
||||
const suite = this._ensureCurrentSuite(location, 'test()');
|
||||
const suite = this._ensureCurrentSuite(location, this._projectSetup ? 'setup()' : 'test()');
|
||||
const test = new TestCase(title, fn, this, location);
|
||||
test._requireFile = suite._requireFile;
|
||||
test._isProjectSetup = suite._isProjectSetup;
|
||||
suite._addTest(test);
|
||||
|
||||
if (type === 'only')
|
||||
@ -101,7 +109,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._ensureCurrentSuite(location, 'test.describe()');
|
||||
const suite = this._ensureCurrentSuite(location, this._projectSetup ? 'setup.describe()' : 'test.describe()');
|
||||
|
||||
if (typeof title === 'function') {
|
||||
fn = title;
|
||||
@ -110,6 +118,7 @@ export class TestTypeImpl {
|
||||
|
||||
const child = new Suite(title, 'describe');
|
||||
child._requireFile = suite._requireFile;
|
||||
child._isProjectSetup = suite._isProjectSetup;
|
||||
child.location = location;
|
||||
suite._addSuite(child);
|
||||
|
||||
@ -135,13 +144,13 @@ export class TestTypeImpl {
|
||||
}
|
||||
|
||||
private _hook(name: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll', location: Location, fn: Function) {
|
||||
const suite = this._ensureCurrentSuite(location, `test.${name}()`);
|
||||
const suite = this._ensureCurrentSuite(location, `${this._projectSetup ? 'setup' : 'test'}.${name}()`);
|
||||
suite._hooks.push({ type: name, fn, location });
|
||||
}
|
||||
|
||||
private _configure(location: Location, options: { mode?: 'parallel' | 'serial', retries?: number, timeout?: number }) {
|
||||
throwIfRunningInsideJest();
|
||||
const suite = this._ensureCurrentSuite(location, `test.describe.configure()`);
|
||||
const suite = this._ensureCurrentSuite(location, `${this._projectSetup ? 'setup' : 'test'}.describe.configure()`);
|
||||
|
||||
if (options.timeout !== undefined)
|
||||
suite._timeout = options.timeout;
|
||||
@ -202,14 +211,14 @@ export class TestTypeImpl {
|
||||
}
|
||||
|
||||
private _use(location: Location, fixtures: Fixtures) {
|
||||
const suite = this._ensureCurrentSuite(location, `test.use()`);
|
||||
const suite = this._ensureCurrentSuite(location, `${this._projectSetup ? 'setup' : 'test'}.use()`);
|
||||
suite._use.push({ fixtures, location });
|
||||
}
|
||||
|
||||
private async _step<T>(location: Location, title: string, body: () => Promise<T>): Promise<T> {
|
||||
const testInfo = currentTestInfo();
|
||||
if (!testInfo)
|
||||
throw errorWithLocation(location, `test.step() can only be called from a test`);
|
||||
throw errorWithLocation(location, `${this._projectSetup ? 'setup' : 'test'}.step() can only be called from a test`);
|
||||
const step = testInfo._addStep({
|
||||
category: 'test.step',
|
||||
title,
|
||||
@ -254,4 +263,11 @@ 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([]);
|
||||
|
@ -169,7 +169,7 @@ export class WorkerRunner extends EventEmitter {
|
||||
let fatalUnknownTestIds;
|
||||
try {
|
||||
await this._loadIfNeeded();
|
||||
const fileSuite = await this._loader.loadTestFile(runPayload.file, 'worker');
|
||||
const fileSuite = await this._loader.loadTestFile(runPayload.file, 'worker', runPayload.projectSetup);
|
||||
const suite = this._loader.buildFileSuiteForProject(this._project, fileSuite, this._params.repeatEachIndex, test => {
|
||||
if (runPayload.watchMode) {
|
||||
const testResolvedPayload: WatchTestResolvedPayload = {
|
||||
|
@ -29,8 +29,8 @@ function createConfigWithProjects(names: string[], testInfo: TestInfo, projectTe
|
||||
await new Promise(f => setTimeout(f, 100));
|
||||
});`;
|
||||
files[`${name}/${name}.setup.ts`] = `
|
||||
const { test } = pwt;
|
||||
test('${name} setup', async () => {
|
||||
const { setup } = pwt;
|
||||
setup('${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 { test, expect } = pwt;
|
||||
test('a setup', async () => {
|
||||
const { setup, expect } = pwt;
|
||||
setup('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 { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
setup('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 { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
`,
|
||||
'p2.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup3', async () => { });
|
||||
test('setup4', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup3', async () => { });
|
||||
setup('setup4', async () => { });
|
||||
`,
|
||||
};
|
||||
|
||||
@ -347,20 +347,20 @@ test('list-files should enumerate setup files in same group', async ({ runComman
|
||||
]
|
||||
};`,
|
||||
'a1.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('test1', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('test1', async () => { });
|
||||
`,
|
||||
'a2.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('test1', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('test1', async () => { });
|
||||
`,
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
test('test2', async () => { });
|
||||
`,
|
||||
'b.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('test3', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('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 { test } = pwt;
|
||||
test('test1', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('test1', async () => { });
|
||||
`,
|
||||
'a2.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('test1', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('test1', async () => { });
|
||||
`,
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
test('test2', async () => { });
|
||||
`,
|
||||
'b.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('test3', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('test3', async () => { });
|
||||
`,
|
||||
'b.test.ts': `
|
||||
const { test } = pwt;
|
||||
@ -445,17 +445,17 @@ test('should allow .only in setup files', async ({ runGroups }, testInfo) => {
|
||||
test('test4', async () => { });
|
||||
`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test.only('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
test.only('setup3', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup.only('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
setup.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:12 › setup1');
|
||||
expect(output).toContain('[p1] › a.setup.ts:7:12 › setup3');
|
||||
expect(output).toContain('[p1] › a.setup.ts:5:13 › setup1');
|
||||
expect(output).toContain('[p1] › a.setup.ts:7:13 › setup3');
|
||||
expect(fileNames(timeline)).toEqual(['a.setup.ts']);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(passed).toBe(2);
|
||||
@ -480,12 +480,12 @@ test('should allow describe.only in setup files', async ({ runGroups }, testInfo
|
||||
test('test4', async () => { });
|
||||
`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test.describe.only('main', () => {
|
||||
test('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup.describe.only('main', () => {
|
||||
setup('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
});
|
||||
test('setup3', async () => { });
|
||||
setup('setup3', async () => { });
|
||||
`,
|
||||
};
|
||||
|
||||
@ -517,12 +517,12 @@ test('should filter describe line in setup files', async ({ runGroups }, testInf
|
||||
test('test4', async () => { });
|
||||
`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test.describe('main', () => {
|
||||
test('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup.describe('main', () => {
|
||||
setup('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
});
|
||||
test('setup3', async () => { });
|
||||
setup('setup3', async () => { });
|
||||
`,
|
||||
};
|
||||
|
||||
@ -554,16 +554,16 @@ test('should allow .only in both setup and test files', async ({ runGroups }, te
|
||||
test('test4', async () => { });
|
||||
`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test.only('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
test('setup3', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup.only('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
setup('setup3', async () => { });
|
||||
`,
|
||||
};
|
||||
|
||||
const { exitCode, output } = await runGroups(files);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(output).toContain('[p1] › a.setup.ts:5:12 › setup1');
|
||||
expect(output).toContain('[p1] › a.setup.ts:5:13 › 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 { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
`,
|
||||
'b.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup3', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup3', async () => { });
|
||||
`,
|
||||
};
|
||||
|
||||
@ -628,13 +628,13 @@ test('should allow filtering setup by file:line', async ({ runGroups }, testInfo
|
||||
test('test3', async () => { });
|
||||
`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
`,
|
||||
'b.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
`,
|
||||
'b.test.ts': `
|
||||
const { test } = pwt;
|
||||
@ -680,13 +680,13 @@ test('should support filters matching both setup and test', async ({ runGroups }
|
||||
test('test3', async () => { });
|
||||
`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
`,
|
||||
'b.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
`,
|
||||
'b.test.ts': `
|
||||
const { test } = pwt;
|
||||
@ -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 { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
`,
|
||||
'b.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
`,
|
||||
'b.test.ts': `
|
||||
const { test } = pwt;
|
||||
@ -765,13 +765,13 @@ test('should run all setup files if only tests match filter', async ({ runGroups
|
||||
test('test3', async () => { });
|
||||
`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
`,
|
||||
'b.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
`,
|
||||
};
|
||||
|
||||
@ -802,13 +802,13 @@ test('should run all setup files if only tests match grep filter', async ({ runG
|
||||
test('test3', async () => { });
|
||||
`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
`,
|
||||
'b.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
`,
|
||||
};
|
||||
|
||||
@ -840,14 +840,14 @@ test('should apply project.grep filter to both setup and tests', async ({ runGro
|
||||
test('foo', async () => { });
|
||||
`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
test('setup2', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
setup('setup2', async () => { });
|
||||
`,
|
||||
'b.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('setup1', async () => { });
|
||||
test('foo', async () => { });
|
||||
const { setup } = pwt;
|
||||
setup('setup1', async () => { });
|
||||
setup('foo', async () => { });
|
||||
`,
|
||||
};
|
||||
|
||||
@ -858,3 +858,74 @@ test('should apply project.grep filter to both setup and tests', async ({ runGro
|
||||
expect(output).toContain('[p1] › a.test.ts:6:7 › test1');
|
||||
expect(output).toContain('[p1] › a.test.ts:7:7 › test2');
|
||||
});
|
||||
|
||||
test('should prohibit setup in test files', async ({ runGroups }, testInfo) => {
|
||||
const files = {
|
||||
'a.test.ts': `
|
||||
const { setup, test } = pwt;
|
||||
setup('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.');
|
||||
});
|
||||
|
||||
test('should prohibit setup hooks in test files', async ({ runGroups }, testInfo) => {
|
||||
const files = {
|
||||
'a.test.ts': `
|
||||
const { setup } = pwt;
|
||||
setup.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');
|
||||
});
|
||||
|
||||
test('should prohibit test in setup files', async ({ runGroups }, testInfo) => {
|
||||
const files = {
|
||||
'playwright.config.ts': `
|
||||
module.exports = {
|
||||
projects: [
|
||||
{
|
||||
name: 'p1',
|
||||
setup: /.*.setup.ts/,
|
||||
},
|
||||
]
|
||||
};`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test('test1', async () => { });
|
||||
`,
|
||||
};
|
||||
|
||||
const { exitCode, output } = await runGroups(files);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(output).toContain('test() is called in a project setup file');
|
||||
});
|
||||
|
||||
test('should prohibit test hooks in setup files', async ({ runGroups }, testInfo) => {
|
||||
const files = {
|
||||
'playwright.config.ts': `
|
||||
module.exports = {
|
||||
projects: [
|
||||
{
|
||||
name: 'p1',
|
||||
setup: /.*.setup.ts/,
|
||||
},
|
||||
]
|
||||
};`,
|
||||
'a.setup.ts': `
|
||||
const { test } = pwt;
|
||||
test.beforeEach(async () => { });
|
||||
`,
|
||||
};
|
||||
|
||||
const { exitCode, output } = await runGroups(files);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(output).toContain('test.beforeEach() is called in a project setup file');
|
||||
});
|
||||
|
@ -56,9 +56,9 @@ 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 { setup, expect } = pwt;
|
||||
setup('should initialize storage', async ({ }) => {
|
||||
const storage = setup.info().storage();
|
||||
expect(await storage.get('number')).toBe(undefined);
|
||||
await storage.set('number', 2022)
|
||||
expect(await storage.get('number')).toBe(2022);
|
||||
@ -142,16 +142,16 @@ 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 { setup, expect } = pwt;
|
||||
setup('should initialize storage', async ({ }) => {
|
||||
const storage = setup.info().storage();
|
||||
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-' + test.info().project.name)
|
||||
expect(await storage.get('name')).toBe('str-' + test.info().project.name);
|
||||
await storage.set('name', 'str-' + setup.info().project.name)
|
||||
expect(await storage.get('name')).toBe('str-' + setup.info().project.name);
|
||||
});
|
||||
`,
|
||||
'a.test.ts': `
|
||||
@ -192,9 +192,9 @@ 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 { setup, expect } = pwt;
|
||||
setup('should save storageState', async ({ page, context }) => {
|
||||
const storage = setup.info().storage();
|
||||
expect(await storage.get('user')).toBe(undefined);
|
||||
await page.goto('${server.PREFIX}/setcookie.html');
|
||||
const state = await page.context().storageState();
|
||||
@ -245,12 +245,12 @@ test('should load storageStateName specified in the project config from storage'
|
||||
};
|
||||
`,
|
||||
'storage.setup.ts': `
|
||||
const { test, expect } = pwt;
|
||||
test.use({
|
||||
const { setup, expect } = pwt;
|
||||
setup.use({
|
||||
storageStateName: ({}, use) => use(undefined),
|
||||
})
|
||||
test('should save storageState', async ({ page, context }) => {
|
||||
const storage = test.info().storage();
|
||||
setup('should save storageState', async ({ page, context }) => {
|
||||
const storage = setup.info().storage();
|
||||
expect(await storage.get('stateInStorage')).toBe(undefined);
|
||||
await page.goto('${server.PREFIX}/setcookie.html');
|
||||
const state = await page.context().storageState();
|
||||
@ -290,12 +290,12 @@ test('should load storageStateName specified in the global config from storage',
|
||||
};
|
||||
`,
|
||||
'storage.setup.ts': `
|
||||
const { test, expect } = pwt;
|
||||
test.use({
|
||||
const { setup, expect } = pwt;
|
||||
setup.use({
|
||||
storageStateName: ({}, use) => use(undefined),
|
||||
})
|
||||
test('should save storageStateName', async ({ page, context }) => {
|
||||
const storage = test.info().storage();
|
||||
setup('should save storageStateName', async ({ page, context }) => {
|
||||
const storage = setup.info().storage();
|
||||
expect(await storage.get('stateInStorage')).toBe(undefined);
|
||||
await page.goto('${server.PREFIX}/setcookie.html');
|
||||
const state = await page.context().storageState();
|
||||
|
Loading…
Reference in New Issue
Block a user