Skip to content

Commit

Permalink
feat: TS support improvements (#35)
Browse files Browse the repository at this point in the history
* feat: TS support improvements

* docs: adjust readme to latest changes

* chore: adjust examples to latest changes

* chore: run tsc in build step

* chore: generate changeset

* chore: generate changelog using `@changesets/changelog-github`

* chore: rephrase changesets
  • Loading branch information
SebastianSedzik committed Jan 2, 2024
1 parent 7398cc2 commit 8ba55c6
Show file tree
Hide file tree
Showing 38 changed files with 283 additions and 140 deletions.
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": "@changesets/cli/changelog",
"changelog": ["@changesets/changelog-github", { "repo": "sebastianSedzik/playwright-decorators" }],
"commit": false,
"fixed": [],
"linked": [],
Expand Down
8 changes: 4 additions & 4 deletions .changeset/funny-pugs-kick.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
'playwright-decorators': patch
---

- Display `reason` from `@skip` decorator.
- Show tags from `@skip` tests.
- Provide more detailed info in error messages.
- Cosmetic changes in readme file
Fixes of `@skip` and `@annotate` decorators:

- Pass `reason` from `@skip` decorator to the reporter.
- Added support for annotations on skipped tests.
22 changes: 22 additions & 0 deletions .changeset/strong-kangaroos-fly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
'playwright-decorators': minor
---


Enhanced TypeScript support:

- constrained the `@suite` decorator to class contexts only.
- constrained the `@test` decorator to class method context only. Type check of test method arguments.
- exported the `TestArgs` type to provide validity within test methods.

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

@suite()
class ExampleSuite {
@test()
async exampleTest({ page }: TestArgs) { // <- TestArgs ensures correct types of arguments
// ...
}
}
```
1 change: 1 addition & 0 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
run: |
cd examples
npx playwright install chromium
npm run build
npm t
- name: Publish or release proposal
uses: changesets/action@v1
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ jobs:
run: |
cd examples
npx playwright install chromium
npm run build
npm t
64 changes: 32 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,25 @@ npm i playwright-decorators
## 🏗️ Usage
Declare tests using `@suite` and `@test` decorators
```ts
import { suite, test, slow, tag } from 'playwright-decorators';
import { suite, test, slow, tag, TestArgs, TestInfo } from 'playwright-decorators';

@suite() // <-- Decorate class with @suite
class MyTestSuite {
@test() // <-- Decorate test method with @test
async myTest({ page }) {
async myTest({ page }: TestArgs, testInfo: TestInfo) {
// ...
}

@tag(['team-x'])
@slow('Response from pasword reset service takes a long time')
@test()
async userShouldBeAbleToResetPassword({ page }) {
async userShouldBeAbleToResetPassword({ page }: TestArgs) {
// ...
}

@withUser({ features: ['payment'] }) // <- Use your own custom decorators
@test()
async userShouldBeAbleToCancelSubscription({ page }) {
async userShouldBeAbleToCancelSubscription({ page }: TestArgs) {
// ...
}
}
Expand Down Expand Up @@ -63,12 +63,12 @@ Mark class method as test.
Under the hood, decorator creates a `test` block and runs the method inside it.

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

@suite()
class MyTestSuite {
@test() // <-- Decorate test method with @test() or @test(options)
async myTest({ page }) {
async myTest({ page }: TestArgs) {
// ...
}
}
Expand All @@ -82,12 +82,12 @@ class MyTestSuite {
Mark method as `beforeAll` book.

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

@suite()
class MyTestSuite {
@beforeAll() // <-- Decorate method with @beforeAll()
async beforeAll({page}) {
async beforeAll({ page }: TestArgs) {
// ...
}
}
Expand All @@ -98,12 +98,12 @@ class MyTestSuite {
Mark method as `beforeEach` book.

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

@suite()
class MyTestSuite {
@beforeEach() // <-- Decorate method with @beforeEach()
async beforeEach({ page }) {
async beforeEach({ page }: TestArgs) {
// ...
}
}
Expand All @@ -114,12 +114,12 @@ class MyTestSuite {
Mark method as `afterAll` book.

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

@suite()
class MyTestSuite {
@afterAll() // <-- Decorate method with @afterAll()
async afterAll({page}) {
async afterAll({ page }: TestArgs) {
// ...
}
}
Expand All @@ -130,12 +130,12 @@ class MyTestSuite {
Mark method as `afterEach` book.

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

@suite()
class MyTestSuite {
@afterEach() // <-- Decorate method with @afterEach()
async afterEach({ page }) {
async afterEach({ page }: TestArgs) {
// ...
}
}
Expand All @@ -146,7 +146,7 @@ class MyTestSuite {
Skip single `@test` or `@suite`.

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

// Skip test suite
@skip() // <-- Decorate suite with @skip()
Expand All @@ -159,7 +159,7 @@ class SkippedTestSuite {
class MyTestSuite {
@skip() // <-- Decorate test with @skip()
@test()
async skippedTest({ page }) {
async skippedTest({ page }: TestArgs) {
// ...
}
}
Expand All @@ -175,7 +175,7 @@ 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';
import { suite, test, fail, TestArgs } from 'playwright-decorators';

// Mark suite as "fail", ensure that all tests from suite fail
@fail() // <-- Decorate suite with @fail()
Expand All @@ -188,7 +188,7 @@ class FailTestSuite {
class MyTestSuite {
@fail() // <-- Decorate test with @fail()
@test()
async failingTest({ page }) {
async failingTest({ page }: TestArgs) {
// ...
}
}
Expand All @@ -203,7 +203,7 @@ Marks a `@test` or `@suite` as "fixme", with the intention to fix (with optional
Decorated tests or suites will not be run.

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

// Mark test suite as "fixme"
@fixme() // <-- Decorate suite with @fixme()
Expand All @@ -216,7 +216,7 @@ class FixmeTestSuite {
class MyTestSuite {
@fixme() // <-- Decorate test with @fixme()
@test()
async fixmeTest({ page }) {
async fixmeTest({ page }: TestArgs) {
// ...
}
}
Expand All @@ -231,7 +231,7 @@ Mark single `@test` or `@suite` as "slow".
Slow test will be given triple the default timeout.

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

// Mark test suite as "slow"
@slow() // <-- Decorate suite with @slow()
Expand All @@ -244,7 +244,7 @@ class SlowTestSuite {
class MyTestSuite {
@slow() // <-- Decorate test with @slow()
@test()
async slowTest({ page }) {
async slowTest({ page }: TestArgs) {
// ...
}
}
Expand All @@ -259,7 +259,7 @@ Declares a focused `@test` or `@suite`.
If there are some focused tests or suites, all of them will be run but nothing else.

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

// Run only selected test suite(s)
@only() // <-- Decorate suite with @only()
Expand All @@ -272,7 +272,7 @@ class FocusedTestSuite {
class TestSuite {
@only() // <-- Decorate test with @only()
@test()
async focusedTest({ page }) {
async focusedTest({ page }: TestArgs) {
// ...
}
}
Expand All @@ -285,7 +285,7 @@ You can later run test(s) or suite(s) with specific tag, using `npx playwright t
For example: to run tests/suites with `x` tag, please run `npx playwright test --grep "@x"`

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

// Run only selected test suite(s)
@tag(['x-api-consumer']) // <-- Decorate suite with @tag()
Expand All @@ -298,7 +298,7 @@ class ApiConsumerTestSuite {
class TestSuite {
@tag(['x-api-consumer']) // <-- Decorate test with @tag()
@test()
async apiConsumerTest({ page }) {
async apiConsumerTest({ page }: TestArgs) {
// ...
}
}
Expand All @@ -318,13 +318,13 @@ Add custom annotation to a test.
Annotations are accessible via test.info().annotations. Many reporters show annotations, for example 'html'.

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

@suite()
class MyTestSuite {
@annotate({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/<some-issue>' }) // <-- Decorate test with @annotate()
@annotation({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/<some-issue>' }) // <-- Decorate test with @annotate()
@test()
async testWithCustomAnnotation({ page }) {
async testWithCustomAnnotation({ page }: TestArgs) {
// ...
}
}
Expand All @@ -348,7 +348,7 @@ Attempting to utilize a custom test decorator on a method that lacks the `@test`
import { suite, createTestDecorator } from 'playwright-decorators';
import playwright from '@playwright/test';

const customTestDecorator = createTestDecorator('customTestDecorator', ({test, context}) => {
const customTestDecorator = createTestDecorator('customTestDecorator', ({ test, context }) => {
// create code using hooks provided by test decorator...
test.beforeTest(() => { /* ... */ })
test.afterTest(() => { /* ... */ })
Expand All @@ -366,7 +366,7 @@ Then use it on `@test` decorator:
class MyTestSuite {
@customTestDecorator() // <-- Decorate test with custom decorator
@test()
async myTest({ page }) {
async myTest({ page }: TestArgs) {
// ...
}
}
Expand All @@ -379,7 +379,7 @@ Attempting to apply a custom suite decorator to a class that lacks the `@suite`
```ts
import { suite, createSuiteDecorator } from 'playwright-decorators';

const customSuiteDecorator = createSuiteDecorator('customSuiteDecorator', ({suite, context}) => {
const customSuiteDecorator = createSuiteDecorator('customSuiteDecorator', ({ suite, context }) => {
// ...
});
```
Expand Down
1 change: 1 addition & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"private": true,
"scripts": {
"start": "node app.js",
"build": "tsc",
"test": "playwright test"
},
"devDependencies": {
Expand Down
15 changes: 9 additions & 6 deletions examples/tests/basic.spec.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import {expect} from "@playwright/test";
import { expect } from "@playwright/test";
import {
beforeEach,
suite,
test,
tag,
fixme, slow, annotation
fixme,
slow,
annotation,
TestArgs
} from "playwright-decorators";

@tag(['x-api-consumer'])
@suite()
class SignInSuite {
@beforeEach()
async setPageRoute({ page }) {
async setPageRoute({ page }: TestArgs) {
// set sign-in page context for each test in the suite
await page.goto('http://localhost:3000/sign-in');
}

@test()
async userShouldNotBeAbleToSignInWithInvalidCredentials({ page }) {
async userShouldNotBeAbleToSignInWithInvalidCredentials({ page }: TestArgs) {
// when user fills invalid credentials & submits the form
await page.getByTestId('sign-in-email').fill("example@email.com");
await page.getByTestId('sign-in-password').fill("example password");
Expand All @@ -32,15 +35,15 @@ class SignInSuite {
description: 'jira.com/issue-123'
})
@test()
async userShouldBeAbleToResetPassword({ page }) {
async userShouldBeAbleToResetPassword({ page }: TestArgs) {
await page.goto('http://localhost:3000/sign-in/reset');
// ...
}

@tag(['team-y'])
@slow("/sign-in/sso page is under the development, and needs more then 500ms to load")
@test()
async userShouldBeAbleToLoginViaSSO({ page }) {
async userShouldBeAbleToLoginViaSSO({ page }: TestArgs) {
await page.goto('http://localhost:3000/sign-in/sso');
await expect(page.getByTestId('page-title')).toHaveText('SSO Login');
// ...
Expand Down
Loading

0 comments on commit 8ba55c6

Please sign in to comment.