A Bit About Selectors
Selectors in Playwright are a powerful tool for picking out elements on a web page. They allow you to identify elements by their type, attributes, content, or a combination of these. Here's an example of how you might use a CSS selector:
import { test, expect } from '@playwright/test';
test('Check button with CSS selector', async ({ page }) => {
await page.goto('https://ray.run/');
const button = await page.$('css=button');
// You can now interact with the button
});
However, it's important to note that the use of selectors in this way has been deprecated in recent versions of Playwright. Selectors do not wait for the element to pass actionability checks, which can lead to flaky tests. So, while you'll still see selectors used in this way in some older Playwright code, it's recommended to use locators or web-first assertions instead.
The Power of Locators
Enter locators, a recent addition to Playwright. A locator represents a specific element (or a collection of elements) on a page, and encapsulates the logic to retrieve that element. The beauty of locators is in their resilience against page changes. Here's how you might use a locator:
import { test, expect } from '@playwright/test';
test('Check button with Locator', async ({ page }) => {
await page.goto('https://ray.run/');
const button = page.locator('button');
// You can now interact with the button
});
Spotting the Difference
So, how do selectors and locators differ?
Selectors are essentially search queries used to select elements on the page. They're strings that represent the "where" in finding an element.
In contrast, locators are more of the "what". They are objects that hold onto the search query (the selector) and provide methods to perform actions on the elements, like clicking or typing.
When to Choose What?
While the deprecation of selectors in some contexts might make it seem like locators are always the better choice, there can still be cases where a simple selector query could be suitable. However, if you need to interact with an element in multiple ways, or you want your tests to be more resilient against changes in the page, locators are the way to go. They encapsulate the retrieval logic, resulting in cleaner, less flaky tests.
Here's an example showcasing the resilience provided by locators:
import { test, expect } from '@playwright/test';
test('Check button with Locator', async ({ page }) => {
await page.goto('https://ray.run/');
const button = page.locator('button');
// You can interact with the button multiple times,
// and Playwright will re-find the button each time.
await button.click();
await expect(button).toHaveText('Clicked!');
});
In conclusion, while selectors and locators both hold importance in your Playwright toolbox, understanding their differences and appropriate usage will help you write cleaner, more reliable tests.