diff --git a/docs/src/test-api/class-test.md b/docs/src/test-api/class-test.md index 4fde7bb576..764447cee4 100644 --- a/docs/src/test-api/class-test.md +++ b/docs/src/test-api/class-test.md @@ -823,6 +823,34 @@ An object containing fixtures and/or options. Learn more about [fixtures format] +## method: Test.fail#4 +* since: v1.42 + +Declares a test that "should fail". Playwright Test runs this test and ensures that it is actually failing. This is useful for documentation purposes to acknowledge that some functionality is broken until it is fixed. + +**Usage** + +```js +import { test, expect } from '@playwright/test'; + +test.fail('not yet ready', async ({ page }) => { + // ... +}); +``` + +### param: Test.fail#4.title +* since: v1.42 +- `title` <[string]> + +Test title. + +### param: Test.fail#4.testFunction +* since: v1.42 +- `testFunction` <[function]\([Fixtures], [TestInfo]\)> + +Test function that takes one or two arguments: an object with fixtures and optional [TestInfo]. + + ## method: Test.fail#1 * since: v1.10 diff --git a/packages/playwright/src/common/testType.ts b/packages/playwright/src/common/testType.ts index 0b3dc6e1c9..01d936f4d9 100644 --- a/packages/playwright/src/common/testType.ts +++ b/packages/playwright/src/common/testType.ts @@ -81,7 +81,7 @@ export class TestTypeImpl { return suite; } - private _createTest(type: 'default' | 'only' | 'skip' | 'fixme', location: Location, title: string, fn: Function) { + private _createTest(type: 'default' | 'only' | 'skip' | 'fixme' | 'fail', location: Location, title: string, fn: Function) { throwIfRunningInsideJest(); const suite = this._currentSuite(location, 'test()'); if (!suite) @@ -92,7 +92,7 @@ export class TestTypeImpl { if (type === 'only') test._only = true; - if (type === 'skip' || type === 'fixme') + if (type === 'skip' || type === 'fixme' || type === 'fail') test._staticAnnotations.push({ type }); } @@ -173,7 +173,7 @@ export class TestTypeImpl { private _modifier(type: 'skip' | 'fail' | 'fixme' | 'slow', location: Location, ...modifierArgs: [arg?: any | Function, description?: string]) { const suite = currentlyLoadingFileSuite(); if (suite) { - if (typeof modifierArgs[0] === 'string' && typeof modifierArgs[1] === 'function' && (type === 'skip' || type === 'fixme')) { + if (typeof modifierArgs[0] === 'string' && typeof modifierArgs[1] === 'function' && (type === 'skip' || type === 'fixme' || type === 'fail')) { // Support for test.{skip,fixme}('title', () => {}) this._createTest(type, location, modifierArgs[0], modifierArgs[1]); return; diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index 1bdb8c341f..a557514fcb 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -2946,6 +2946,24 @@ export interface TestType boolean, description?: string): void; + /** + * Declares a test that "should fail". Playwright Test runs this test and ensures that it is actually failing. This is + * useful for documentation purposes to acknowledge that some functionality is broken until it is fixed. + * + * **Usage** + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test.fail('not yet ready', async ({ page }) => { + * // ... + * }); + * ``` + * + * @param title Test title. + * @param testFunction Test function that takes one or two arguments: an object with fixtures and optional {@link TestInfo}. + */ + fail(title: string, testFunction: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | void): void; /** * Unconditionally marks a test as "slow". Slow test will be given triple the default timeout. * diff --git a/tests/playwright-test/test-modifiers.spec.ts b/tests/playwright-test/test-modifiers.spec.ts index ce9a1aff9a..68dcd45d58 100644 --- a/tests/playwright-test/test-modifiers.spec.ts +++ b/tests/playwright-test/test-modifiers.spec.ts @@ -143,6 +143,8 @@ test.describe('test modifier annotations', () => { test('skip inner', () => { test.skip(); }); test.fixme('fixme wrap', () => {}); test('fixme inner', () => { test.fixme(); }); + test.fail('fail wrap', () => { expect(1).toBe(2); }); + test('fail inner', () => { test.fail(); expect(1).toBe(2); }); }); test('example', () => {}); @@ -151,13 +153,15 @@ test.describe('test modifier annotations', () => { const expectTest = expectTestHelper(result); expect(result.exitCode).toBe(0); - expect(result.passed).toBe(2); + expect(result.passed).toBe(4); expect(result.skipped).toBe(4); expectTest('no marker', 'passed', 'expected', []); expectTest('skip wrap', 'skipped', 'skipped', ['skip']); expectTest('skip inner', 'skipped', 'skipped', ['skip']); expectTest('fixme wrap', 'skipped', 'skipped', ['fixme']); expectTest('fixme inner', 'skipped', 'skipped', ['fixme']); + expectTest('fail wrap', 'failed', 'expected', ['fail']); + expectTest('fail inner', 'failed', 'expected', ['fail']); expectTest('example', 'passed', 'expected', []); }); diff --git a/tests/playwright-test/types-2.spec.ts b/tests/playwright-test/types-2.spec.ts index f463f21d60..84b55f1974 100644 --- a/tests/playwright-test/types-2.spec.ts +++ b/tests/playwright-test/types-2.spec.ts @@ -32,6 +32,7 @@ test('basics should work', async ({ runTSC }) => { }); test.skip('my test', async () => {}); test.fixme('my test', async () => {}); + test.fail('my test', async () => {}); }); test.describe(() => { test('my test', () => {}); diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index 5f29548676..464cd7f8b2 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -145,6 +145,7 @@ export interface TestType boolean, description?: string): void; + fail(title: string, testFunction: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise | void): void; slow(): void; slow(condition: boolean, description?: string): void; slow(callback: (args: TestArgs & WorkerArgs) => boolean, description?: string): void;