diff --git a/packages/playwright-core/src/utils/isomorphic/cssParser.ts b/packages/playwright-core/src/utils/isomorphic/cssParser.ts index 58d4df243b..9a791a1da4 100644 --- a/packages/playwright-core/src/utils/isomorphic/cssParser.ts +++ b/packages/playwright-core/src/utils/isomorphic/cssParser.ts @@ -43,7 +43,7 @@ export function parseCSS(selector: string, customNames: Set): { selector if (!(tokens[tokens.length - 1] instanceof css.EOFToken)) tokens.push(new css.EOFToken()); } catch (e) { - const newMessage = e.message + ` while parsing selector "${selector}"`; + const newMessage = e.message + ` while parsing css selector "${selector}". Did you mean to CSS.escape it?`; const index = (e.stack || '').indexOf(e.message); if (index !== -1) e.stack = e.stack.substring(0, index) + newMessage + e.stack.substring(index + e.message.length); @@ -68,13 +68,13 @@ export function parseCSS(selector: string, customNames: Set): { selector (token instanceof css.PercentageToken); }); if (unsupportedToken) - throw new InvalidSelectorError(`Unsupported token "${unsupportedToken.toSource()}" while parsing selector "${selector}"`); + throw new InvalidSelectorError(`Unsupported token "${unsupportedToken.toSource()}" while parsing css selector "${selector}". Did you mean to CSS.escape it?`); let pos = 0; const names = new Set(); function unexpected() { - return new InvalidSelectorError(`Unexpected token "${tokens[pos].toSource()}" while parsing selector "${selector}"`); + return new InvalidSelectorError(`Unexpected token "${tokens[pos].toSource()}" while parsing css selector "${selector}". Did you mean to CSS.escape it?`); } function skipWhitespace() { @@ -246,7 +246,7 @@ export function parseCSS(selector: string, customNames: Set): { selector if (!isEOF()) throw unexpected(); if (result.some(arg => typeof arg !== 'object' || !('simples' in arg))) - throw new InvalidSelectorError(`Error while parsing selector "${selector}"`); + throw new InvalidSelectorError(`Error while parsing css selector "${selector}". Did you mean to CSS.escape it?`); return { selector: result as CSSComplexSelector[], names: Array.from(names) }; } diff --git a/tests/library/css-parser.spec.ts b/tests/library/css-parser.spec.ts index 3bf8a742e6..e6ff046579 100644 --- a/tests/library/css-parser.spec.ts +++ b/tests/library/css-parser.spec.ts @@ -77,7 +77,8 @@ it('should throw on malformed css', async () => { } catch (e) { error = e; } - expect(error.message).toContain(`while parsing selector "${selector}"`); + expect(error.message).toContain(`while parsing css selector "${selector}"`); + expect(error.message).toContain(`Did you mean to CSS.escape it?`); } expectError(''); diff --git a/tests/page/expect-boolean.spec.ts b/tests/page/expect-boolean.spec.ts index 49b06b7747..d5b4c4d3b5 100644 --- a/tests/page/expect-boolean.spec.ts +++ b/tests/page/expect-boolean.spec.ts @@ -479,7 +479,7 @@ test('should print unknown engine error', async ({ page }) => { test('should print selector syntax error', async ({ page }) => { const error = await expect(page.locator('row]')).toBeVisible().catch(e => e); - expect(error.message).toContain(`Unexpected token "]" while parsing selector "row]"`); + expect(error.message).toContain(`Unexpected token "]" while parsing css selector "row]"`); }); test.describe(() => { diff --git a/tests/page/selectors-misc.spec.ts b/tests/page/selectors-misc.spec.ts index 605ff6c5a0..f656e9d512 100644 --- a/tests/page/selectors-misc.spec.ts +++ b/tests/page/selectors-misc.spec.ts @@ -415,7 +415,7 @@ it('should work with internal:has=', async ({ page, server }) => { const error3 = await page.$(`div >> internal:has=33`).catch(e => e); expect(error3.message).toContain('Malformed selector: internal:has=33'); const error4 = await page.$(`div >> internal:has="span!"`).catch(e => e); - expect(error4.message).toContain('Unexpected token "!" while parsing selector "span!"'); + expect(error4.message).toContain('Unexpected token "!" while parsing css selector "span!"'); }); it('should work with internal:has-not=', async ({ page }) => {