playwright-testing-library
🔍 Find elements in playwright like your users with queries from @testing-library/dom
🎛 Features
All of your favorite user-centric querying functions from @testing-library/react and @testing-library/dom available from within Playwright!
- Playwright Test fixture for @playwright/test via @playwright-testing-library/test
- ✨ New —
Locator queries fixture (locatorFixtures) ↓
ElementHandle queries fixture (fixtures) ↓
- Standalone queries for playwright via playwright-testing-library
ElementHandle queries (getDocument + queries) ↓
- Asynchronous
waitFor assertion helper (via wait-for-expect)
🌱 Installation
npm install --save-dev @playwright-testing-library/test
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.
⚠️ 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.
Playwright Test Fixture
Using the Locator Playwright Test (@playwright/test) fixture with @playwright-testing-library/test.
Setup
import {test as base} from '@playwright/test'
import {
locatorFixtures as fixtures,
LocatorFixtures as TestingLibraryFixtures,
} from '@playwright-testing-library/test/fixture'
const test = base.extend<TestingLibraryFixtures>(fixtures)
const {expect} = test
test('my form', async ({screen, within}) => {
const formLocator = screen.getByTestId('my-form')
const emailInputLocator = within(formLocator).getByLabelText('Email')
await emailInputLocator.fill('email@playwright.dev')
await emailInputLocator.press('Enter')
screen.goto('/account')
const emailLocator = screen.getByRole('heading', {level: 2})
await expect(emailLocator).toHaveText('email@playwright.dev')
})
Configuration
The Locator query API is configured using Playwright's use API. See Playwright's documentation for global, project, and test.
Global
Configuring Testing Library globally in playwright.config.ts
import type {PlaywrightTestConfig} from '@playwright/test'
const config: PlaywrightTestConfig = {
use: {
testIdAttribute: 'data-testid',
asyncUtilTimeout: 1000,
asyncUtilExpectedState: 'visible',
},
}
export default config
Local
Scoping Testing Library configuration to test suites or describe blocks
import {test as base} from '@playwright/test'
import {
locatorFixtures as fixtures,
LocatorFixtures as TestingLibraryFixtures,
} from '@playwright-testing-library/test/fixture'
const test = base.extend<TestingLibraryFixtures>(fixtures)
const {describe, expect, use} = test
use({testIdAttribute: 'data-custom-test-id'})
describe(() => {
use({
testIdAttribute: 'some-other-test-id',
asyncUtilsTimeout: 5000,
asyncUtilExpectedState: 'attached',
})
test('my form', async ({screen}) => {
})
})
Legacy Playwright Test Fixture
Using the ElementHandle Playwright Test (@playwright/test) fixture with @playwright-testing-library/test.
⚠️ See note in Usage as you should be using the Locator fixture if possible
Setup
import {test as base} from '@playwright/test'
import {fixtures, within, TestingLibraryFixtures} from '@playwright-testing-library/test/fixture'
const test = base.extend<TestingLibraryFixtures>(fixtures)
const {expect} = test
test('my form', async ({page, queries}) => {
const formHandle = await queries.getByTestId('my-form')
const emailInputHandle = await within(formHandle).getByLabelText('Email')
await emailInputHandle.fill('email@playwright.dev')
await emailInputHandle.press('Enter')
page.goto('/account')
const emailHandle = queries.getByRole('heading', {level: 2})
expect(await emailHandle.textContent()).toEqual('email@playwright.dev')
})
Configuration
import {test as base} from '@playwright/test'
import {
configure,
fixtures,
within,
TestingLibraryFixtures,
} from '@playwright-testing-library/test/fixture'
const test = base.extend<TestingLibraryFixtures>(fixtures)
const {beforeEach, describe, expect} = test
configure({asyncUtilTimeout: 1000, testIdAttribute: 'data-testid'})
describe('my page', () => {
beforeEach(() => configure({asyncUtilTimeout: 5000, testIdAttribute: 'data-custom-test-id'}))
afterEach(() => configure({}))
test('my form', async ({page, queries}) => {
})
})
Standalone Playwright Queries
Using the ElementHandle queries with Playwright (playwright) and playwright-testing-library.
⚠️ See note in Usage as you should be using @playwright/test with the Locator fixture if possible. The Locator queries will be made available for standalone playwright in the next major release.
import {beforeAll, expect, jest, test} from '@jest/globals'
import {webkit} from 'playwright'
import {getDocument, queries, within} from 'playwright-testing-library'
let browser: playwright.Browser
let page: playwright.Page
beforeAll(() => {
const browser = await webkit.launch()
const page = await browser.newPage()
})
test('my form', () => {
const documentHandle = await getDocument(page)
const formHandle = await queries.getByTestId(documentHandle, 'my-form')
const emailInputHandle = await within(formHandle).getByLabelText('Email')
await emailInputHandle.fill('email@playwright.dev')
await emailInputHandle.press('Enter')
page.goto('/account')
const accountHandle = getDocument(page)
const emailHandle = queries.getByRole(accountHandle, 'heading', {level: 2})
expect(await emailHandle.textContent()).toEqual('email@playwright.dev')
})
Configuration
import {beforeEach, afterEach, expect, jest, test} from '@jest/globals'
import {configure, getDocument, queries, within} from 'playwright-testing-library'
configure({asyncUtilTimeout: 1000, testIdAttribute: 'data-testid'})
describe('my page', () => {
beforeEach(() => configure({asyncUtilTimeout: 5000, testIdAttribute: 'data-custom-test-id'}))
afterEach(() => configure({}))
test('my form', async ({page, queries}) => {
})
})
🔌 API
Testing Library
All queries from @testing-library/dom 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
Additional
Unique methods, not part of @testing-library/dom
⚠️ These only apply to the ElementHandle queries
-
Get an ElementHandle for the document
getDocument(page: playwright.Page): ElementHandle
-
Wait for an assertion (wrapper around wait-for-expect)
waitFor(
expectation: () => void | Promise<void>,
timeout?: number,
interval?: number
): Promise<{}>
Known Limitations
- Only
testIdAttribute and asyncUtilTimeout are supported as configuration options
- Async utilities
waitForElement, waitForElementToBeRemoved and waitForDomChange are not exposed. Consider using a find* query or a Playwright built-in like Locator.waitFor().
- The
fireEvent method is not exposed, use Playwright's built-ins instead.
- Assertion extensions from jest-dom are not compatible, use Playwright Test if possible.
- The
getNodeText() function is not currently supported for Locator.
Special Thanks
Related Playwright Test Utilities
LICENSE
MIT
Maintenance
This project is actively maintained by engineers at
@hoverinc 😀.