← Back to microsoft/playwright
microsoft / playwright · Issue No. 42813
1.64.0-next (main @ 07f1a6154); long-standing
import { test, expect } from '@playwright/test';
test('regex with g flag', async ({ page }) => {
await page.setContent(`
<div>foo</div><div>foo</div><div>foo</div>
<label>foo<input></label><label>foo<input></label><label>foo<input></label>
`);
console.log(await page.getByText(/foo/).count()); // 6
console.log(await page.getByText(/foo/g).count()); // 4
console.log(await page.getByLabel(/foo/g).count()); // 2
console.log(await page.getByText(/foo/y).count()); // 4
});
The g and y flags have no meaning for a locator match, so /foo/g should match the same elements as /foo/. getByRole('button', { name: /foo/g }) and filter({ hasText: /foo/g }) already behave that way.
Every other matching element is skipped, depending on traversal order:
6
4
2
4
createTextMatcher in packages/injected/src/injectedScript.ts builds one RegExp and reuses re.test(elementText.full) for every element. RegExp.prototype.test is stateful when the g or y flag is set: lastIndex advances after a hit and only resets after a miss, so the next element is tested from a non-zero offset. escapeRegexForSelector passes user flags through verbatim and the selector parser accepts [dgimsuvy], so the flag reaches the engine.
Role-name matching uses String.prototype.match and has-text builds a fresh RegExp per element, which is why those are unaffected and the inconsistency is confusing. Copying a /pattern/g regex from String.replace code into getByText is an easy habit; the result is a silently wrong count or a hidden strict-mode violation.
I intend to work on this and will send a PR.
- Operating System: macOS (Darwin 25.6.0)
- Node.js: 24.8.0
- Browser: Chromium (bundled r1246)
- Playwright: main @ 07f1a6154
Relay reads this issue against the repository's contribution signals: the files it is likely to touch, how the maintainers triage work this size, and what the first contribution would exercise.
The full analysis for this issue is still being assembled. Until then, the description above and the thread on GitHub are the most reliable context.