Locators
Use this guide when you want readable, stable element lookup patterns.
Locator quick map
Section titled “Locator quick map”- CSS:
querySelector,querySelectorAll - Role:
getByRole(role, options?) - Text:
getByText(text, options?) - Label:
getByLabel(label, options?) - Placeholder:
getByPlaceholder(text, options?) - Alt text:
getByAltText(text, options?) - Title:
getByTitle(text, options?) - Data attribute:
getByDataAttribute(name, value, options?) - XPath:
getByXPath(xpath) - Frame chaining:
getFrame(selector) - Raw frame handle:
getFrameElement(selector)
Single-page form flow
Section titled “Single-page form flow”await view.navigate("https://example.com/login");await view.waitForDocumentReady({ state: "complete", timeoutMs: 15000 });
const username = await view.getByLabel("Username", { exact: true });const password = await view.getByPlaceholder("Password", { exact: true });const signIn = await view.getByRole("button", { name: "Sign in", exact: true });
if (!username || !password || !signIn) { throw new Error("Missing login controls");}
await view.click(username);await view.type("demo-user", { perCharacterDelayMs: 0 });
await view.click(password);await view.type("demo-password", { perCharacterDelayMs: 0 });
await view.click(signIn);Content lookup examples
Section titled “Content lookup examples”const releaseNote = await view.getByText("Release notes", { exact: false });const logo = await view.getByAltText("Company logo", { exact: true });const helpIcon = await view.getByTitle("Help", { exact: true });const panel = await view.getByDataAttribute("testid", "settings-panel", { exact: true });const saveByXPath = await view.getByXPath("//button[@id='save']");
if (!releaseNote || !logo || !helpIcon || !panel || !saveByXPath) { throw new Error("Expected content not found");}CSS and multiple matches
Section titled “CSS and multiple matches”const rows = await view.querySelectorAll("table#orders tbody tr");
for (const row of rows) { const status = await view.getAttribute(row, "data-status"); if (status === "pending") { await view.click(row); } await view.disposeElement(row);}Frame chaining
Section titled “Frame chaining”getFrame() returns a chainable frame locator that supports the same locator family.
const frame = await view.getFrame("iframe#payment-frame");if (!frame) throw new Error("payment frame not found");
const cardNumber = await frame.getByLabel("Card number", { exact: true });const payNow = await frame.getByRole("button", { name: "Pay now", exact: true });
if (!cardNumber || !payNow) throw new Error("payment controls not found");
await view.click(cardNumber);await view.type("4242 4242 4242 4242", { perCharacterDelayMs: 0 });await view.click(payNow);Use getFrameElement() when you specifically need an ElementHandle for low-level handle-scoped work.
Shadow DOM traversal
Section titled “Shadow DOM traversal”Open shadow roots are traversed by the locator engine automatically.
const openMenu = await view.getByRole("button", { name: "Open menu", exact: true });const shadowItem = await view.getByText("Shadow menu item", { exact: true });
if (!openMenu || !shadowItem) throw new Error("shadow controls not found");
await view.click(openMenu);await view.click(shadowItem);Matching behavior tips
Section titled “Matching behavior tips”- Use
{ exact: true }for strict, deterministic checks. - Use partial text matching (
exact: falseor omitted) for flexible content. - Prefer role and label locators for UI actions.
- Use data attributes for test-only hooks.
- Use XPath when CSS and semantic locators are awkward.