Security News
Introducing the Socket Python SDK
The initial version of the Socket Python SDK is now on PyPI, enabling developers to more easily interact with the Socket REST API in Python projects.
playwright-testing-library
Advanced tools
🔍 Find elements in playwright like your users with queries from @testing-library/dom
All of your favorite user-centric querying functions from @testing-library/react and @testing-library/dom available from within Playwright!
ElementHandle
queries (getDocument
+ queries
) ↓waitFor
assertion helper (via wait-for-expect)# For use with Playwright Test (@playwright/test)
npm install --save-dev @playwright-testing-library/test
# For use with Playwright (playwright)
npm install --save-dev playwright-testing-library
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 with Playwright Test (@playwright/test).
⚠️ The
ElementHandle
query APIs were created before Playwright introduced itsLocator
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 theElementHandle
query API, but a migration path will be provided when we switch to the newLocator
APIs.
🔖 Added in 4.4.0
Using the Locator
Playwright Test (@playwright/test) fixture with @playwright-testing-library/test.
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}) => {
// Screen provides `Locator` queries scoped to current Playwright `Page`
const formLocator = screen.getByTestId('my-form')
// Scope queries to `Locator` with `within`
// (note that this is a fixture from `test`, not the `within` import)
const emailInputLocator = within(formLocator).getByLabelText('Email')
// Interact via `Locator` API 🥳
await emailInputLocator.fill('email@playwright.dev')
await emailInputLocator.press('Enter')
// Screen also provides Playwright's `Page` API
screen.goto('/account')
const emailLocator = screen.getByRole('heading', {level: 2})
// Assert via `Locator` APIs 🎉
await expect(emailLocator).toHaveText('email@playwright.dev')
})
The findBy
queries work the same way as they do in Testing Library core in that they return Promise<Locator>
and are intended to be used to defer test execution until an element appears on the page.
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()
})
🔖 Added in 4.5.0
As an alternative to the within(locator: Locator)
function you're familiar with from Testing Library, Playwright Testing Library also supports chaining queries together.
All synchronous queries (get*
+ query*
) return Locator
instances are augmented with a .within()
method (TestingLibraryLocator
). All asynchronous queries (find*
) return a special LocatorPromise
that also supports .within()
. This makes it possible to chain queries, including chaining get*
, query*
and find*
interchangeably.
⚠️ Note that including any
find*
query in the chain will make the entire chain asynchronous
test('chaining synchronous queries', async ({screen}) => {
const locator = screen.getByRole('figure').within().findByRole('img')
expect(await locator.getAttribute('alt')).toEqual('Some image')
})
test('chaining synchronous queries + asynchronous queries', ({screen}) => {
// ↓↓↓↓↓ including any `find*` queries makes the whole chain asynchronous
const locator = await screen
.getByTestId('modal-container') // Get "modal container" or throw (sync)
.within()
.findByRole('dialog') // Wait for modal to appear (async, until `asyncUtilTimeout`)
.within()
.getByRole('button', {name: 'Close'}) // Get close button within modal (sync)
expect(await locator.textContent()).toEqual('Close')
})
The Locator
query API is configured using Playwright's use
API. See Playwright's documentation for global, project, and test.
Configuring Testing Library globally in playwright.config.ts
import type {PlaywrightTestConfig} from '@playwright/test'
const config: PlaywrightTestConfig = {
use: {
// These are the defaults
testIdAttribute: 'data-testid',
asyncUtilTimeout: 1000,
asyncUtilExpectedState: 'visible',
},
}
export default config
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
// Entire test suite
use({testIdAttribute: 'data-custom-test-id'})
describe(() => {
// Specific block
use({
testIdAttribute: 'some-other-test-id',
asyncUtilsTimeout: 5000,
asyncUtilExpectedState: 'attached',
})
test('my form', async ({screen}) => {
// ...
})
})
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
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}) => {
// Query methods are available in `test` blocks
const formHandle = await queries.getByTestId('my-form')
// Scope queries to an `ElementHandle` with `within`
const emailInputHandle = await within(formHandle).getByLabelText('Email')
// Interact via `ElementHandle` API
await emailInputHandle.fill('email@playwright.dev')
await emailInputHandle.press('Enter')
page.goto('/account')
const emailHandle = queries.getByRole('heading', {level: 2})
// Assert via `ElementHandle` APIs
expect(await emailHandle.textContent()).toEqual('email@playwright.dev')
})
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
// Global (these are the defaults)
configure({asyncUtilTimeout: 1000, testIdAttribute: 'data-testid'})
// Specific block
describe('my page', () => {
beforeEach(() => configure({asyncUtilTimeout: 5000, testIdAttribute: 'data-custom-test-id'}))
afterEach(() => configure({}))
test('my form', async ({page, 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. TheLocator
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' // or 'firefox' or 'chromium'
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', () => {
// Get `ElementHandle` for document from `Page`
const documentHandle = await getDocument(page)
// Global query methods take document handle as the first parameter
const formHandle = await queries.getByTestId(documentHandle, 'my-form')
// Scope queries to an `ElementHandle` with `within`
const emailInputHandle = await within(formHandle).getByLabelText('Email')
// Interact via `ElementHandle` API
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})
// Assert via `ElementHandle` APIs
expect(await emailHandle.textContent()).toEqual('email@playwright.dev')
})
import {beforeEach, afterEach, expect, jest, test} from '@jest/globals'
import {configure, getDocument, queries, within} from 'playwright-testing-library'
// Global (these are the defaults)
configure({asyncUtilTimeout: 1000, testIdAttribute: 'data-testid'})
// Specific block
describe('my page', () => {
beforeEach(() => configure({asyncUtilTimeout: 5000, testIdAttribute: 'data-custom-test-id'}))
afterEach(() => configure({}))
test('my form', async ({page, queries}) => {
// ...
})
})
All queries from @testing-library/dom are supported.
📝 The
find*
queries for theLocator
queries returnPromise<Locator>
which resolves when the element is found before the timeout specified viaasyncUtilTimeout
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<{}>
testIdAttribute
and asyncUtilTimeout
are supported as configuration optionswaitForElement
, waitForElementToBeRemoved
and waitForDomChange
are not exposed. Consider using a find*
query or a Playwright built-in like Locator.waitFor()
.fireEvent
method is not exposed, use Playwright's built-ins instead.The getNodeText()
function is currently unsupported.
When using a function for TextMatch
, the function cannot reference its closure scope
// ✅ This is supported
screen.getByText(content => content.startsWith('Foo'))
// ❌ This is not supported
const startsWithFoo = (content: string) => content.startsWith('Foo')
screen.getByText(content => startsWithFoo(content))
MIT
This project is actively maintained by engineers at @hoverinc 😀.
FAQs
playwright + dom-testing-library
The npm package playwright-testing-library receives a total of 2,817 weekly downloads. As such, playwright-testing-library popularity was classified as popular.
We found that playwright-testing-library demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
The initial version of the Socket Python SDK is now on PyPI, enabling developers to more easily interact with the Socket REST API in Python projects.
Security News
Floating dependency ranges in npm can introduce instability and security risks into your project by allowing unverified or incompatible versions to be installed automatically, leading to unpredictable behavior and potential conflicts.
Security News
A new Rust RFC proposes "Trusted Publishing" for Crates.io, introducing short-lived access tokens via OIDC to improve security and reduce risks associated with long-lived API tokens.