Top 50 Playwright Locator Interview Questions and Answers

Playwright locators are one of the most important interview topics for QA Automation Engineers, SDETs, and Test Automation Engineers. Interviewers frequently ask questions about locator strategies, best practices, auto-waiting, strict mode, and advanced locator chaining.


1. What is a Locator in Playwright?

Answer:

A locator is an object that identifies and interacts with elements on a web page. Unlike traditional selectors, Playwright locators automatically wait for elements to become available before performing actions.

Example

const loginButton = page.locator('#login');

await loginButton.click();

2. Why are Playwright Locators better than CSS or XPath?

Answer:

Playwright locators provide:

  • Auto-waiting
  • Retry mechanism
  • Better readability
  • Improved stability
  • Built-in strict mode
  • Better handling of dynamic pages

3. What is the difference between page.locator() and page.$()?

Answer:

page.locator()page.$()
Auto waitsNo auto wait
RecommendedDeprecated for most use cases
Supports retriesReturns immediately
Better stabilityMore flaky

Example:

await page.locator('#submit').click();

4. What is Strict Mode in Playwright?

Answer:

Strict mode ensures a locator resolves to exactly one element.

If multiple elements match, Playwright throws an error.

Example

await page.locator('button').click();

Error:

Strict mode violation:
Locator resolved to 5 elements.

5. How do you disable Strict Mode?

Answer:

Use methods like:

.first()

.last()

.nth(index)

Example

await page.locator('button').first().click();

6. Explain page.locator().

Answer:

Creates a reusable locator.

const username = page.locator('#username');

await username.fill('Admin');

7. What is getByRole()?

Answer:

Locates elements using their ARIA role.

Example

await page.getByRole('button', {
    name: 'Login'
}).click();

Recommended because it mimics user interaction.


8. Why is getByRole() preferred?

Answer:

  • Accessibility friendly
  • Stable
  • Less affected by UI changes
  • Easy to understand

9. What is getByText()?

Answer:

Finds elements using visible text.

await page.getByText('Sign In').click();

10. Difference between locator('text=Login') and getByText()?

Answer:

getByText() is more readable and recommended.

page.getByText('Login');

instead of

page.locator('text=Login');

11. What is getByLabel()?

Answer:

Locates form fields using associated labels.

await page.getByLabel('Username')
.fill('Admin');

12. What is getByPlaceholder()?

Answer:

Finds input elements using placeholder text.

await page
.getByPlaceholder('Search')
.fill('Laptop');

13. What is getByAltText()?

Answer:

Used for images.

page.getByAltText('Company Logo');

14. What is getByTitle()?

Answer:

Finds elements using the title attribute.

page.getByTitle('Settings');

15. What is getByTestId()?

Answer:

Locates elements using the data-testid attribute.

<button data-testid="login-btn">
page.getByTestId('login-btn');

16. Why is data-testid recommended?

Answer:

  • Independent of UI
  • Stable
  • Easy to maintain
  • Designed for automation

17. What is Locator Chaining?

Answer:

Locating elements inside another locator.

page.locator('.card')
.locator('button');

18. What is filter()?

Answer:

Filters locator results.

page.locator('.product')
.filter({
    hasText:'Laptop'
});

19. What is hasText?

Answer:

Filters elements by text.

page.locator('li').filter({
    hasText:'Apple'
});

20. What is has()?

Answer:

Filters elements containing another locator.

page.locator('.card').filter({

    has: page.locator('button')

});

21. What is nth()?

Answer:

Selects the element at a given index (zero-based).

page.locator('li').nth(2);

22. What is first()?

Answer:

Returns the first matching element.

page.locator('button').first();

23. What is last()?

Answer:

Returns the last matching element.

page.locator('button').last();

24. Difference between nth(0) and first()?

Answer:

Both return the first element, but first() is more readable and expressive.


25. How do you count matching elements?

Answer:

const count =
await page.locator('.product').count();

26. How do you loop through multiple elements?

Answer:

const items = page.locator('.product');

const count = await items.count();

for (let i = 0; i < count; i++) {
    console.log(await items.nth(i).textContent());
}

27. How do you get the text of an element?

Answer:

const text =
await page.locator('h1').textContent();

Prefer assertions when verifying text:

await expect(page.locator('h1'))
    .toHaveText('Dashboard');

28. What is allTextContents()?

Answer:

Returns the text content of all matching elements.

const texts =
await page.locator('li').allTextContents();

29. What is allInnerTexts()?

Answer:

Returns the rendered inner text of all matching elements, excluding hidden text in many cases.

const texts =
await page.locator('li').allInnerTexts();

30. Difference between textContent() and innerText()?

Answer:

textContent()innerText()
Includes hidden textReturns visible rendered text
FasterSlower due to layout calculations
Reads DOM textReads displayed text

31. How do you locate using CSS selectors?

Answer:

page.locator('#username');

page.locator('.login');

page.locator('input');

32. Can Playwright use XPath?

Answer:

Yes.

page.locator('//button');

However, CSS selectors and user-facing locators like getByRole() are generally preferred for readability and maintainability.


33. How do you locate a parent element?

Answer:

Use locator chaining or XPath when appropriate.

Example using chaining:

const card = page.locator('.card').filter({
  has: page.getByText('Product A')
});

34. How do you locate child elements?

Answer:

page.locator('.card')
.locator('button');

35. What is Auto Waiting?

Answer:

Playwright automatically waits until the target element is actionable (e.g., attached, visible, stable, and enabled where applicable) before performing actions.

Example:

await page.locator('#login').click();

36. Can Locators be reused?

Answer:

Yes.

const loginButton =
page.getByRole('button', { name: 'Login' });

await loginButton.click();
await expect(loginButton).toBeVisible();

37. Are Locators Lazy?

Answer:

Yes.

A locator does not immediately search the DOM. It resolves the element when an action or assertion is performed, allowing it to work with dynamic pages.


38. Difference between Locator and ElementHandle?

Answer:

LocatorElementHandle
Lazy evaluationSnapshot of a DOM element
Auto waitsNo automatic retries
RecommendedUse only for advanced scenarios
More resilientCan become stale

39. How do you wait for a Locator?

Answer:

Usually you don’t need to wait manually.

If needed:

await page.locator('#login').waitFor();

40. How do you verify a Locator exists?

Answer:

await expect(
page.locator('#login')
).toBeVisible();

41. How do you locate an element inside an iframe?

Answer:

Use frameLocator().

await page
.frameLocator('#payment-frame')
.getByRole('button', { name: 'Pay Now' })
.click();

42. How do you locate shadow DOM elements?

Answer:

Playwright automatically pierces open shadow DOMs, so standard locators often work without extra APIs.

await page.getByRole('button', { name: 'Submit' }).click();

43. What are the best locator strategies in Playwright?

Answer:

Preferred order:

  1. getByRole()
  2. getByLabel()
  3. getByPlaceholder()
  4. getByTestId()
  5. getByText()
  6. CSS selectors
  7. XPath (only when necessary)

44. Why should XPath be avoided when possible?

Answer:

  • More fragile
  • Harder to read
  • Breaks easily after DOM changes
  • Longer and more complex expressions

45. How do you handle dynamic locators?

Answer:

Use template literals.

const productName = 'Laptop';

await page.getByText(productName).click();

Or:

await page.locator(
    `[data-id="${productName}"]`
).click();

46. How do you locate a button with specific text?

Answer:

await page.getByRole('button', {
    name: 'Submit'
}).click();

47. How do you locate multiple buttons with the same text?

Answer:

Use nth(), first(), or last().

await page
.getByRole('button', { name: 'Edit' })
.nth(1)
.click();

48. How do you debug a locator?

Answer:

Useful techniques include:

  • Use Playwright Inspector (--debug)
  • Use page.pause()
  • Use the Playwright Codegen tool
  • Inspect the locator in browser DevTools
  • Verify uniqueness with assertions like toHaveCount(1)

Example:

await page.pause();

49. What are common locator mistakes?

Answer:

  • Using overly generic selectors like div or button
  • Relying on dynamic CSS classes
  • Depending on long XPath expressions
  • Using nth() unnecessarily when a unique locator is available
  • Adding manual waits instead of relying on locator auto-waiting

50. What are the best practices for Playwright locators?

Answer:

  • Prefer user-facing locators such as getByRole() and getByLabel().
  • Use data-testid for elements without stable accessible attributes.
  • Create reusable locators in Page Object Model classes.
  • Avoid brittle XPath and deeply nested CSS selectors.
  • Keep locators unique and descriptive.
  • Use Playwright assertions (toBeVisible(), toHaveText(), etc.) instead of manual checks.
  • Take advantage of locator chaining and filter() to make selectors more precise.
  • Write locators that reflect user behavior rather than implementation details.

Bonus Interview Question

What is the recommended locator priority in Playwright?

Answer:

The Playwright team recommends choosing locators in roughly this order:

  1. getByRole() – Best for accessibility and user-centric testing.
  2. getByLabel() – Ideal for form controls.
  3. getByPlaceholder() – Useful for inputs with meaningful placeholders.
  4. getByTestId() – Great for stable automation-specific selectors.
  5. getByText() – Suitable for visible text when it uniquely identifies the element.
  6. CSS selectors – Use when semantic locators are unavailable.
  7. XPath – Reserve for cases where no better locator strategy is feasible.

Following this hierarchy produces tests that are more readable, accessible, and resilient to UI changes.

Leave a Comment