Skip to content

Commit 8218a71

Browse files
authored
feat(selectors): add more tests for css selectors (#4596)
1 parent cdbc96a commit 8218a71

File tree

2 files changed

+67
-6
lines changed

2 files changed

+67
-6
lines changed

src/server/injected/selectorEvaluator.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ const hasEngine: SelectorEngine = {
289289
return evaluator.query({ ...context, scope: element }, args).length > 0;
290290
},
291291

292+
// TODO: we do not implement "relative selectors", as in "div:has(> span)" or "div:has(+ span)".
293+
292294
// TODO: we can implement efficient "query" by matching "args" and returning
293295
// all parents/descendants, just have to be careful with the ":scope" matching.
294296
};

test/selectors-css.spec.ts

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,53 @@ it('should work with numerical id', async ({page, server}) => {
135135
expect(element).toBeTruthy();
136136
});
137137

138+
it('should work with wrong-case id', async ({page}) => {
139+
await page.setContent('<section id="Hello"></section>');
140+
expect(await page.$eval('#Hello', e => e.tagName)).toBe('SECTION');
141+
expect(await page.$eval('#hello', e => e.tagName)).toBe('SECTION');
142+
expect(await page.$eval('#HELLO', e => e.tagName)).toBe('SECTION');
143+
expect(await page.$eval('#helLO', e => e.tagName)).toBe('SECTION');
144+
});
145+
146+
it('should work with *', async ({page}) => {
147+
await page.setContent('<div id=div1></div><div id=div2><span><span></span></span></div>');
148+
// Includes html, head and body.
149+
expect(await page.$$eval('*', els => els.length)).toBe(7);
150+
expect(await page.$$eval('*#div1', els => els.length)).toBe(1);
151+
expect(await page.$$eval('*:not(#div1)', els => els.length)).toBe(6);
152+
expect(await page.$$eval('*:not(div)', els => els.length)).toBe(5);
153+
expect(await page.$$eval('*:not(span)', els => els.length)).toBe(5);
154+
expect(await page.$$eval('*:not(*)', els => els.length)).toBe(0);
155+
expect(await page.$$eval('*:is(*)', els => els.length)).toBe(7);
156+
expect(await page.$$eval('* *', els => els.length)).toBe(6);
157+
expect(await page.$$eval('* *:not(span)', els => els.length)).toBe(4);
158+
expect(await page.$$eval('div > *', els => els.length)).toBe(1);
159+
expect(await page.$$eval('div *', els => els.length)).toBe(2);
160+
expect(await page.$$eval('* > *', els => els.length)).toBe(6);
161+
162+
const body = await page.$('body');
163+
// Does not include html, head or body.
164+
expect(await body.$$eval('*', els => els.length)).toBe(4);
165+
expect(await body.$$eval('*#div1', els => els.length)).toBe(1);
166+
expect(await body.$$eval('*:not(#div1)', els => els.length)).toBe(3);
167+
expect(await body.$$eval('*:not(div)', els => els.length)).toBe(2);
168+
expect(await body.$$eval('*:not(span)', els => els.length)).toBe(2);
169+
expect(await body.$$eval('*:not(*)', els => els.length)).toBe(0);
170+
expect(await body.$$eval('*:is(*)', els => els.length)).toBe(4);
171+
expect(await body.$$eval('div > *', els => els.length)).toBe(1);
172+
expect(await body.$$eval('div *', els => els.length)).toBe(2);
173+
// Selectors v2 matches jquery in the sense that matching starts with the element scope,
174+
// not the document scope.
175+
expect(await body.$$eval('* > *', els => els.length)).toBe(selectorsV2Enabled() ? 2 : 4);
176+
// Adding scope makes querySelectorAll work like jquery.
177+
expect(await body.$$eval(':scope * > *', els => els.length)).toBe(2);
178+
// Note that the following two selectors are following jquery logic even
179+
// with selectors v1. Just running `body.querySelectorAll` returns 4 and 2 respectively.
180+
// That's probably a bug in v1, but oh well.
181+
expect(await body.$$eval('* *', els => els.length)).toBe(2);
182+
expect(await body.$$eval('* *:not(span)', els => els.length)).toBe(0);
183+
});
184+
138185
it('should work with :nth-child', async ({page, server}) => {
139186
await page.goto(server.PREFIX + '/deep-shadow.html');
140187
expect(await page.$$eval(`css=span:nth-child(odd)`, els => els.length)).toBe(3);
@@ -176,12 +223,14 @@ it('should work with ~', async ({page}) => {
176223

177224
it('should work with +', async ({page}) => {
178225
await page.setContent(`
179-
<div id=div1></div>
180-
<div id=div2></div>
181-
<div id=div3></div>
182-
<div id=div4></div>
183-
<div id=div5></div>
184-
<div id=div6></div>
226+
<section>
227+
<div id=div1></div>
228+
<div id=div2></div>
229+
<div id=div3></div>
230+
<div id=div4></div>
231+
<div id=div5></div>
232+
<div id=div6></div>
233+
</section>
185234
`);
186235
expect(await page.$$eval(`css=#div1 ~ div + #div6`, els => els.length)).toBe(1);
187236
expect(await page.$$eval(`css=#div1 ~ div + div`, els => els.length)).toBe(4);
@@ -190,6 +239,16 @@ it('should work with +', async ({page}) => {
190239
expect(await page.$$eval(`css=#div5 + div + div`, els => els.length)).toBe(0);
191240
expect(await page.$$eval(`css=#div3 ~ #div2 + #div6`, els => els.length)).toBe(0);
192241
expect(await page.$$eval(`css=#div3 + #div4 + #div5`, els => els.length)).toBe(1);
242+
expect(await page.$$eval(`css=div + #div1`, els => els.length)).toBe(0);
243+
expect(await page.$$eval(`css=section > div + div ~ div`, els => els.length)).toBe(4);
244+
expect(await page.$$eval(`css=section > div + #div4 ~ div`, els => els.length)).toBe(2);
245+
if (selectorsV2Enabled()) {
246+
// Selectors v1 do not support this.
247+
expect(await page.$$eval(`css=section:has(:scope > div + #div2)`, els => els.length)).toBe(1);
248+
expect(await page.$$eval(`css=section:has(:scope > div + #div1)`, els => els.length)).toBe(0);
249+
}
250+
// TODO: the following does not work. Should it?
251+
// expect(await page.$eval(`css=div:has(:scope + #div5)`, e => e.id)).toBe('div4');
193252
});
194253

195254
it('should work with spaces in :nth-child and :not', async ({page, server}) => {

0 commit comments

Comments
 (0)