Skip to content

Commit 1b41bd5

Browse files
committed
docs(readme): add Locator documentation and clarify different APIs
1 parent e66667d commit 1b41bd5

File tree

1 file changed

+228
-100
lines changed

1 file changed

+228
-100
lines changed

README.md

+228-100
Original file line numberDiff line numberDiff line change
@@ -22,94 +22,271 @@
2222

2323
<br>
2424

25-
## Features
25+
## 🎛 Features
2626

27-
All of your favorite user-centric querying functions from **@testing-library/react** and **@testing-library/dom** available from Playwright!
27+
All of your favorite user-centric querying functions from **@testing-library/react** and **@testing-library/dom** available from within Playwright!
2828

29-
- Playwright Test [fixture](https://playwright.dev/docs/test-fixtures)**`@playwright-testing-library/test/fixture`** or...
30-
- Standalone queries — **`playwright-testing-library`**/**`@playwright-testing-library/test`**
31-
- Asynchronous assertion helper (via **[wait-for-expect](https://github.com/TheBrainFamily/wait-for-expect)**)
29+
- Playwright Test [fixture](https://playwright.dev/docs/test-fixtures) for **@playwright/test** via **@playwright-testing-library/test**
30+
-**New**`Locator` queries fixture (`locatorFixtures`) [](#playwright-test-locator-fixture)
31+
- `ElementHandle` queries fixture (`fixtures`) [](#legacy-playwright-test-fixture)
32+
- Standalone queries for **playwright** via **playwright-testing-library**
33+
- `ElementHandle` queries (`getDocument` + `queries`) [](#standalone-playwright-queries)
34+
- Asynchronous `waitFor` assertion helper (via **[wait-for-expect](https://github.com/TheBrainFamily/wait-for-expect)**)
3235

33-
## 🌱 Getting Started
34-
35-
### 1. Install
36+
## 🌱 Installation
3637

3738
```bash
3839
# For use with Playwright Test (@playwright/test)
3940
npm install --save-dev @playwright-testing-library/test
4041

4142
# For use with Playwright (playwright)
4243
npm install --save-dev playwright-testing-library
43-
4444
```
4545

46-
### 2a. Use _Playwright Test [fixture](https://playwright.dev/docs/test-fixtures)_
46+
## 📝 Usage
47+
48+
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.
49+
50+
> ⚠️ 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.
51+
52+
### Playwright Test Fixture
53+
54+
Using the `Locator` Playwright Test (**@playwright/test**) fixture with **@playwright-testing-library/test**.
55+
56+
#### Setup
4757

4858
```ts
49-
import {test as baseTest} from '@playwright/test'
50-
import {fixtures, within, TestingLibraryFixtures} from '@playwright-testing-library/test/fixture'
59+
import {test as base} from '@playwright/test'
60+
import {
61+
locatorFixtures as fixtures,
62+
LocatorFixtures as TestingLibraryFixtures,
63+
} from '@playwright-testing-library/test/fixture'
64+
65+
const test = base.extend<TestingLibraryFixtures>(fixtures)
66+
67+
const {expect} = test
68+
69+
test('my form', async ({screen, within}) => {
70+
// Screen provides `Locator` queries scoped to current Playwright `Page`
71+
const formLocator = screen.getByTestId('my-form')
72+
73+
// Scope queries to `Locator` with `within`
74+
// (note that this is a fixture from `test`, not the `within` import)
75+
const emailInputLocator = within(formLocator).getByLabelText('Email')
76+
77+
// Interact via `Locator` API 🥳
78+
await emailInputLocator.fill('[email protected]')
79+
await emailInputLocator.press('Enter')
80+
81+
// Screen also provides Playwright's `Page` API
82+
screen.goto('/account')
83+
84+
const emailLocator = screen.getByRole('heading', {level: 2})
85+
86+
// Assert via `Locator` APIs 🎉
87+
await expect(emailLocator).toHaveText('[email protected]')
88+
})
89+
```
90+
91+
#### Configuration
92+
93+
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).
5194

52-
// As only fixture
53-
const test = baseTest.extend<TestingLibraryFixtures>(fixtures)
95+
##### Global
5496

55-
// Alternatively, with other fixtures
56-
interface Fixtures extends TestingLibraryFixtures {
57-
// ... additional fixture types
97+
Configuring Testing Library globally in `playwright.config.ts`
98+
99+
```ts
100+
import type {PlaywrightTestConfig} from '@playwright/test'
101+
102+
const config: PlaywrightTestConfig = {
103+
use: {
104+
// These are the defaults
105+
testIdAttribute: 'data-testid',
106+
asyncUtilTimeout: 1000,
107+
asyncUtilExpectedState: 'visible',
108+
},
58109
}
59110

60-
const test = baseTest.extend<Fixtures>({
61-
...fixtures,
62-
// ... additional fixtures
111+
export default config
112+
```
113+
114+
##### Local
115+
116+
Scoping Testing Library configuration to test suites or `describe` blocks
117+
118+
```ts
119+
import {test as base} from '@playwright/test'
120+
import {
121+
locatorFixtures as fixtures,
122+
LocatorFixtures as TestingLibraryFixtures,
123+
} from '@playwright-testing-library/test/fixture'
124+
125+
const test = base.extend<TestingLibraryFixtures>(fixtures)
126+
127+
const {describe, expect, use} = test
128+
129+
// Entire test suite
130+
use({testIdAttribute: 'data-custom-test-id'})
131+
132+
describe(() => {
133+
// Specific block
134+
use({
135+
testIdAttribute: 'some-other-test-id',
136+
asyncUtilsTimeout: 5000,
137+
asyncUtilExpectedState: 'attached',
138+
})
139+
140+
test('my form', async ({screen}) => {
141+
// ...
142+
})
63143
})
144+
```
145+
146+
### Legacy Playwright Test Fixture
147+
148+
Using the `ElementHandle` Playwright Test (**@playwright/test**) fixture with **@playwright-testing-library/test**.
149+
150+
> ⚠️ See note in [Usage](#-usage) as you should be using the `Locator` fixture if possible
151+
152+
#### Setup
153+
154+
```ts
155+
import {test as base} from '@playwright/test'
156+
import {fixtures, within, TestingLibraryFixtures} from '@playwright-testing-library/test/fixture'
157+
158+
const test = base.extend<TestingLibraryFixtures>(fixtures)
64159

65160
const {expect} = test
66161

67-
// Query methods are available in `test` blocks
68-
test('my form', async ({queries: {getByTestId}}) => {
69-
const $form = await getByTestId('my-form')
162+
test('my form', async ({page, queries}) => {
163+
// Query methods are available in `test` blocks
164+
const formHandle = await queries.getByTestId('my-form')
165+
166+
// Scope queries to an `ElementHandle` with `within`
167+
const emailInputHandle = await within(formHandle).getByLabelText('Email')
168+
169+
// Interact via `ElementHandle` API
170+
await emailInputHandle.fill('[email protected]')
171+
await emailInputHandle.press('Enter')
172+
173+
page.goto('/account')
174+
175+
const emailHandle = queries.getByRole('heading', {level: 2})
176+
177+
// Assert via `ElementHandle` APIs
178+
expect(await emailHandle.textContent()).toEqual('[email protected]')
179+
})
180+
```
181+
182+
#### Configuration
70183

71-
// Scope queries with `within`
72-
const {getByLabelText} = within($form)
184+
```ts
185+
import {test as base} from '@playwright/test'
186+
import {
187+
configure,
188+
fixtures,
189+
within,
190+
TestingLibraryFixtures,
191+
} from '@playwright-testing-library/test/fixture'
192+
193+
const test = base.extend<TestingLibraryFixtures>(fixtures)
194+
195+
const {beforeEach, describe, expect} = test
73196

74-
const $email = await getByLabelText('Email')
197+
// Global (these are the defaults)
198+
configure({asyncUtilTimeout: 1000, testIdAttribute: 'data-testid'})
75199

76-
// Interact with Playwright like usual
77-
await $email.type('[email protected]')
200+
// Specific block
201+
describe('my page', () => {
202+
beforeEach(() => configure({asyncUtilTimeout: 5000, testIdAttribute: 'data-custom-test-id'}))
78203

79-
// ...
204+
afterEach(() => configure({}))
205+
206+
test('my form', async ({page, queries}) => {
207+
// ...
208+
})
80209
})
81210
```
82211

83-
### 2b. Use _standalone queries_
212+
### Standalone Playwright Queries
213+
214+
Using the `ElementHandle` queries with Playwright (**playwright**) and **playwright-testing-library**.
84215

85-
```js
86-
const {webkit} = require('playwright') // or 'firefox' or 'chromium'
87-
const {getDocument, queries} = require('playwright-testing-library')
216+
> ⚠️ See note in [Usage](#-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.
88217
89-
const {getByTestId, getByLabelText} = queries
218+
```ts
219+
import {beforeAll, expect, jest, test} from '@jest/globals'
220+
import {webkit} from 'playwright' // or 'firefox' or 'chromium'
221+
import {getDocument, queries, within} from 'playwright-testing-library'
222+
223+
let browser: playwright.Browser
224+
let page: playwright.Page
225+
226+
beforeAll(() => {
227+
const browser = await webkit.launch()
228+
const page = await browser.newPage()
229+
})
90230

91-
const browser = await webkit.launch()
92-
const page = await browser.newPage()
231+
test('my form', () => {
232+
// Get `ElementHandle` for document from `Page`
233+
const documentHandle = await getDocument(page)
93234

94-
// Grab ElementHandle for document
95-
const $document = await getDocument(page)
235+
// Global query methods take document handle as the first parameter
236+
const formHandle = await queries.getByTestId(documentHandle, 'my-form')
96237

97-
// Your favorite query methods are available
98-
const $form = await getByTestId($document, 'my-form')
238+
// Scope queries to an `ElementHandle` with `within`
239+
const emailInputHandle = await within(formHandle).getByLabelText('Email')
99240

100-
// Returned elements are ElementHandles too!
101-
const $email = await getByLabelText($form, 'Email')
241+
// Interact via `ElementHandle` API
242+
await emailInputHandle.fill('[email protected]')
243+
await emailInputHandle.press('Enter')
102244

103-
// Interact with playwright like usual
104-
await $email.type('[email protected]')
245+
page.goto('/account')
105246

106-
// ...
247+
const accountHandle = getDocument(page)
248+
const emailHandle = queries.getByRole(accountHandle, 'heading', {level: 2})
249+
250+
// Assert via `ElementHandle` APIs
251+
expect(await emailHandle.textContent()).toEqual('[email protected]')
252+
})
253+
```
254+
255+
#### Configuration
256+
257+
```ts
258+
import {beforeEach, afterEach, expect, jest, test} from '@jest/globals'
259+
import {configure, getDocument, queries, within} from 'playwright-testing-library'
260+
261+
// Global (these are the defaults)
262+
configure({asyncUtilTimeout: 1000, testIdAttribute: 'data-testid'})
263+
264+
// Specific block
265+
describe('my page', () => {
266+
beforeEach(() => configure({asyncUtilTimeout: 5000, testIdAttribute: 'data-custom-test-id'}))
267+
268+
afterEach(() => configure({}))
269+
270+
test('my form', async ({page, queries}) => {
271+
// ...
272+
})
273+
})
107274
```
108275

109276
## 🔌 API
110277

278+
### Testing Library
279+
280+
All queries from **[@testing-library/dom](https://github.com/testing-library/dom-testing-library#usage)** are supported.
281+
282+
> 📝 The **`find*`** queries for the `Locator` queries return `Promise<Locator>` which resolves when the element is found before the timeout specified via `asyncUtilTimeout`
283+
284+
### Additional
285+
111286
Unique methods, not part of **@testing-library/dom**
112287

288+
> ⚠️ These only apply to the `ElementHandle` queries
289+
113290
- Get an `ElementHandle` for the document
114291

115292
```ts
@@ -126,72 +303,23 @@ Unique methods, not part of **@testing-library/dom**
126303
): Promise<{}>
127304
```
128305

129-
---
130-
131-
The **[@testing-library/dom](https://github.com/testing-library/dom-testing-library#usage)** — All **`get*`**, **`query*`**, and **`find*`** methods are supported.
132-
133-
- `getQueriesForElement(handle: ElementHandle): ElementHandle & QueryUtils` - extend the input object with the query API and return it
134-
- `getNodeText(handle: ElementHandle): Promise<string>` - get the text content of the element
135-
- `queries: QueryUtils` - the query subset of `@testing-library/dom` exports
136-
- `queryByPlaceholderText`
137-
- `queryAllByPlaceholderText`
138-
- `getByPlaceholderText`
139-
- `getAllByPlaceholderText`
140-
- `findByPlaceholderText`
141-
- `findAllByPlaceholderText`
142-
- `queryByText`
143-
- `queryAllByText`
144-
- `getByText`
145-
- `getAllByText`
146-
- `findByText`
147-
- `findAllByText`
148-
- `queryByLabelText`
149-
- `queryAllByLabelText`
150-
- `getByLabelText`
151-
- `getAllByLabelText`
152-
- `findByLabelText`
153-
- `findAllByLabelText`
154-
- `queryByAltText`
155-
- `queryAllByAltText`
156-
- `getByAltText`
157-
- `getAllByAltText`
158-
- `findByAltText`
159-
- `findAllByAltText`
160-
- `queryByTestId`
161-
- `queryAllByTestId`
162-
- `getByTestId`
163-
- `getAllByTestId`
164-
- `findByTestId`
165-
- `findAllByTestId`
166-
- `queryByTitle`
167-
- `queryAllByTitle`
168-
- `getByTitle`
169-
- `getAllByTitle`
170-
- `findByTitle`
171-
- `findAllByTitle`
172-
- `queryByDisplayValue`,
173-
- `queryAllByDisplayValue`,
174-
- `getByDisplayValue`,
175-
- `getAllByDisplayValue`,
176-
- `findByDisplayValue`,
177-
- `findAllByDisplayValue`,
178-
179306
## Known Limitations
180307

181-
- Async utilities `waitForElement`, `waitForElementToBeRemoved` and `waitForDomChange` are not exposed. Consider using a `find*` query.
182-
- `fireEvent` method is not exposed, use Playwright's built-ins instead.
183-
- `expect` assertion extensions are not available.
308+
- Only `testIdAttribute` and `asyncUtilTimeout` are supported as configuration options
309+
- Async utilities `waitForElement`, `waitForElementToBeRemoved` and `waitForDomChange` are not exposed. Consider using a `find*` query or a Playwright built-in like [`Locator.waitFor()`](https://playwright.dev/docs/api/class-locator#locator-wait-for).
310+
- The `fireEvent` method is not exposed, use Playwright's built-ins instead.
311+
- Assertion extensions from [**jest-dom**](https://testing-library.com/docs/ecosystem-jest-dom/) are not compatible, use Playwright Test if possible.
312+
- The [`getNodeText()`](https://testing-library.com/docs/dom-testing-library/api-custom-queries/#getnodetext) function is not currently supported for `Locator`.
184313

185314
## Special Thanks
186315

187316
- [pptr-testing-library](https://github.com/testing-library/pptr-testing-library)
188-
- [@testing-library/dom](https://github.com/testing-library/dom-testing-library) of course!
317+
- [@testing-library/dom](https://github.com/testing-library/dom-testing-library)
189318

190319
## Related Playwright Test Utilities
191320

192321
- [jest-playwright](https://github.com/playwright-community/jest-playwright)
193322
- [expect-playwright](https://github.com/playwright-community/expect-playwright)
194-
- Yours! Name TBD, PR welcome ;)
195323

196324
## LICENSE
197325

0 commit comments

Comments
 (0)