diff --git a/src/injected/cssSelectorEngine.ts b/src/injected/cssSelectorEngine.ts index de173bfcf1..2dd27eba98 100644 --- a/src/injected/cssSelectorEngine.ts +++ b/src/injected/cssSelectorEngine.ts @@ -221,7 +221,6 @@ function split(selector: string): string[][] { let quote: string | undefined; let insideAttr = false; let start = 0; - let space: 'none' | 'before' | 'after' = 'none'; const result: string[][] = []; let current: string[] = []; const appendToCurrent = () => { @@ -234,24 +233,23 @@ function split(selector: string): string[][] { result.push(current); current = []; }; + const isCombinator = (char: string) => { + return char === '>' || char === '+' || char === '~'; + }; + const peekForward = () => { + return selector.substring(index).trim()[0]; + }; + const peekBackward = () => { + const s = selector.substring(0, index).trim(); + return s[s.length - 1]; + }; while (index < selector.length) { const c = selector[index]; - if (!quote && !insideAttr && c === ' ') { - if (space === 'none' || space === 'before') - space = 'before'; + if (!quote && !insideAttr && c === ' ' && !isCombinator(peekForward()) && !isCombinator(peekBackward())) { + appendToCurrent(); + start = index; index++; } else { - if (space === 'before') { - if (c === '>' || c === '+' || c === '~') { - space = 'after'; - } else { - appendToCurrent(); - start = index; - space = 'none'; - } - } else { - space = 'none'; - } if (c === '\\' && index + 1 < selector.length) { index += 2; } else if (c === quote) { diff --git a/test/queryselector.spec.js b/test/queryselector.spec.js index f73dedddf2..3fd646de25 100644 --- a/test/queryselector.spec.js +++ b/test/queryselector.spec.js @@ -662,6 +662,24 @@ describe('css selector', () => { expect(await root3.$(`css:light=[attr*="value"]`)).toBe(null); }); + it('should work with > combinator and spaces', async({page, server}) => { + await page.setContent(`
`); + expect(await page.$eval(`div[foo="bar"] > span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"]> span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"] >span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"]>span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"] > span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"]> span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"] >span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"][bar="baz"] > span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"][bar="baz"]> span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"][bar="baz"] >span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"][bar="baz"]>span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"][bar="baz"] > span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"][bar="baz"]> span`, e => e.outerHTML)).toBe(``); + expect(await page.$eval(`div[foo="bar"][bar="baz"] >span`, e => e.outerHTML)).toBe(``); + }); + it('should work with comma separated list', async({page, server}) => { await page.goto(server.PREFIX + '/deep-shadow.html'); expect(await page.$$eval(`css=span,section #root1`, els => els.length)).toBe(5);