Skip to content
This repository was archived by the owner on Aug 6, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@

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**
- ✨ **New** — `Locator` queries fixture (`locatorFixtures`) [↓](#playwright-test-locator-fixture)
- Test [fixture](https://playwright.dev/docs/test-fixtures) for **@playwright/test** via **@playwright-testing-library/test**
- ✨ **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)
Expand All @@ -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.

Expand Down Expand Up @@ -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<Locator>` 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).
Expand Down Expand Up @@ -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<Locator>` which resolves when the element is found before the timeout specified via `asyncUtilTimeout`

Expand Down
9 changes: 9 additions & 0 deletions test/fixture/locators.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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})

Expand Down
19 changes: 19 additions & 0 deletions test/fixtures/late-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -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)
</script>
</body>
Expand Down