fix(test runner): improve error message for unexpected calls (#12240)

This commit is contained in:
Dmitry Gozman 2022-02-18 18:25:18 -08:00 committed by GitHub
parent ee0dd6ec71
commit d3c4323021
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 23 additions and 21 deletions

View file

@ -63,12 +63,24 @@ export class TestTypeImpl {
this.test = test; this.test = test;
} }
private _ensureCurrentSuite(location: Location, title: string): Suite {
const suite = currentlyLoadingFileSuite();
if (!suite) {
throw errorWithLocation(location, [
`Playwright Test did not expect ${title} to be called here.`,
`Most common reasons include:`,
`- You are calling ${title} in a configuration file.`,
`- You are calling ${title} in a file that is imported by the configuration file.`,
`- You have two different versions of @playwright/test. This usually happens`,
` when one of the dependenices in your package.json depends on @playwright/test.`,
].join('\n'));
}
return suite;
}
private _createTest(type: 'default' | 'only' | 'skip' | 'fixme', location: Location, title: string, fn: Function) { private _createTest(type: 'default' | 'only' | 'skip' | 'fixme', location: Location, title: string, fn: Function) {
throwIfRunningInsideJest(); throwIfRunningInsideJest();
const suite = currentlyLoadingFileSuite(); const suite = this._ensureCurrentSuite(location, 'test()');
if (!suite)
throw errorWithLocation(location, `test() can only be called in a test file`);
const test = new TestCase('test', title, fn, nextOrdinalInFile(suite._requireFile), this, location); const test = new TestCase('test', title, fn, nextOrdinalInFile(suite._requireFile), this, location);
test._requireFile = suite._requireFile; test._requireFile = suite._requireFile;
suite._addTest(test); suite._addTest(test);
@ -81,10 +93,7 @@ export class TestTypeImpl {
private _describe(type: 'default' | 'only' | 'serial' | 'serial.only' | 'parallel' | 'parallel.only', location: Location, title: string, fn: Function) { private _describe(type: 'default' | 'only' | 'serial' | 'serial.only' | 'parallel' | 'parallel.only', location: Location, title: string, fn: Function) {
throwIfRunningInsideJest(); throwIfRunningInsideJest();
const suite = currentlyLoadingFileSuite(); const suite = this._ensureCurrentSuite(location, 'test.describe()');
if (!suite)
throw errorWithLocation(location, `describe() can only be called in a test file`);
if (typeof title === 'function') { if (typeof title === 'function') {
throw errorWithLocation(location, [ throw errorWithLocation(location, [
'It looks like you are calling describe() without the title. Pass the title as a first argument:', 'It looks like you are calling describe() without the title. Pass the title as a first argument:',
@ -120,9 +129,7 @@ export class TestTypeImpl {
} }
private _hook(name: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll', location: Location, fn: Function) { private _hook(name: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll', location: Location, fn: Function) {
const suite = currentlyLoadingFileSuite(); const suite = this._ensureCurrentSuite(location, `test.${name}()`);
if (!suite)
throw errorWithLocation(location, `${name} hook can only be called in a test file`);
if (name === 'beforeAll' || name === 'afterAll') { if (name === 'beforeAll' || name === 'afterAll') {
const sameTypeCount = suite.hooks.filter(hook => hook._type === name).length; const sameTypeCount = suite.hooks.filter(hook => hook._type === name).length;
const suffix = sameTypeCount ? String(sameTypeCount) : ''; const suffix = sameTypeCount ? String(sameTypeCount) : '';
@ -136,10 +143,7 @@ export class TestTypeImpl {
private _configure(location: Location, options: { mode?: 'parallel' | 'serial' }) { private _configure(location: Location, options: { mode?: 'parallel' | 'serial' }) {
throwIfRunningInsideJest(); throwIfRunningInsideJest();
const suite = currentlyLoadingFileSuite(); const suite = this._ensureCurrentSuite(location, `test.describe.configure()`);
if (!suite)
throw errorWithLocation(location, `describe.configure() can only be called in a test file`);
if (!options.mode) if (!options.mode)
return; return;
if (suite._parallelMode !== 'default') if (suite._parallelMode !== 'default')
@ -196,9 +200,7 @@ export class TestTypeImpl {
} }
private _use(location: Location, fixtures: Fixtures) { private _use(location: Location, fixtures: Fixtures) {
const suite = currentlyLoadingFileSuite(); const suite = this._ensureCurrentSuite(location, `test.use()`);
if (!suite)
throw errorWithLocation(location, `test.use() can only be called in a test file and can only be nested in test.describe()`);
suite._use.push({ fixtures, location }); suite._use.push({ fixtures, location });
} }

View file

@ -218,7 +218,7 @@ test('should throw when test() is called in config file', async ({ runInlineTest
}); });
`, `,
}); });
expect(result.output).toContain('test() can only be called in a test file'); expect(result.output).toContain('Playwright Test did not expect test() to be called here');
}); });
test('should filter by project, case-insensitive', async ({ runInlineTest }) => { test('should filter by project, case-insensitive', async ({ runInlineTest }) => {

View file

@ -197,7 +197,7 @@ test('beforeAll from a helper file should throw', async ({ runInlineTest }) => {
`, `,
}); });
expect(result.exitCode).toBe(1); expect(result.exitCode).toBe(1);
expect(result.output).toContain('beforeAll hook can only be called in a test file'); expect(result.output).toContain('Playwright Test did not expect test.beforeAll() to be called here');
}); });
test('beforeAll hooks are skipped when no tests in the suite are run', async ({ runInlineTest }) => { test('beforeAll hooks are skipped when no tests in the suite are run', async ({ runInlineTest }) => {

View file

@ -176,6 +176,6 @@ test('test.use() should throw if called from beforeAll ', async ({ runInlineTest
`, `,
}); });
expect(result.exitCode).toBe(1); expect(result.exitCode).toBe(1);
expect(result.output).toContain('test.use() can only be called in a test file and can only be nested in test.describe()'); expect(result.output).toContain('Playwright Test did not expect test.use() to be called here');
}); });