diff --git a/packages/playwright-core/src/utils/isomorphic/stringUtils.ts b/packages/playwright-core/src/utils/isomorphic/stringUtils.ts
index 91fb7b82b2..07d1544853 100644
--- a/packages/playwright-core/src/utils/isomorphic/stringUtils.ts
+++ b/packages/playwright-core/src/utils/isomorphic/stringUtils.ts
@@ -78,5 +78,5 @@ export function escapeForAttributeSelector(value: string, exact: boolean): strin
// cssEscape(value).replace(/\\ /g, ' ')
// However, our attribute selectors do not conform to CSS parsing spec,
// so we escape them differently.
- return `"${value.replace(/["]/g, '\\"')}"${exact ? 's' : 'i'}`;
+ return `"${value.replace(/\\/g, '\\\\').replace(/["]/g, '\\"')}"${exact ? 's' : 'i'}`;
}
diff --git a/tests/page/selectors-get-by.spec.ts b/tests/page/selectors-get-by.spec.ts
index 4ff4d3ed37..d8ec170f55 100644
--- a/tests/page/selectors-get-by.spec.ts
+++ b/tests/page/selectors-get-by.spec.ts
@@ -192,6 +192,13 @@ world`);
await expect(page.getByPlaceholder('hello my\nworld')).toHaveAttribute('id', 'control');
await expect(page.getByAltText('hello my\nworld')).toHaveAttribute('id', 'control');
await expect(page.getByTitle('hello my\nworld')).toHaveAttribute('id', 'control');
+
+ await page.setContent(`
Text here
`);
+ await expect.soft(page.getByTitle('my title', { exact: true })).toHaveCount(1, { timeout: 500 });
+ await expect.soft(page.getByTitle('my t\itle', { exact: true })).toHaveCount(1, { timeout: 500 });
+ await expect.soft(page.getByTitle('my t\\itle', { exact: true })).toHaveCount(0, { timeout: 500 });
+ await expect.soft(page.getByTitle('my t\\\itle', { exact: true })).toHaveCount(0, { timeout: 500 });
+ await expect.soft(page.getByTitle('my t\\\\itle', { exact: true })).toHaveCount(0, { timeout: 500 });
});
it('getByRole escaping', async ({ page }) => {
@@ -225,4 +232,17 @@ it('getByRole escaping', async ({ page }) => {
expect.soft(await page.getByRole('link', { name: ' he \n llo 56 ', exact: true }).evaluateAll(els => els.map(e => e.outerHTML))).toEqual([
`he llo 56`,
]);
+
+ expect.soft(await page.getByRole('button', { name: 'Click me', exact: true }).evaluateAll(els => els.map(e => e.outerHTML))).toEqual([
+ ``,
+ ]);
+ expect.soft(await page.getByRole('button', { name: 'Click \me', exact: true }).evaluateAll(els => els.map(e => e.outerHTML))).toEqual([
+ ``,
+ ]);
+ expect.soft(await page.getByRole('button', { name: 'Click \\me', exact: true }).evaluateAll(els => els.map(e => e.outerHTML))).toEqual([
+ ]);
+ expect.soft(await page.getByRole('button', { name: 'Click \\\me', exact: true }).evaluateAll(els => els.map(e => e.outerHTML))).toEqual([
+ ]);
+ expect.soft(await page.getByRole('button', { name: 'Click \\\\me', exact: true }).evaluateAll(els => els.map(e => e.outerHTML))).toEqual([
+ ]);
});