Without showing your document structure, we can only guess what'd be better. The structural context matters greatly. Often, a parent container is necessary to disambiguate similar children.
If the buttons have different text, aria labels or titles, you can select on that. If they have different parent containers, you could filter on those first using chained locators.
You can also let Playwright can choose the best locator with its test generator.
The reason XPath and CSS selectors are considered "last resort" is because they tend to be too closely coupled to implementation details like document structure and styling-oriented classes that don't reflect how the user engages with the app.
This warning applies as much to CSS selectors as XPath, but XPath in particular tends to result in highly brittle tests due to its tendency to be very precise about structure and properties.
Other discouraged patterns include over-reliance on nth and test ids. As a rule of thumb, you want to be the right kind of precise ("button with text 'Learn more'"), but not precise in the wrong way ("4th child of the first child of the 6th child of the 2nd paragraph nested within...."). Try to determine what characteristics make an element unique in a way that isn't likely to change other than due to a meaningful adjustment, preferably something that a user might notice.
See the docs for further details:
XPath and CSS selectors can be tied to the DOM structure or implementation. These selectors can break when the DOM structure changes. Long CSS or XPath chains below are an example of a bad practice that leads to unstable tests:
await page.locator( '#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > > input' ).click();await page .locator('//*[@id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input') .click();
I also caution against the "long selector chains" pattern in my Puppeteer antipatterns blog post (similar framework). If you do use CSS or XPath, try to avoid >, n-th and [class="something-too-specific"] and only use the bare number of ancestor containers necessary to disambiguate the element.
React Testing Library follows a similar "don't test implementation details" philosophy which has swept through the React world in the past few years and surely influenced Playwright.
Answer from ggorlen on Stack OverflowVideos
Without showing your document structure, we can only guess what'd be better. The structural context matters greatly. Often, a parent container is necessary to disambiguate similar children.
If the buttons have different text, aria labels or titles, you can select on that. If they have different parent containers, you could filter on those first using chained locators.
You can also let Playwright can choose the best locator with its test generator.
The reason XPath and CSS selectors are considered "last resort" is because they tend to be too closely coupled to implementation details like document structure and styling-oriented classes that don't reflect how the user engages with the app.
This warning applies as much to CSS selectors as XPath, but XPath in particular tends to result in highly brittle tests due to its tendency to be very precise about structure and properties.
Other discouraged patterns include over-reliance on nth and test ids. As a rule of thumb, you want to be the right kind of precise ("button with text 'Learn more'"), but not precise in the wrong way ("4th child of the first child of the 6th child of the 2nd paragraph nested within...."). Try to determine what characteristics make an element unique in a way that isn't likely to change other than due to a meaningful adjustment, preferably something that a user might notice.
See the docs for further details:
XPath and CSS selectors can be tied to the DOM structure or implementation. These selectors can break when the DOM structure changes. Long CSS or XPath chains below are an example of a bad practice that leads to unstable tests:
await page.locator( '#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > > input' ).click();await page .locator('//*[@id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input') .click();
I also caution against the "long selector chains" pattern in my Puppeteer antipatterns blog post (similar framework). If you do use CSS or XPath, try to avoid >, n-th and [class="something-too-specific"] and only use the bare number of ancestor containers necessary to disambiguate the element.
React Testing Library follows a similar "don't test implementation details" philosophy which has swept through the React world in the past few years and surely influenced Playwright.
XPath are not recommended as the DOM can often change leading to non resilient tests. You can get those buttons by their class
await page.locator("//div[@class='mui-primary']")
If you have no option then you can use xpath.