Skip to content

Commit

Permalink
feat: add @fixme decorator (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianSedzik committed Jul 22, 2023
1 parent be51ffb commit 866e7a3
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 4 deletions.
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,21 @@ class MyTestSuite {
- `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".
### Mark test or suite as "should fail": `@fail(reason?: string)`
Mark single `@test` or `@suite` 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';

// Mark suite as "fail", ensure that all tests from suite fail
@fail() // <-- Decorate suite with @fail()
@suite()
class FailTestSuite {
}

// Or mark selected test as "fail"
@suite()
class MyTestSuite {
@fail() // <-- Decorate test with @fail()
Expand All @@ -174,6 +181,34 @@ class MyTestSuite {
- `reason` (optional) - reason of marking as "should fail". Will be displayed in the test report.


### Mark test or suite as "fixme", with the intention to fix it: `@fixme(reason?: string)`
Marks a `@test` or `@suite` as "fixme", with the intention to fix (with optional reason).
Decorated tests or suites will not be run.

```ts
import { suite, test, fixme } from 'playwright-decorators';

// Mark test suite as "fixme"
@fixme() // <-- Decorate suite with @fixme()
@suite()
class FixmeTestSuite {
}

// Or mark selected test as "fixme"
@suite()
class MyTestSuite {
@fixme() // <-- Decorate test with @fixme()
@test()
async fixmeTest({ page }) {
// ...
}
}
```

#### Options
- `reason` (optional) - reason of marking as "fixme". 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.
Expand Down
8 changes: 7 additions & 1 deletion lib/fail.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import {SuiteDecoratedMethod} from "./suite.decorator";
import {TestDecoratedMethod} from "./test.decorator";

/**
* Marks a @test as "should fail".
* Marks a @test or @suite 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 SuiteDecoratedMethod)?.suiteDecorator) {
originalMethod.suiteDecorator.fail = reason || true;
return;
}

if ((originalMethod as TestDecoratedMethod)?.testDecorator) {
originalMethod.testDecorator.fail = reason || true;
return;
Expand Down
18 changes: 18 additions & 0 deletions lib/fixme.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {SuiteDecoratedMethod} from "./suite.decorator";
import {TestDecoratedMethod} from "./test.decorator";

/**
* Marks a @test or @suite as "fixme", with the intention to fix (with optional reason).
* Decorated tests or suites will not be run.
*/
export const fixme = (reason?: string) => function(originalMethod: any, context?: any) {
if ((originalMethod as SuiteDecoratedMethod)?.suiteDecorator) {
originalMethod.suiteDecorator.fixme = reason || true;
return;
}

if ((originalMethod as TestDecoratedMethod)?.testDecorator) {
originalMethod.testDecorator.fixme = reason || true;
return;
}
}
1 change: 1 addition & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export { afterEach } from './afterEach.decorator';
export { skip } from './skip.decorator';
export { slow } from './slow.decorator';
export { fail } from './fail.decorator';
export { fixme } from './fixme.decorator';
export { only } from './only.decorator';
// helpers
export { tag } from './tag.decorator';
39 changes: 39 additions & 0 deletions lib/suite.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ interface SuiteDecoratorOptions {
* Slow test will be given triple the default timeout.
*/
slow?: string | boolean;
/**
* Marks a suite as "should fail".
* Playwright Test runs all test from suite and ensures that they are actually failing.
* This is useful for documentation purposes to acknowledge that some functionality is broken until it is fixe
*/
fail?: string | boolean
/**
* Marks a suite as "fixme", with the intention to fix (with optional reason).
* Decorated suite will not be run.
*/
fixme?: string | boolean;
/**
* Declares a focused suite.
* If there are some focused @test(s) or @suite(s), all of them will be run but nothing else.
Expand All @@ -27,6 +38,8 @@ class SuiteDecorator implements SuiteDecoratorOptions {
name: string;
skip: string | boolean = false;
slow: string | boolean = false;
fail: string | boolean = false;
fixme: string | boolean = false;
only = false;

constructor(private suiteClass: Constructor, options: SuiteDecoratorOptions) {
Expand Down Expand Up @@ -58,10 +71,36 @@ class SuiteDecorator implements SuiteDecoratorOptions {

return playwright.slow();
}

private handleFail() {
if (this.fail === false) {
return;
}

if (typeof this.fail === 'string') {
return playwright.fail(true, this.fail);
}

return playwright.fail();
}

private handleFixme() {
if (this.fixme === false) {
return;
}

if (typeof this.fixme === 'string') {
return playwright.fixme(true, this.fixme);
}

return playwright.fixme();
}

private runSuite(userSuiteCode: () => Promise<any>) {
this.handleSkip();
this.handleSlow();
this.handleFail();
this.handleFixme();

return userSuiteCode();
}
Expand Down
19 changes: 19 additions & 0 deletions lib/test.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ interface TestDecoratorOptions {
* This is useful for documentation purposes to acknowledge that some functionality is broken until it is fixe
*/
fail?: string | boolean
/**
* Marks a test as "fixme", with the intention to fix (with optional reason).
* Decorated test will not be run.
*/
fixme?: 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.
Expand All @@ -33,6 +38,7 @@ class TestDecorator implements TestDecoratorOptions {
skip: string | boolean = false;
slow: string | boolean = false;
fail: string | boolean = false;
fixme: string | boolean = false;
only = false;

constructor(private testMethod: any, options: TestDecoratorOptions) {
Expand Down Expand Up @@ -77,6 +83,18 @@ class TestDecorator implements TestDecoratorOptions {
return playwright.fail();
}

private handleFixme() {
if (this.fixme === false) {
return;
}

if (typeof this.fixme === 'string') {
return playwright.fixme(true, this.fixme);
}

return playwright.fixme();
}

/**
* Run playwright.test function using all collected data.
*/
Expand All @@ -85,6 +103,7 @@ class TestDecorator implements TestDecoratorOptions {
this.handleSkip();
this.handleSlow();
this.handleFail();
this.handleFixme();

// set correct executionContext (test class)
return testFunction.call(executionContext, ...args);
Expand Down
26 changes: 25 additions & 1 deletion tests/fail.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@ import playwright, {expect} from "@playwright/test";
import {suite, test, fail} from "../lib";

playwright.describe('@fail decorator', () => {
playwright.describe('with @suite', () => {
const called: string[] = [];

@fail()
@suite()
class SkipSuite {
@test()
async test() {
called.push('test');
expect(true).toBe(false);
}

@test()
async test2() {
called.push('test2');
expect(true).toBe(false);
}
}

playwright('@fail decorator should not throw error when tests intentionally fails', () => {
expect(called).toEqual(['test', 'test2']);
});
});

playwright.describe('with @test', () => {
const called: string[] = [];

Expand All @@ -15,7 +39,7 @@ playwright.describe('@fail decorator', () => {
}
}

playwright('@fail decorator should not throw error when test fails', () => {
playwright('@fail decorator should not throw error when test intentionally fails', () => {
// is called and not throw error
expect(called).toEqual(['failingTest']);
});
Expand Down
53 changes: 53 additions & 0 deletions tests/fixme.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import playwright, {expect} from "@playwright/test";
import {suite, test, slow, beforeAll, skip, fixme} from "../lib";

playwright.describe('@fixme decorator', () => {
playwright.describe('with @suite', () => {
const called: string[] = [];

@fixme()
@suite()
class SkipSuite {
@test()
async test() {
called.push('test');
}

@test()
async test2() {
called.push('test2');
}
}

playwright('@fixme decorator should not call any @test methods from suite', () => {
expect(called).toEqual([]);
});
});

playwright.describe('with @test', () => {
const called: string[] = [];

@suite()
class TestSuite {
@test()
async test() {
called.push('test');
}

@fixme()
@test()
async fixmeTest() {
called.push('fixmeTest');
}

@test()
async test2() {
called.push('test2');
}
}

playwright('@fixme decorator should not execute @test method', () => {
expect(called).not.toContain('fixmeTest');
})
});
});

0 comments on commit 866e7a3

Please sign in to comment.