Shorthand attribute selectors
Playwright supports shorthand for selecting elements using certain attributes: 'id', 'data-testid', 'data-test-id', 'data-test'. For example, 'id=username' fills an input with id 'username', and 'data-test-id=submit' clicks an element with data-test-id 'submit'.
Attribute selectors do not support CSS pseudo-classes
Attribute selectors are not CSS selectors, so CSS-specific pseudo-classes like :enabled are not supported. For more features, use a proper CSS selector, for example 'css=[data-test="login"]:enabled'.
Chaining selectors with >> operator
Selectors defined as 'engine=body' or in short-form can be combined with the '>>' token. When selectors are chained, the next one is queried relative to the previous one's result. For example, 'css=article >> css=.bar > .baz >> css=span[attr=value]' is equivalent to document.querySelector('article').querySelector('.bar > .baz').querySelector('span[attr=value]').
Escaping >> in selector body
If a selector needs to include '>>' in the body, it should be escaped inside a string to not be confused with the chaining separator. For example, 'text="some >> text"' searches for text containing '>>'.
Chained selector intermediate matches with *
By default, chained selectors resolve to an element queried by the last selector. A selector can be prefixed with '*' to capture elements queried by an intermediate selector. For example, 'css=article >> text=Hello' captures the element with text 'Hello', while '*css=article >> text=Hello' captures the article element that contains some element with text 'Hello'.
FrameLocator.owner example
const frameLocator = page.frameLocator('iframe[name="embedded"]');
const locator = frameLocator.owner();
await expect(locator).toBeVisible();
Locator has option filters by child locator
Locators can include a has option to filter elements that contain a specific child element: page.locator('article', { has: page.locator('.highlight') }).click();
Locator.page returns locator's page
The Locator.page method returns the Page associated with the locator.
Locator has option for element composition
The has option in locators allows filtering elements that contain specific child elements, enabling complex element selection patterns.
Frame locators are strict by default
Frame locators introduced in Playwright 1.17 are strict by default. They capture the logic to retrieve an iframe and then locate elements within that iframe. Frame locators will wait for the iframe to appear and can be used in Web-First assertions. Frame locators can be created with either `page.frameLocator()` or `locator.frameLocator()` methods.
Frame locator example usage
Example of creating and using a frame locator: const locator = page.frameLocator('#my-iframe').locator('text=Submit'); await locator.click();
Locators are strict by default
Locators introduced in Playwright 1.14 are strict by default, meaning they ensure the selector points to a single element and throw otherwise. This prevents selector ambiguity issues common in automation testing.
Locator API represents element view
The Locator API (introduced in 1.14) represents a view to the elements on a page and captures the logic sufficient to retrieve the element at any given moment. The key difference from ElementHandle is that Locator captures the retrieval logic, while ElementHandle points to a particular element.
React selector engine syntax
React selectors (experimental in 1.14) allow selecting elements by component name and/or property values using syntax similar to attribute selectors. Example: await page.locator('_react=SubmitButton[enabled=true]').click();
Vue selector engine syntax
Vue selectors (experimental in 1.14) allow selecting elements by component name and/or property values. Example: await page.locator('_vue=submit-button[enabled=true]').click();
getByTitle locator by title attribute
The Page.getByTitle method locates an element by its title attribute.
nth selector engine usage
The `nth` selector engine (introduced in 1.14) is equivalent to the `:nth-match` pseudo class but can be combined with other selector engines. Alternative syntax using locators: page.locator('button').first(), page.locator('button').nth(0), page.locator('button').last()
visible selector engine usage
The `visible` selector engine (introduced in 1.14) is equivalent to the `:visible` pseudo class but can be combined with other selector engines. Example: await page.locator('button >> visible=true').click();
Strict mode throws on selector ambiguity
Strict mode (introduced in 1.14) ensures a selector points to a single element and throws if it matches multiple elements. Pass `strict: true` to action calls to opt in. Example: await page.click('button', { strict: true });
CSS selector extensions in 1.7
Playwright 1.7 introduced new CSS selector extensions and revamped the selectors implementation for more flexible selectors.
has-text pseudo-class for CSS selectors
The `:has-text("example")` pseudo-class (introduced in 1.9) matches any element containing "example" somewhere inside, possibly in a child or descendant element.
CSS selectors with layout matching
Playwright 1.8 introduced layout-based CSS selectors: `:left-of()`, `:right-of()`, `:above()`, and `:below()` for selecting elements based on layout.
getByTestId locator by data-testid attribute
The Page.getByTestId method locates an element based on its data-testid attribute (the attribute name can be configured).
getByPlaceholder locator by input placeholder
The Page.getByPlaceholder method locates an input element by its placeholder text.
getByAltText locator by alt text
The Page.getByAltText method locates an element (usually an image) by its text alternative (alt attribute).
getByLabel locator by associated label text
The Page.getByLabel method locates a form control by the associated label's text.
addLocatorHandler times option limits handler execution
The times option in Page.addLocatorHandler specifies the maximum number of times the handler should be executed. After reaching this limit, the handler will no longer be invoked.
addLocatorHandler example with overlay
const locator = page.getByText('This interstitial covers the button');
await page.addLocatorHandler(locator, async overlay => {
await overlay.locator('#close').click();
}, { times: 3, noWaitAfter: true });
await page.removeLocatorHandler(locator);
Locator.contentFrame converts Locator to FrameLocator
The new Locator.contentFrame method converts a Locator object to a FrameLocator, useful when you have a Locator and need to interact with content inside an iframe.
FrameLocator.owner converts FrameLocator to Locator
The new FrameLocator.owner method converts a FrameLocator object to a Locator, useful when you need to interact with the iframe element itself.
contentFrame example
const locator = page.locator('iframe[name="embedded"]');
const frameLocator = locator.contentFrame();
await frameLocator.getByRole('button').click();
Page.addLocatorHandler registers overlay handler callback
The Page.addLocatorHandler method registers a callback that is invoked when a specified element becomes visible and may block Playwright actions. The callback can dismiss overlays like cookie dialogs.
addLocatorHandler cookie dialog example
await page.addLocatorHandler(
page.getByRole('heading', { name: 'Hej! You are in control of your cookies.' }),
async () => {
await page.getByRole('button', { name: 'Accept all' }).click();
});
await page.goto('https://www.ikea.com/');
Locator.filter with hasNot and hasNotText options
The Locator.filter method now supports hasNot and hasNotText options to find elements that do not match certain conditions.
Locator.or creates union locator
The Locator.or method creates a locator that matches either of two locators, useful for handling variable UI like dialogs that may appear instead of expected elements.
removeLocatorHandler removes previously added handlers
Page.removeLocatorHandler removes a handler that was previously registered with Page.addLocatorHandler for a specific locator.
addLocatorHandler passes locator as argument to handler
The handler callback in Page.addLocatorHandler now receives the locator as an argument, allowing the handler to interact with the element that triggered it.
getByRole locator with ARIA role and attributes
The Page.getByRole method locates elements by their ARIA role, ARIA attributes, and accessible name, following accessibility best practices.
getByText locator by text content
The Page.getByText method locates elements by their visible text content.
Locator.filter filters locator by conditions
The Locator.filter method creates a new locator that only matches elements satisfying additional conditions like hasText.
Locator.and creates intersection locator
The Locator.and method creates a locator that matches elements satisfying both locator conditions, useful for precise element selection.
Locator hasText filter option
Locators can be filtered by text using the hasText option: page.locator('li', { hasText: 'my item' }).locator('button').click();
testIdAttribute configuration option
The testIdAttribute option changes the default data-testid attribute used by Playwright locators. Defaults to 'data-testid'. Example: 'pw-test-id' changes the attribute to data-pw-test-id.
Basic Playwright actions on locators
The most popular Playwright actions are: check (check the input checkbox), click (click the element), uncheck (uncheck the input checkbox), hover (hover mouse over the element), fill (fill the form field, input text), focus (focus the element), press (press single key), setInputFiles (pick files to upload), and selectOption (select option in the drop down).
ElementHandle is discouraged
The use of ElementHandle is discouraged. Use Locator objects and web-first assertions instead.
Fetching ElementHandle with waitForSelector
When ElementHandle is required, fetch it with page.waitForSelector() or Frame.waitForSelector() methods. These APIs wait for the element to be attached and visible.
Obtaining JSHandle example
To obtain a JSHandle, call page.evaluateHandle with a JavaScript expression: const jsHandle = await page.evaluateHandle('window');
ElementHandle boundingBox example
To assert the bounding box of an element: const elementHandle = page.waitForSelector('#box'); const boundingBox = await elementHandle.boundingBox(); expect(boundingBox.width).toBe(100);
ElementHandle getAttribute example
To assert an element attribute: const classNames = await elementHandle.getAttribute('class'); expect(classNames.includes('highlighted')).toBeTruthy();
Passing handles to evaluate method
Handles can be passed into page.evaluate() and similar methods as parameters. This allows using handles in subsequent evaluations within the page context.
Handle lifecycle and garbage collection
Handles are acquired using page methods such as page.evaluateHandle(), page.querySelector(), or page.querySelectorAll() and their frame counterparts. Once created, handles retain objects from garbage collection unless the page navigates or the handle is manually disposed via JSHandle.dispose() method.
Disposing handles example
To release a handle when no longer needed: await myArrayHandle.dispose();
Locator vs ElementHandle difference
ElementHandle points to a particular DOM element at a moment in time. If that element changes text or React renders a different component, the handle still points to the stale DOM element. Locator captures the logic of how to retrieve an element, so every time it is used, the up-to-date DOM element is located using the selector.
Locator example with fresh element
Locator example showing how it retrieves fresh elements: const locator = page.getByText('Submit'); await locator.hover(); await locator.click(); The locator re-locates the underlying DOM element each time it is used.
ElementHandle example with stale element
ElementHandle example showing the problem of stale references: const handle = await page.$('text=Submit'); await handle.hover(); await handle.click(); The handle points to a specific element that may become stale.
When to use ElementHandle
Only recommend using ElementHandle in the rare cases when you need to perform extensive DOM traversal on a static page. For all user actions and assertions use locator instead.
JSHandle vs ElementHandle types
Playwright can create two types of handles to page objects. JSHandle references any JavaScript object in the page. ElementHandle references DOM elements in the page and has extra methods for performing actions and asserting properties. Since any DOM element is also a JavaScript object, any ElementHandle is a JSHandle as well.
Passing handle to evaluate with parameters
Handles can be passed as parameters to page.evaluate() by including them in an object or array: await page.evaluate(arg => arg.myArray.push(arg.newElement), { myArray: myArrayHandle, newElement: 2 });