diff --git a/packages/playwright-core/src/server/injected/selectorGenerator.ts b/packages/playwright-core/src/server/injected/selectorGenerator.ts index 93d5e0ba70..6df906d36a 100644 --- a/packages/playwright-core/src/server/injected/selectorGenerator.ts +++ b/packages/playwright-core/src/server/injected/selectorGenerator.ts @@ -260,7 +260,7 @@ function cssFallback(injectedScript: InjectedScript, targetElement: Element, str // Combine class names until unique. const classes = [...element.classList]; for (let i = 0; i < classes.length; ++i) { - const token = '.' + classes.slice(0, i + 1).join('.'); + const token = '.' + cssEscape(classes.slice(0, i + 1).join('.')); const selector = uniqueCSSSelector(token); if (selector) return makeStrict(selector); diff --git a/tests/page/page-strict.spec.ts b/tests/page/page-strict.spec.ts index 816b83d4a1..99c3b08674 100644 --- a/tests/page/page-strict.spec.ts +++ b/tests/page/page-strict.spec.ts @@ -83,3 +83,25 @@ it('should properly format :nth-child() in strict mode message', async ({ page } // if '>' were ' '. expect(error.message).toContain('body > div:nth-child(2) > div:nth-child(2)'); }); + +it('should escape class names', async ({ page }) => { + await page.setContent(` +
+
+
+
+
+
+
+
+
+
+
+
+
+ `); + const error = await page.locator('.foo').hover().catch(e => e); + expect(error.message).toContain('strict mode violation'); + expect(error.message).toContain('