diff --git a/README.md b/README.md index 0334c1c..54f1a55 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ class MyTestSuite { #### Options - `name` (optional) - name of the test suite. By default, name of the class. + ### Creating a test: `@test(options?)` Mark class method as test. Under the hood, decorator creates a `test` block and runs the method inside it. @@ -59,6 +60,7 @@ class MyTestSuite { #### Options - `name` (optional) - name of the test. By default, name of the method. + ### Run method before all test in the suite: `@beforeAll()` Mark method as `beforeAll` book. @@ -74,6 +76,7 @@ class MyTestSuite { } ``` + ### Run method before each test in the suite: `@beforeEach()` Mark method as `beforeEach` book. @@ -89,6 +92,7 @@ class MyTestSuite { } ``` + ### Run method after all test in the suite: `@afterAll()` Mark method as `afterAll` book. @@ -104,6 +108,7 @@ class MyTestSuite { } ``` + ### Run method after each test in the suite: `@afterEach()` Mark method as `afterEach` book. @@ -119,6 +124,7 @@ class MyTestSuite { } ``` + ### Skip test or suite: `@skip(reason?: string)` Skip single `@test` or `@suite`. @@ -145,6 +151,29 @@ class MyTestSuite { #### Options - `reason` (optional) - reason of skipping. Will be displayed in the test report. + +### Mark test as "should fail": `@fail(reason?: string)` +Mark single `@test` as "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. + +```ts +import { suite, test, fail } from 'playwright-decorators'; + +@suite() +class MyTestSuite { + @fail() // <-- Decorate test with @fail() + @test() + async failingTest({ page }) { + // ... + } +} +``` + +#### Options +- `reason` (optional) - reason of marking as "should fail". Will be displayed in the test report. + + ### Mark test or suite as "slow": `@slow(reason?: string)` Mark single `@test` or `@suite` as "slow". Slow test will be given triple the default timeout. @@ -172,6 +201,7 @@ class MyTestSuite { #### Options - `reason` (optional) - reason of marking as "slow". Will be displayed in the test report. + ### Run only selected test(s) or suite(s): `@only()` Declares a focused `@test` or `@suite`. If there are some focused tests or suites, all of them will be run but nothing else. @@ -196,6 +226,7 @@ class TestSuite { } ``` + ### Run test(s) or suite(s) with certain tag(s): `@tag(tags: string[])` Adds tags to `@test` or `@suite`. You can later run test(s) or suite(s) with specific tag, using `npx playwright test --grep "@nameOfTag"` command. diff --git a/lib/fail.decorator.ts b/lib/fail.decorator.ts new file mode 100644 index 0000000..28aa38e --- /dev/null +++ b/lib/fail.decorator.ts @@ -0,0 +1,13 @@ +import {TestDecoratedMethod} from "./test.decorator"; + +/** + * Marks a @test as "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. + */ +export const fail = (reason?: string) => function(originalMethod: any, context?: any) { + if ((originalMethod as TestDecoratedMethod)?.testDecorator) { + originalMethod.testDecorator.fail = reason || true; + return; + } +} diff --git a/lib/index.ts b/lib/index.ts index 5196778..874de43 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -9,6 +9,7 @@ export { afterEach } from './afterEach.decorator'; // annotations export { skip } from './skip.decorator'; export { slow } from './slow.decorator'; +export { fail } from './fail.decorator'; export { only } from './only.decorator'; // helpers export { tag } from './tag.decorator'; diff --git a/lib/test.decorator.ts b/lib/test.decorator.ts index 7175892..5b6d464 100644 --- a/lib/test.decorator.ts +++ b/lib/test.decorator.ts @@ -15,6 +15,12 @@ interface TestDecoratorOptions { * Slow test will be given triple the default timeout. */ slow?: string | boolean; + /** + * Marks a test as "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 fixe + */ + fail?: string | boolean /** * Declares a focused test. * If there are some focused @test(s) or @suite(s), all of them will be run but nothing else. @@ -26,6 +32,7 @@ class TestDecorator implements TestDecoratorOptions { name: string; skip: string | boolean = false; slow: string | boolean = false; + fail: string | boolean = false; only = false; constructor(private testMethod: any, options: TestDecoratorOptions) { @@ -58,6 +65,18 @@ class TestDecorator implements TestDecoratorOptions { return playwright.slow(); } + private handleFail() { + if (this.fail === false) { + return; + } + + if (typeof this.fail === 'string') { + return playwright.fail(true, this.fail); + } + + return playwright.fail(); + } + /** * Run playwright.test function using all collected data. */ @@ -65,6 +84,7 @@ class TestDecorator implements TestDecoratorOptions { const decoratedTest: TestDecoratorFunction = (testFunction) => (...args) => { this.handleSkip(); this.handleSlow(); + this.handleFail(); // set correct executionContext (test class) return testFunction.call(executionContext, ...args); diff --git a/tests/fail.spec.ts b/tests/fail.spec.ts new file mode 100644 index 0000000..9b3396c --- /dev/null +++ b/tests/fail.spec.ts @@ -0,0 +1,23 @@ +import playwright, {expect} from "@playwright/test"; +import {suite, test, fail} from "../lib"; + +playwright.describe('@fail decorator', () => { + playwright.describe('with @test', () => { + const called: string[] = []; + + @suite() + class FocusedSuite { + @fail() + @test() + failingTest() { + called.push('failingTest'); + expect(true).toBe(false); + } + } + + playwright('@fail decorator should not throw error when test fails', () => { + // is called and not throw error + expect(called).toEqual(['failingTest']); + }); + }); +});