From c6a573623db4b1923f5ffb19dacb0348172f718b Mon Sep 17 00:00:00 2001 From: Jamie Rolfs Date: Tue, 20 Sep 2022 00:17:54 -0700 Subject: [PATCH 1/6] docs(readme): clarify the `findBy*` query methods a bit Closes #510 Closes #513 --- README.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e76a97f..bb1e568 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ All of your favorite user-centric querying functions from **@testing-library/react** and **@testing-library/dom** available from within Playwright! -- Playwright Test [fixture](https://playwright.dev/docs/test-fixtures) for **@playwright/test** via **@playwright-testing-library/test** +- Test [fixture](https://playwright.dev/docs/test-fixtures) for **@playwright/test** via **@playwright-testing-library/test** - ✨ **New** — `Locator` queries fixture (`locatorFixtures`) [↓](#playwright-test-locator-fixture) - `ElementHandle` queries fixture (`fixtures`) [↓](#legacy-playwright-test-fixture) - Standalone queries for **playwright** via **playwright-testing-library** @@ -88,6 +88,27 @@ test('my form', async ({screen, within}) => { }) ``` +#### Async Methods + +The `findBy` queries work the same way as they do in [Testing Library core](https://testing-library.com/docs/dom-testing-library/api-async) in that they return `Promise` and are intended to be used to defer test execution until an element appears on the page. + +```ts +test('my modal', async ({screen, within}) => { + // Here we wait for a modal to appear asynchronously before continuing + // Note: the timeout for `findBy` queries is configured with `asyncUtilTimeout` + const modalLocator = await screen.findByRole('dialog') + + // Once the modal is visible, we can interact with its contents and assert + await expect(modalLocator).toHaveText(/My Modal/) + await within(modalLocator).getByRole('button', {name: 'Okay'}).click() + + // We can also use `queryBy` methods to take advantage of Playwright's `Locator` auto-waiting + // See: https://playwright.dev/docs/actionability + // Note: this will use Playwright's timeout, not `asyncUtilTimeout` + await expect(screen.queryByRole('dialog')).toBeHidden() +}) +``` + #### Configuration The `Locator` query API is configured using Playwright's `use` API. See Playwright's documentation for [global](https://playwright.dev/docs/api/class-testconfig#test-config-use), [project](https://playwright.dev/docs/api/class-testproject#test-project-use), and [test](https://playwright.dev/docs/api/class-test#test-use). @@ -277,7 +298,7 @@ describe('my page', () => { ### Testing Library -All queries from **[@testing-library/dom](https://github.com/testing-library/dom-testing-library#usage)** are supported. +All queries from **[@testing-library/dom](https://github.com/testing-library/dom-testing-library#usage)** are supported. > 📝 The **`find*`** queries for the `Locator` queries return `Promise` which resolves when the element is found before the timeout specified via `asyncUtilTimeout` From b034827a7d356a62e705699e8cf1e274907b9c63 Mon Sep 17 00:00:00 2001 From: Jamie Rolfs Date: Tue, 20 Sep 2022 00:23:26 -0700 Subject: [PATCH 2/6] test(fixture): add coverage for auto-waiting with `queryBy` --- test/fixture/locators.test.ts | 9 +++++++++ test/fixtures/late-page.html | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/test/fixture/locators.test.ts b/test/fixture/locators.test.ts index 6666003..1076774 100644 --- a/test/fixture/locators.test.ts +++ b/test/fixture/locators.test.ts @@ -214,6 +214,15 @@ test.describe('lib/fixture.ts (locators)', () => { expect(await locator.textContent()).toEqual('Loaded!') }) + test("queryBy* methods can be used with Playwright's laziness", async ({screen, within}) => { + const modalLocator = await screen.findByRole('dialog', undefined, {timeout: 3000}) + + await expect(modalLocator).toHaveText(/My Modal/) + await within(modalLocator).getByRole('button', {name: 'Okay'}).click() + + await expect(screen.queryByRole('dialog')).toBeHidden() + }) + test('should handle the findAllBy* methods', async ({queries}) => { const locator = await queries.findAllByText(/Hello/, undefined, {timeout: 3000}) diff --git a/test/fixtures/late-page.html b/test/fixtures/late-page.html index ea0eae2..9ec77c3 100644 --- a/test/fixtures/late-page.html +++ b/test/fixtures/late-page.html @@ -25,6 +25,25 @@ attached.textContent = 'Attached' attached.style.visibility = 'hidden' document.body.appendChild(attached) + + const modal = document.createElement('dialog') + const modalButton = document.createElement('button') + const modalHeader = document.createElement('h1') + + modal.style.display = 'block' + + modalButton.innerText = 'Okay' + modalButton.onclick = () => { + modal.innerText = 'Doing a thing...' + setTimeout(() => document.querySelector('dialog').remove(), 1000) + } + + modalHeader.innerText = 'My Modal' + + modal.appendChild(modalButton) + modal.appendChild(modalHeader) + + document.body.appendChild(modal) }, 2000) From b0452edae4b7795977bc8231250bc063150395af Mon Sep 17 00:00:00 2001 From: Jamie Rolfs Date: Tue, 20 Sep 2022 00:30:45 -0700 Subject: [PATCH 3/6] docs(readme): fix link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb1e568..6fa9970 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ All of your favorite user-centric querying functions from **@testing-library/react** and **@testing-library/dom** available from within Playwright! - Test [fixture](https://playwright.dev/docs/test-fixtures) for **@playwright/test** via **@playwright-testing-library/test** - - ✨ **New** — `Locator` queries fixture (`locatorFixtures`) [↓](#playwright-test-locator-fixture) + - ✨ **New** — `Locator` queries fixture (`locatorFixtures`) [↓](#playwright-test-fixture) - `ElementHandle` queries fixture (`fixtures`) [↓](#legacy-playwright-test-fixture) - Standalone queries for **playwright** via **playwright-testing-library** - `ElementHandle` queries (`getDocument` + `queries`) [↓](#standalone-playwright-queries) From 401f2ce37f28b172e665280488feec70f414df3f Mon Sep 17 00:00:00 2001 From: Jamie Rolfs Date: Tue, 20 Sep 2022 00:31:02 -0700 Subject: [PATCH 4/6] docs(readme): fix usage summary/recommendation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6fa9970..31f5a70 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ npm install --save-dev playwright-testing-library ## 📝 Usage -There are currently a few different ways to use Playwright Testing Library, depending, however using the `Locator` queries fixture with Playwright Test (**@playwright/test**) is the recommended approach. +There are currently a few different ways to use Playwright Testing Library, depending on how you use Playwright. However, the recommended approach is using the `Locator` [queries fixture](#playwright-test-fixture) with Playwright Test (**@playwright/test**). > ⚠️ The `ElementHandle` query APIs were created before Playwright introduced its `Locator` API and will be replaced in the next major version of Playwright Testing Library. If you can't use **@playwright/test** at the moment, you'll need to use the `ElementHandle` query API, but a migration path will be provided when we switch to the new `Locator` APIs. From 4b7eb6e9c2451d456cf301e220e2738d4cad7de5 Mon Sep 17 00:00:00 2001 From: Jamie Rolfs Date: Thu, 22 Sep 2022 15:01:08 -0700 Subject: [PATCH 5/6] ci(actions): remove Node 12 and add Node 18 to the matrix Playwright dropped support for Node 12 in a non-breaking release, but it's leaving LTS soon anyways. --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6050de1..7fb6b4e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: ['12', '14', '16'] + node: ['14', '16', '18'] # TODO: technically we still support down to 1.12 but `locator.waitFor` # was introduced in 1.16 so anything earlier blows up type-checking. # This minimum will be bumped in the next breaking release that will be @@ -68,7 +68,7 @@ jobs: npm why @playwright/test npm run test:legacy - # Only release on Node 14 + # Only release on Node 16 - name: Upload Coverage / Release / Playwright run: npm run ci-after-success @@ -99,13 +99,13 @@ jobs: run: echo ::set-output name=branch::${GITHUB_REF#refs/*/} - name: Release / Playwright Test (latest) - if: ${{ matrix.node == '14' && matrix.playwright == 'latest' && steps.did-release.outputs.released == 'true' && steps.branch.outputs.branch == 'main' }} + if: ${{ matrix.node == '16' && matrix.playwright == 'latest' && steps.did-release.outputs.released == 'true' && steps.branch.outputs.branch == 'main' }} run: | npm run prepare:playwright-test npm publish --access=public - name: Release / Playwright Test (pre-release) - if: ${{ matrix.node == '14' && matrix.playwright == 'latest' && steps.did-release.outputs.released == 'true' && steps.branch.outputs.branch != 'main' }} + if: ${{ matrix.node == '16' && matrix.playwright == 'latest' && steps.did-release.outputs.released == 'true' && steps.branch.outputs.branch != 'main' }} run: | npm run prepare:playwright-test npm publish --access=public --tag=${{ steps.branch.outputs.branch }} From 4ecf17db808172817e75b5f8cca75d18be2d0a90 Mon Sep 17 00:00:00 2001 From: Jamie Rolfs Date: Wed, 21 Sep 2022 18:50:00 -0700 Subject: [PATCH 6/6] fix(fixture): support function `TextMatch` argument in queries --- lib/fixture/helpers.ts | 6 ++++++ test/fixture/locators.test.ts | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/lib/fixture/helpers.ts b/lib/fixture/helpers.ts index cd4fef4..ec2571d 100644 --- a/lib/fixture/helpers.ts +++ b/lib/fixture/helpers.ts @@ -1,5 +1,6 @@ const replacer = (_: string, value: unknown) => { if (value instanceof RegExp) return `__REGEXP ${value.toString()}` + if (typeof value === 'function') return `__FUNCTION ${value.toString()}` return value } @@ -11,6 +12,11 @@ const reviver = (_: string, value: string) => { return new RegExp(match![1], match![2] || '') } + if (value.toString().includes('__FUNCTION ')) { + // eslint-disable-next-line @typescript-eslint/no-implied-eval + return new Function(`return (${value.split('__FUNCTION ')[1]}).apply(this, arguments)`) + } + return value } diff --git a/test/fixture/locators.test.ts b/test/fixture/locators.test.ts index 1076774..edb88bd 100644 --- a/test/fixture/locators.test.ts +++ b/test/fixture/locators.test.ts @@ -40,6 +40,28 @@ test.describe('lib/fixture.ts (locators)', () => { expect(await locator.textContent()).toEqual('Hello h1') }) + test('supports function style `TextMatch`', async ({screen}) => { + const locator = screen.getByText( + // eslint-disable-next-line prefer-arrow-callback, func-names + function (content, element) { + return content.startsWith('Hello') && element?.tagName.toLowerCase() === 'h3' + }, + ) + + expect(locator).toBeTruthy() + expect(await locator.textContent()).toEqual('Hello h3') + }) + + test('supports arrow function style `TextMatch`', async ({screen}) => { + const locator = screen.getByText( + (content, element) => + content.startsWith('Hello') && element?.tagName.toLowerCase() === 'h3', + ) + + expect(locator).toBeTruthy() + expect(await locator.textContent()).toEqual('Hello h3') + }) + test('should handle the get* methods', async ({queries: {getByTestId}}) => { const locator = getByTestId('testid-text-input')