What does strict mode mean for Playwright locators?
Written by Jatin Thacker, Automation Architect · Updated
exact: true or by finding the element inside its card.This answer is one piece of Chapter 9: Locators I: What the User Sees.
- getByRole and the Accessible Name
- getByText, getByLabel, getByPlaceholder, getByTestId
- Strict Mode — One Locator, One Element
Locators are strict: any operation that implies a single target element throws when more than one element matches. That covers actions such as click() and fill(), and single-element assertions such as toBeVisible(). Operations about many elements, such as count() and toHaveCount(), are fine.
Why it exists. Without it, a click on an ambiguous locator would land on whichever element came first, and the test would pass while doing the wrong thing. The error lists every match with a suggested locator for each, which is often the quickest fix.
A common cause is a name that is part of another name. By default getByRole('heading', { name: 'Halcyon Burr Grinder' }) matches the name as a case-insensitive substring, so it finds both 'Halcyon Burr Grinder' and 'Halcyon Burr Grinder Mini'.
The fixes, best first:
- Say exactly which one:
{ name: 'Halcyon Burr Grinder', exact: true }. - Find the container, then act inside it: filter the product cards by that exact heading and click the card's own 'Add to cart' button.
- Use
.first()or.nth()only when position really is the requirement, such as 'the newest row'. Otherwise the test quietly picks a different element when the order changes.
import { test, expect } from '@playwright/test';
test('strict mode: one element, or an error', async ({ page }) => {
await page.goto('/catalog.html?mock=static&seed=42&autologin=1');
// The name matches as a substring: 'Halcyon Burr Grinder' and 'Halcyon Burr Grinder Mini'
const grinder = page.getByRole('heading', { name: 'Halcyon Burr Grinder' });
await expect(grinder.click()).rejects.toThrow(/strict mode violation/);
await expect(expect(grinder).toBeVisible()).rejects.toThrow(/strict mode violation/);
await expect(grinder).toHaveCount(2);
// Fix 1: say exactly which one
await expect(page.getByRole('heading', { name: 'Halcyon Burr Grinder', exact: true })).toBeVisible();
// Fix 2: find the card, then act inside it
const card = page.getByTestId('product-card')
.filter({ has: page.getByRole('heading', { name: 'Halcyon Burr Grinder', exact: true }) });
await card.getByRole('button', { name: 'Add to cart' }).click();
await expect(page.getByTestId('cart-row')).toHaveCount(1);
});$ npx playwright test strict.spec.js
ok 1 [chromium] › strict.spec.js:3:1 › strict mode: one element, or an error (1.3s)
1 passed (2.5s)
# The unscoped click on its own fails like this:
Error: locator.click: Error: strict mode violation: getByRole('heading', { name: 'Halcyon Burr Grinder' }) resolved to 2 elements:
1) <h3>Halcyon Burr Grinder</h3> aka getByRole('heading', { name: 'Halcyon Burr Grinder', exact: true })
2) <h3>Halcyon Burr Grinder Mini</h3> aka getByRole('heading', { name: 'Halcyon Burr Grinder Mini' })await page.getByRole('button', { name: 'Delete' }).click()?Practised in the full course: the drill View details — North.
See the chapterRelated questions
AI can write the test now. The job is knowing whether it checks anything. That's what the course teaches, one chapter at a time.
163 lessons · 226 drills · start free