Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: test/browser/elemHideEmulation.js

Issue 29383960: Issue 3143 - Filter elements with :-abp-has() (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore
Patch Set: Revised patch Created June 8, 2017, 3:45 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/content/elemHideEmulation.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2017 eyeo GmbH 3 * Copyright (C) 2006-2017 eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 "use strict"; 18 "use strict";
19 19
20 /* globals ElemHideEmulation */ 20 /* globals ElemHideEmulation, splitSelector,
21 parseSelectorContent,
22 parseSelector, positionInParent, makeSelector,
23 PlainSelector, HasSelector, PropsSelector */
21 24
22 let myUrl = document.currentScript.src; 25 let myUrl = document.currentScript.src;
23 26
24 exports.tearDown = function(callback) 27 exports.tearDown = function(callback)
25 { 28 {
26 let styleElements = document.head.getElementsByTagName("style"); 29 let styleElements = document.head.getElementsByTagName("style");
27 while (styleElements.length) 30 while (styleElements.length)
28 styleElements[0].parentNode.removeChild(styleElements[0]); 31 styleElements[0].parentNode.removeChild(styleElements[0]);
32
33 let child;
34 while (child = document.body.firstChild)
35 child.parentNode.removeChild(child);
36
29 callback(); 37 callback();
30 }; 38 };
31 39
32 function unexpectedError(error) 40 function unexpectedError(error)
33 { 41 {
34 console.error(error); 42 console.error(error);
35 this.ok(false, "Unexpected error: " + error); 43 this.ok(false, "Unexpected error: " + error);
36 } 44 }
37 45
38 function expectHidden(test, element) 46 function expectHidden(test, element)
(...skipping 23 matching lines...) Expand all
62 if (styleElements.length) 70 if (styleElements.length)
63 styleElement = styleElements[0]; 71 styleElement = styleElements[0];
64 else 72 else
65 { 73 {
66 styleElement = document.createElement("style"); 74 styleElement = document.createElement("style");
67 document.head.appendChild(styleElement); 75 document.head.appendChild(styleElement);
68 } 76 }
69 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); 77 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length);
70 } 78 }
71 79
72 function createElementWithStyle(styleBlock) 80 // insert a <div> with a unique id and a CSS rule
81 // for the the selector matching the id.
82 function createElementWithStyle(styleBlock, parent)
73 { 83 {
74 let element = document.createElement("div"); 84 let element = document.createElement("div");
75 element.id = findUniqueId(); 85 element.id = findUniqueId();
76 document.body.appendChild(element); 86 if (!parent)
87 document.body.appendChild(element);
88 else
89 parent.appendChild(element);
77 insertStyleRule("#" + element.id + " " + styleBlock); 90 insertStyleRule("#" + element.id + " " + styleBlock);
78 return element; 91 return element;
79 } 92 }
80 93
81 function applyElemHideEmulation(selectors) 94 // Will ensure the class ElemHideEmulation is loaded.
95 // NOTE: if it never loads, this will probably hang.
96 function loadElemHideEmulation()
82 { 97 {
83 if (typeof ElemHideEmulation == "undefined") 98 if (typeof ElemHideEmulation == "undefined")
84 { 99 {
85 return loadScript(myUrl + "/../../../lib/common.js").then(() => 100 return loadScript(myUrl + "/../../../lib/common.js").then(() =>
86 { 101 {
87 return loadScript(myUrl + "/../../../chrome/content/elemHideEmulation.js") ; 102 return loadScript(myUrl + "/../../../chrome/content/elemHideEmulation.js") ;
88 }).then(() => 103 }).then(() =>
89 { 104 {
90 return applyElemHideEmulation(selectors); 105 return loadElemHideEmulation();
91 }); 106 });
92 } 107 }
93 108
94 let elemHideEmulation = new ElemHideEmulation( 109 return Promise.resolve();
95 window, 110 }
96 callback => 111
97 { 112 // Create a new ElemHideEmulation instance with @selectors.
98 let patterns = []; 113 function applyElemHideEmulation(selectors)
99 selectors.forEach(selector => 114 {
115 return loadElemHideEmulation().then(() =>
116 {
117 let elemHideEmulation = new ElemHideEmulation(
118 window,
119 callback =>
100 { 120 {
101 patterns.push({selector}); 121 let patterns = [];
102 }); 122 selectors.forEach(selector =>
103 callback(patterns); 123 {
104 }, newSelectors => 124 patterns.push({selector});
105 { 125 });
106 if (!newSelectors.length) 126 callback(patterns);
107 return; 127 },
108 let selector = newSelectors.join(", "); 128 newSelectors =>
109 insertStyleRule(selector + "{display: none !important;}"); 129 {
110 } 130 if (!newSelectors.length)
111 ); 131 return;
112 132 let selector = newSelectors.join(", ");
113 elemHideEmulation.apply(); 133 insertStyleRule(selector + "{display: none !important;}");
114 return Promise.resolve(); 134 },
115 } 135 elems =>
136 {
137 for (let elem of elems)
138 elem.style.display = "none";
139 }
140 );
141
142 elemHideEmulation.apply();
143 return Promise.resolve(elemHideEmulation);
144 });
145 }
146
147 // internals testing
148
149 exports.testParseSelectorContent = function(test)
150 {
151 loadElemHideEmulation().then(() =>
152 {
153 let parsed = parseSelectorContent(":-abp-has(> div) > div", 10);
154 test.equal(parsed.text, "> div");
155 test.equal(parsed.end, 15);
156
157 parsed = parseSelectorContent("> div) > div", 0);
158 test.equal(parsed.text, "> div");
159 test.equal(parsed.end, 5);
160
161 // parens not closed.
162 parsed = parseSelectorContent("> div > div", 0);
163 test.equal(parsed, null);
164 }).catch(unexpectedError.bind(test)).then(() => test.done());
165 };
166
167 exports.testParseSelector = function(test)
168 {
169 loadElemHideEmulation().then(() =>
170 {
171 let selectors = parseSelector("");
172 test.equal(selectors.length, 0);
173
174 let selector = "div > :-abp-properties('background-color: rgb(0, 0, 0)')";
175 selectors = parseSelector(selector);
176 test.equal(selectors.length, 2);
177 test.ok(selectors[0] instanceof PlainSelector);
178 test.ok(selectors[1] instanceof PropsSelector);
179
180 selector = "div > :-abp-has(> div.inside) > div";
181 selectors = parseSelector(selector);
182 test.equal(selectors.length, 3);
183 test.ok(selectors[0] instanceof PlainSelector);
184 test.ok(selectors[1] instanceof HasSelector);
185 test.ok(selectors[2] instanceof PlainSelector);
186
187 selector = "div > div:-abp-has(> div.inside) > div";
188 selectors = parseSelector(selector);
189
190 test.equal(selectors.length, 3);
191 test.ok(selectors[0] instanceof PlainSelector);
192 test.ok(selectors[1] instanceof HasSelector);
193 test.ok(selectors[2] instanceof PlainSelector);
194
195 selector = "div > :-abp-has(> div.inside) > :-abp-properties(background-colo r: rgb(0, 0, 0))";
196 selectors = parseSelector(selector);
197
198 test.equal(selectors.length, 4);
199 test.ok(selectors[0] instanceof PlainSelector);
200 test.ok(selectors[1] instanceof HasSelector);
201 test.ok(selectors[2] instanceof PlainSelector);
202 test.ok(selectors[3] instanceof PropsSelector);
203
204 selector = "div > :-abp-has(> div.inside > :-abp-properties(background-color : rgb(0, 0, 0))";
205 selectors = parseSelector(selector);
206 test.equal(selectors, null);
207
208 // -abp-has-unsupported() is unknown. Ensure we fail parsing.
209 selector = 'div[arial-label="Story"]:-abp-has(> div > div > span > span:-abp -unsupported("Suggested Post"))';
210 selectors = parseSelector(selector);
211 test.equal(selectors, null);
212 }).catch(unexpectedError.bind(test)).then(() => test.done());
213 };
214
215 function buildDom(doc)
216 {
217 doc.body.innerHTML = `<div id="parent">
218 <div id="middle">
219 <div id="middle1"><div id="inside" class="inside"></div></div>
220 </div>
221 <div id="sibling">
222 <div id="tohide">to hide</div>
223 </div>
224 <div id="sibling2">
225 <div id="sibling21"><div id="sibling211" class="inside"></div></div>
226 </div>
227 </div>`;
228 let parent = document.getElementById("parent");
229 let middle = document.getElementById("middle");
230 let middle1 = document.getElementById("middle1");
231 let inside = document.getElementById("inside");
232 let sibling = document.getElementById("sibling");
233 let sibling2 = document.getElementById("sibling2");
234 let toHide = document.getElementById("tohide");
235 return {parent, middle, middle1, inside, sibling, sibling2, toHide};
236 }
237
238 exports.testPositionInParent = function(test)
239 {
240 let nodes = buildDom(document);
241
242 loadElemHideEmulation().then(() =>
243 {
244 test.equal(positionInParent(nodes.middle1), 1);
245 test.equal(positionInParent(nodes.inside), 1);
246 test.equal(positionInParent(nodes.sibling2), 3);
247 }).catch(unexpectedError.bind(test)).then(() => test.done());
248 };
249
250 exports.testMakeSelector = function(test)
251 {
252 let nodes = buildDom(document);
253
254 loadElemHideEmulation().then(() =>
255 {
256 test.equal(makeSelector(nodes.middle, ""),
257 ":root > BODY:nth-child(2) > DIV:nth-child(1) > DIV:nth-child(1)" );
258 test.equal(makeSelector(nodes.toHide, ""),
259 ":root > BODY:nth-child(2) > DIV:nth-child(1) > DIV:nth-child(2) > DIV:nth-child(1)");
260 }).catch(unexpectedError.bind(test)).then(() => test.done());
261 };
262
263 exports.testPlainSelector = function(test)
264 {
265 buildDom(document);
266
267 loadElemHideEmulation().then(() =>
268 {
269 let selector = new PlainSelector("div > div");
270
271 let iter = selector.getSelectors("foo > ");
272 let value = iter.next();
273 test.equal(value.value[0], "foo > div > div");
274 test.ok(iter.next().done);
275 }).catch(unexpectedError.bind(test)).then(() => test.done());
276 };
277
278 exports.testHasSelector = function(test)
279 {
280 buildDom(document);
281
282 loadElemHideEmulation().then(() =>
283 {
284 let selector = new HasSelector("> div.inside");
285
286 let iter = selector.getSelectors("", document, document.sheet);
287 let value = iter.next();
288 test.ok(!value.done);
289 test.equal(value.value[0],
290 ":root > BODY:nth-child(2) > DIV:nth-child(1) > DIV:nth-child(1) > DIV:nth-child(1)");
291
292 iter = selector.getElements("", document, document.sheet);
293 value = iter.next();
294 test.ok(!value.done);
295 test.equal(value.value.id, "middle1");
296 value = iter.next();
297 test.ok(!value.done);
298 test.equal(value.value.id, "sibling21");
299 value = iter.next();
300 test.ok(value.done);
301
302 selector = new HasSelector(":-abp-has(> div.inside)");
303
304 test.ok(selector._innerSelectors);
305 }).catch(unexpectedError.bind(test)).then(() => test.done());
306 };
307
308 exports.testSplitStyleRule = function(test)
309 {
310 loadElemHideEmulation().then(() =>
311 {
312 let selectors = splitSelector("div:-abp-has(div) > [-abp-properties='backgro und-color: rgb(0, 0, 0)'] > span");
313 test.ok(selectors);
314 test.equal(selectors.length, 1, "There is only one selector");
315
316 selectors = splitSelector("div:-abp-has(div), [-abp-properties='background-c olor: rgb(0, 0, 0)']");
317 test.ok(selectors);
318 test.equal(selectors.length, 2, "There are two selectors");
319 }).catch(unexpectedError.bind(test)).then(() => test.done());
320 };
321
322 // API testing
116 323
117 exports.testVerbatimPropertySelector = function(test) 324 exports.testVerbatimPropertySelector = function(test)
118 { 325 {
119 let toHide = createElementWithStyle("{background-color: #000}"); 326 let toHide = createElementWithStyle("{background-color: #000}");
120 applyElemHideEmulation( 327 applyElemHideEmulation(
121 [":-abp-properties(background-color: rgb(0, 0, 0))"] 328 [":-abp-properties(background-color: rgb(0, 0, 0))"]
122 ).then(() => 329 ).then(() =>
123 { 330 {
124 expectHidden(test, toHide); 331 expectHidden(test, toHide);
125 }).catch(unexpectedError.bind(test)).then(() => test.done()); 332 }).catch(unexpectedError.bind(test)).then(() => test.done());
126 }; 333 };
127 334
335 exports.testVerbatimPropertySelectorWithPrefix = function(test)
336 {
337 let parent = createElementWithStyle("{background-color: #000}");
338 let toHide = createElementWithStyle("{background-color: #000}", parent);
339 applyElemHideEmulation(
340 ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]
341 ).then(() =>
342 {
343 expectVisible(test, parent);
344 expectHidden(test, toHide);
345 }).catch(unexpectedError.bind(test)).then(() => test.done());
346 };
347
348 exports.testVerbatimPropertySelectorWithPrefixNoMatch = function(test)
349 {
350 let parent = createElementWithStyle("{background-color: #000}");
351 let toHide = createElementWithStyle("{background-color: #fff}", parent);
352 applyElemHideEmulation(
353 ["div > :-abp-properties(background-color: rgb(0, 0, 0))"]
354 ).then(() =>
355 {
356 expectVisible(test, parent);
357 expectVisible(test, toHide);
358 }).catch(unexpectedError.bind(test)).then(() => test.done());
359 };
360
361 exports.testVerbatimPropertySelectorWithSuffix = function(test)
362 {
363 let parent = createElementWithStyle("{background-color: #000}");
364 let toHide = createElementWithStyle("{background-color: #000}", parent);
365 applyElemHideEmulation(
366 [":-abp-properties(background-color: rgb(0, 0, 0)) > div"]
367 ).then(() =>
368 {
369 expectVisible(test, parent);
370 expectHidden(test, toHide);
371 }).catch(unexpectedError.bind(test)).then(() => test.done());
372 };
373
374 exports.testVerbatimPropertyPseudoSelectorWithPrefixAndSuffix = function(test)
375 {
376 let parent = createElementWithStyle("{background-color: #000}");
377 let middle = createElementWithStyle("{background-color: #000}", parent);
378 let toHide = createElementWithStyle("{background-color: #000}", middle);
379 applyElemHideEmulation(
380 ["div > :-abp-properties(background-color: rgb(0, 0, 0)) > div"]
381 ).then(() =>
382 {
383 expectVisible(test, parent);
384 expectVisible(test, middle);
385 expectHidden(test, toHide);
386 }).catch(unexpectedError.bind(test)).then(() => test.done());
387 };
388
128 exports.testPropertySelectorWithWildcard = function(test) 389 exports.testPropertySelectorWithWildcard = function(test)
129 { 390 {
130 let toHide = createElementWithStyle("{background-color: #000}"); 391 let toHide = createElementWithStyle("{background-color: #000}");
131 applyElemHideEmulation( 392 applyElemHideEmulation(
132 [":-abp-properties(*color: rgb(0, 0, 0))"] 393 [":-abp-properties(*color: rgb(0, 0, 0))"]
133 ).then(() => 394 ).then(() =>
134 { 395 {
135 expectHidden(test, toHide); 396 expectHidden(test, toHide);
136 }).catch(unexpectedError.bind(test)).then(() => test.done()); 397 }).catch(unexpectedError.bind(test)).then(() => test.done());
137 }; 398 };
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 return new Promise((resolve, reject) => 442 return new Promise((resolve, reject) =>
182 { 443 {
183 window.setTimeout(() => 444 window.setTimeout(() =>
184 { 445 {
185 expectHidden(test, toHide); 446 expectHidden(test, toHide);
186 resolve(); 447 resolve();
187 }, 0); 448 }, 0);
188 }); 449 });
189 }).catch(unexpectedError.bind(test)).then(() => test.done()); 450 }).catch(unexpectedError.bind(test)).then(() => test.done());
190 }; 451 };
452
453 exports.testPseudoClassHasSelector = function(test)
454 {
455 let toHide = createElementWithStyle("{}");
456 applyElemHideEmulation(
457 ["div:-abp-has(div)"]
458 ).then(() =>
459 {
460 expectVisible(test, toHide);
461 }).catch(unexpectedError.bind(test)).then(() => test.done());
462 };
463
464 exports.testPseudoClassHasSelectorWithPrefix = function(test)
465 {
466 let parent = createElementWithStyle("{}");
467 let child = createElementWithStyle("{}", parent);
468 applyElemHideEmulation(
469 ["div:-abp-has(div)"]
470 ).then(() =>
471 {
472 expectHidden(test, parent);
473 expectVisible(test, child);
474 }).catch(unexpectedError.bind(test)).then(() => test.done());
475 };
476
477 exports.testPseudoClassHasSelectorWithSuffix = function(test)
478 {
479 let parent = createElementWithStyle("{}");
480 let middle = createElementWithStyle("{}", parent);
481 let child = createElementWithStyle("{}", middle);
482 applyElemHideEmulation(
483 ["div:-abp-has(div) > div"]
484 ).then(() =>
485 {
486 expectVisible(test, parent);
487 expectHidden(test, middle);
488 expectHidden(test, child);
489 }).catch(unexpectedError.bind(test)).then(() => test.done());
490 };
491
492 exports.testPseudoClassHasSelectorWithSuffixSibling = function(test)
493 {
494 let parent = createElementWithStyle("{}");
495 let middle = createElementWithStyle("{}", parent);
496 let toHide = createElementWithStyle("{}");
497 applyElemHideEmulation(
498 ["div:-abp-has(div) + div"]
499 ).then(() =>
500 {
501 expectVisible(test, parent);
502 expectVisible(test, middle);
503 expectHidden(test, toHide);
504 }).catch(unexpectedError.bind(test)).then(() => test.done());
505 };
506
507 exports.testPseudoClassHasSelectorWithSuffixSiblingChild = function(test)
508 {
509 // <div>
510 // <div></div>
511 // <div>
512 // <div>to hide</div>
513 // </div>
514 // </div>
515 let parent = createElementWithStyle("{}");
516 let middle = createElementWithStyle("{}", parent);
517 let sibling = createElementWithStyle("{}");
518 let toHide = createElementWithStyle("{}", sibling);
519 applyElemHideEmulation(
520 ["div:-abp-has(div) + div > div"]
521 ).then(() =>
522 {
523 expectVisible(test, parent);
524 expectVisible(test, middle);
525 expectVisible(test, sibling);
526 expectHidden(test, toHide);
527 }).catch(unexpectedError.bind(test)).then(() => test.done());
528 };
529
530 function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, selector )
531 {
532 document.body.innerHTML = `<div id="parent">
533 <div id="middle">
534 <div id="middle1"><div id="inside" class="inside"></div></div>
535 </div>
536 <div id="sibling">
537 <div id="tohide">to hide</div>
538 </div>
539 <div id="sibling2">
540 <div id="sibling21"><div id="sibling211" class="inside"></div></div>
541 </div>
542 </div>`;
543 let parent = document.getElementById("parent");
544 let middle = document.getElementById("middle");
545 let inside = document.getElementById("inside");
546 let sibling = document.getElementById("sibling");
547 let sibling2 = document.getElementById("sibling2");
548 let toHide = document.getElementById("tohide");
549
550 insertStyleRule(".inside {}");
551
552 applyElemHideEmulation(
553 [selector]
554 ).then(() =>
555 {
556 expectVisible(test, parent);
557 expectVisible(test, middle);
558 expectVisible(test, inside);
559 expectVisible(test, sibling);
560 expectVisible(test, sibling2);
561 expectHidden(test, toHide);
562 }).catch(unexpectedError.bind(test)).then(() => test.done());
563 }
564
565 exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling = function(test)
566 {
567 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, "div:-abp-has(: -abp-has(div.inside)) + div > div");
568 };
569
570 exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling2 = function(test)
571 {
572 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, "div:-abp-has(: -abp-has(> div.inside)) + div > div");
573 };
574
575 exports.testPseudoClassHasSelectorWithPropSelector = function(test)
576 {
577 let parent = createElementWithStyle("{}");
578 let child = createElementWithStyle("{background-color: #000}", parent);
579 applyElemHideEmulation(
580 ["div:-abp-has(:-abp-properties(background-color: rgb(0, 0, 0)))"]
581 ).then(() =>
582 {
583 expectVisible(test, child);
584 expectHidden(test, parent);
585 }).catch(unexpectedError.bind(test)).then(() => test.done());
586 };
OLDNEW
« no previous file with comments | « chrome/content/elemHideEmulation.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld