From 209bde5000dd384a94af7ffbd1a9351dbb1f2739 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Fri, 18 Mar 2022 16:07:11 -0700 Subject: [PATCH] feat(test runner): descrbe.skip (#12865) `describe.skip` declares a test group that is skipped. --- docs/src/test-api/class-test.md | 32 ++++++++++++++++++++++++ packages/playwright-test/src/test.ts | 2 ++ packages/playwright-test/src/testType.ts | 9 ++++++- packages/playwright-test/types/test.d.ts | 18 +++++++++++++ tests/playwright-test/basic.spec.ts | 26 +++++++++++++++++++ tests/playwright-test/types-2.spec.ts | 10 ++++++++ utils/generate_types/overrides-test.d.ts | 1 + 7 files changed, 97 insertions(+), 1 deletion(-) diff --git a/docs/src/test-api/class-test.md b/docs/src/test-api/class-test.md index bf4d608ae8..63ced99407 100644 --- a/docs/src/test-api/class-test.md +++ b/docs/src/test-api/class-test.md @@ -459,6 +459,38 @@ A callback that is run immediately when calling [`method: Test.describe.serial.o +## method: Test.describe.skip + +Declares a skipped test group, similarly to [`method: Test.describe`]. Tests in the skipped group are never run. + +```js js-flavor=js +test.describe.skip('skipped group', () => { + test('example', async ({ page }) => { + // This test will not run + }); +}); +``` + +```js js-flavor=ts +test.describe.skip('skipped group', () => { + test('example', async ({ page }) => { + // This test will not run + }); +}); +``` + +### param: Test.describe.skip.title +- `title` <[string]> + +Group title. + +### param: Test.describe.skip.callback +- `callback` <[function]> + +A callback that is run immediately when calling [`method: Test.describe.skip`]. Any tests added in this callback will belong to the group, and will not be run. + + + ## property: Test.expect - type: <[Object]> diff --git a/packages/playwright-test/src/test.ts b/packages/playwright-test/src/test.ts index fcba982911..33df726f11 100644 --- a/packages/playwright-test/src/test.ts +++ b/packages/playwright-test/src/test.ts @@ -44,6 +44,7 @@ export class Suite extends Base implements reporterTypes.Suite { parent?: Suite; _use: FixturesWithLocation[] = []; _isDescribe = false; + _skipped = false; _entries: (Suite | TestCase)[] = []; _hooks: { type: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll', fn: Function, location: Location }[] = []; _timeout: number | undefined; @@ -108,6 +109,7 @@ export class Suite extends Base implements reporterTypes.Suite { suite._isDescribe = this._isDescribe; suite._parallelMode = this._parallelMode; suite._projectConfig = this._projectConfig; + suite._skipped = this._skipped; return suite; } diff --git a/packages/playwright-test/src/testType.ts b/packages/playwright-test/src/testType.ts index 5be9a5e8b6..e16bbaa3d9 100644 --- a/packages/playwright-test/src/testType.ts +++ b/packages/playwright-test/src/testType.ts @@ -41,6 +41,7 @@ export class TestTypeImpl { test.describe.parallel.only = wrapFunctionWithLocation(this._describe.bind(this, 'parallel.only')); test.describe.serial = wrapFunctionWithLocation(this._describe.bind(this, 'serial')); test.describe.serial.only = wrapFunctionWithLocation(this._describe.bind(this, 'serial.only')); + test.describe.skip = wrapFunctionWithLocation(this._describe.bind(this, 'skip')); test.beforeEach = wrapFunctionWithLocation(this._hook.bind(this, 'beforeEach')); test.afterEach = wrapFunctionWithLocation(this._hook.bind(this, 'afterEach')); test.beforeAll = wrapFunctionWithLocation(this._hook.bind(this, 'beforeAll')); @@ -89,9 +90,13 @@ export class TestTypeImpl { test._only = true; if (type === 'skip' || type === 'fixme') test.expectedStatus = 'skipped'; + for (let parent: Suite | undefined = suite; parent; parent = parent.parent) { + if (parent._skipped) + test.expectedStatus = 'skipped'; + } } - 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' | 'skip', location: Location, title: string, fn: Function) { throwIfRunningInsideJest(); const suite = this._ensureCurrentSuite(location, 'test.describe()'); if (typeof title === 'function') { @@ -115,6 +120,8 @@ export class TestTypeImpl { child._parallelMode = 'serial'; if (type === 'parallel' || type === 'parallel.only') child._parallelMode = 'parallel'; + if (type === 'skip') + child._skipped = true; for (let parent: Suite | undefined = suite; parent; parent = parent.parent) { if (parent._parallelMode === 'serial' && child._parallelMode === 'parallel') diff --git a/packages/playwright-test/types/test.d.ts b/packages/playwright-test/types/test.d.ts index 1bb94f3f3f..00e5d40b1c 100644 --- a/packages/playwright-test/types/test.d.ts +++ b/packages/playwright-test/types/test.d.ts @@ -1795,6 +1795,24 @@ export interface TestType { + * test('example', async ({ page }) => { + * // This test will not run + * }); + * }); + * ``` + * + * @param title Group title. + * @param callback A callback that is run immediately when calling [test.describe.skip(title, callback)](https://playwright.dev/docs/api/class-test#test-describe-skip). Any tests added in + * this callback will belong to the group, and will not be run. + */ + skip: SuiteFunction; + /** * Declares a group of tests that should always be run serially. If one of the tests fails, all subsequent tests are * skipped. All tests in a group are retried together. * diff --git a/tests/playwright-test/basic.spec.ts b/tests/playwright-test/basic.spec.ts index 9eb9d96dde..cdefd43cbd 100644 --- a/tests/playwright-test/basic.spec.ts +++ b/tests/playwright-test/basic.spec.ts @@ -442,3 +442,29 @@ test('should allow unhandled expects in test.fail', async ({ runInlineTest }) => expect(result.passed).toBe(1); expect(result.output).not.toContain(`Error: expect`); }); + +test('should support describe.skip', async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'nested-skip.spec.js': ` + const { test } = pwt; + test.describe.skip('skipped', () => { + test.describe('nested', () => { + test('test1', () => {}); + }); + test('test2', () => {}); + }); + test.describe('not skipped', () => { + test.describe.skip('skipped', () => { + test('test4', () => {}); + }); + test('test4', () => { + console.log('heytest4'); + }); + }); + ` + }); + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(1); + expect(result.skipped).toBe(3); + expect(result.output).toContain('heytest4'); +}); diff --git a/tests/playwright-test/types-2.spec.ts b/tests/playwright-test/types-2.spec.ts index 589529a3a6..e1ed63a3fa 100644 --- a/tests/playwright-test/types-2.spec.ts +++ b/tests/playwright-test/types-2.spec.ts @@ -22,11 +22,21 @@ test('basics should work', async ({ runTSC }) => { const { test } = pwt; test.describe('suite', () => { test.beforeEach(async () => {}); + test.afterEach(async () => {}); + test.beforeAll(async () => {}); + test.afterAll(async () => {}); test('my test', async({}, testInfo) => { expect(testInfo.title).toBe('my test'); testInfo.annotations[0].type; }); + test.skip('my test', async () => {}); + test.fixme('my test', async () => {}); }); + test.describe.parallel('suite', () => {}); + test.describe.parallel.only('suite', () => {}); + test.describe.serial('suite', () => {}); + test.describe.serial.only('suite', () => {}); + test.describe.skip('suite', () => {}); // @ts-expect-error test.foo(); ` diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index 2a117b1c71..fefc8003d0 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -290,6 +290,7 @@ export interface TestType; describe: SuiteFunction & { only: SuiteFunction; + skip: SuiteFunction; serial: SuiteFunction & { only: SuiteFunction; };