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: Filter reporting was broken in the previous revision. Created May 12, 2017, 3:40 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
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 parseSelector,
22 PlainSelector, HasSelector, PropsSelector */
21 23
22 let myUrl = document.currentScript.src; 24 let myUrl = document.currentScript.src;
23 25
24 exports.tearDown = function(callback) 26 exports.tearDown = function(callback)
25 { 27 {
26 let styleElements = document.head.getElementsByTagName("style"); 28 let styleElements = document.head.getElementsByTagName("style");
27 while (styleElements.length) 29 while (styleElements.length)
28 styleElements[0].parentNode.removeChild(styleElements[0]); 30 styleElements[0].parentNode.removeChild(styleElements[0]);
31
32 let child;
33 while (child = document.body.firstChild)
34 document.body.removeChild(child);
35
29 callback(); 36 callback();
30 }; 37 };
31 38
32 function unexpectedError(error) 39 function unexpectedError(error)
33 { 40 {
34 console.error(error); 41 console.error(error);
35 this.ok(false, "Unexpected error: " + error); 42 this.ok(false, "Unexpected error: " + error);
36 } 43 }
37 44
38 function expectHidden(test, element) 45 function expectHidden(test, element)
(...skipping 23 matching lines...) Expand all
62 if (styleElements.length) 69 if (styleElements.length)
63 styleElement = styleElements[0]; 70 styleElement = styleElements[0];
64 else 71 else
65 { 72 {
66 styleElement = document.createElement("style"); 73 styleElement = document.createElement("style");
67 document.head.appendChild(styleElement); 74 document.head.appendChild(styleElement);
68 } 75 }
69 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); 76 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length);
70 } 77 }
71 78
72 function createElementWithStyle(styleBlock) 79 // insert a <div> with a unique id and and empty CSS rule
80 // for the the selector matching the id.
81 function createElementWithStyle(styleBlock, parent)
73 { 82 {
74 let element = document.createElement("div"); 83 let element = document.createElement("div");
75 element.id = findUniqueId(); 84 element.id = findUniqueId();
76 document.body.appendChild(element); 85 if (!parent)
86 document.body.appendChild(element);
87 else
88 parent.appendChild(element);
77 insertStyleRule("#" + element.id + " " + styleBlock); 89 insertStyleRule("#" + element.id + " " + styleBlock);
78 return element; 90 return element;
79 } 91 }
80 92
81 function applyElemHideEmulation(selectors) 93 // Will ensure the class ElemHideEmulation is loaded
94 // and then will call the callback.
95 // NOTE: if it never loads, this will probably hang in an infinite
96 // loop
97 function loadElemHideEmulation()
82 { 98 {
83 if (typeof ElemHideEmulation == "undefined") 99 if (typeof ElemHideEmulation == "undefined")
84 { 100 {
85 return loadScript(myUrl + "/../../../lib/common.js").then(() => 101 return loadScript(myUrl + "/../../../lib/common.js").then(() =>
86 { 102 {
87 return loadScript(myUrl + "/../../../chrome/content/elemHideEmulation.js") ; 103 return loadScript(myUrl + "/../../../chrome/content/elemHideEmulation.js") ;
88 }).then(() => 104 }).then(() =>
89 { 105 {
90 return applyElemHideEmulation(selectors); 106 return loadElemHideEmulation();
91 }); 107 });
92 } 108 }
93 109
94 let elemHideEmulation = new ElemHideEmulation( 110 return Promise.resolve();
95 window, 111 }
96 callback => 112
97 { 113 // instantiate a ElemHideEmulation with @selectors.
98 let patterns = []; 114 function applyElemHideEmulation(selectors)
99 selectors.forEach(selector => 115 {
116 return loadElemHideEmulation().then(() =>
117 {
118 let elemHideEmulation = new ElemHideEmulation(
119 window,
120 callback =>
100 { 121 {
101 patterns.push({selector}); 122 let patterns = [];
102 }); 123 selectors.forEach(selector =>
103 callback(patterns); 124 {
104 }, newSelectors => 125 patterns.push({selector});
105 { 126 });
106 if (!newSelectors.length) 127 callback(patterns);
107 return; 128 },
108 let selector = newSelectors.join(", "); 129 newSelectors =>
109 insertStyleRule(selector + "{display: none !important;}"); 130 {
110 } 131 if (!newSelectors.length)
111 ); 132 return;
112 133 let selector = newSelectors.join(", ");
113 elemHideEmulation.apply(); 134 insertStyleRule(selector + "{display: none !important;}");
114 return Promise.resolve(); 135 },
115 } 136 elements =>
137 {
138 if (!elements.length)
139 return;
140 for (let element of elements)
141 element.style.display = "none";
142 }
143 );
144
145 elemHideEmulation.apply();
146 return Promise.resolve();
147 });
148 }
149
150 exports.testParseSelector = function(test)
151 {
152 loadElemHideEmulation().then(() =>
153 {
154 let selectors = parseSelector("");
155 test.equal(selectors.length, 0);
156
157 let selector = "div > :-abp-properties('background-color: rgb(0, 0, 0)')";
158 selectors = parseSelector(selector);
159 test.equal(selectors.length, 2);
160 test.ok(selectors[0] instanceof PlainSelector);
161 test.ok(selectors[1] instanceof PropsSelector);
162
163 selector = "div > :-abp-has(> div.inside) > div";
164 selectors = parseSelector(selector);
165 test.equal(selectors.length, 3);
166 test.ok(selectors[0] instanceof PlainSelector);
167 test.ok(selectors[1] instanceof HasSelector);
168 test.ok(selectors[2] instanceof PlainSelector);
169
170 selector = "div > div:-abp-has(> div.inside) > div";
171 selectors = parseSelector(selector);
172
173 test.equal(selectors.length, 3);
174 test.ok(selectors[0] instanceof PlainSelector);
175 test.ok(selectors[1] instanceof HasSelector);
176 test.ok(selectors[2] instanceof PlainSelector);
177
178 selector = "div > :-abp-has(> div.inside) > :-abp-properties('background-col or: rgb(0, 0, 0)')";
179 selectors = parseSelector(selector);
180
181 test.equal(selectors.length, 4);
182 test.ok(selectors[0] instanceof PlainSelector);
183 test.ok(selectors[1] instanceof HasSelector);
184 test.ok(selectors[2] instanceof PlainSelector);
185 test.ok(selectors[3] instanceof PropsSelector);
186
187 selector = "div > :-abp-has(> div.inside > :-abp-properties('background-colo r: rgb(0, 0, 0)')";
188 selectors = parseSelector(selector);
189
190 test.equal(selectors, null);
191 }).catch(unexpectedError.bind(test)).then(() => test.done());
192 };
193
194 function buildDom(doc)
195 {
196 doc.body.innerHTML = `<div id="parent">
197 <div id="middle">
198 <div id="middle1"><div id="inside" class="inside"></div></div>
199 </div>
200 <div id="sibling">
201 <div id="tohide">to hide</div>
202 </div>
203 <div id="sibling2">
204 <div id="sibling21"><div id="sibling211" class="inside"></div></div>
205 </div>
206 </div>`;
207 let parent = document.getElementById("parent");
208 let middle = document.getElementById("middle");
209 let inside = document.getElementById("inside");
210 let sibling = document.getElementById("sibling");
211 let sibling2 = document.getElementById("sibling2");
212 let toHide = document.getElementById("tohide");
213 return {parent, middle, inside, sibling, sibling2, toHide};
214 }
215
216 exports.testPlainSelector = function(test)
217 {
218 let nodes = buildDom(document);
219
220 loadElemHideEmulation().then(() =>
221 {
222 let selector = new PlainSelector("div > div");
223
224 let iter = selector.getSelectors("foo > ");
225 let value = iter.next();
226 test.equal(value.value[0], "foo > div > div");
227 test.ok(iter.next().done);
228
229 iter = selector.getElements("", document, [document.sheet]);
230 value = iter.next();
231 test.ok(!value.done);
232 test.equal(value.value, nodes.middle);
233 value = iter.next();
234 test.ok(!value.done);
235 test.equal(value.value.id, "middle1");
236 value = iter.next();
237 test.ok(!value.done);
238 test.equal(value.value, nodes.inside);
239 }).catch(unexpectedError.bind(test)).then(() => test.done());
240 };
241
242 exports.testHasSelector = function(test)
243 {
244 buildDom(document);
245
246 loadElemHideEmulation().then(() =>
247 {
248 let selector = new HasSelector("> div.inside");
249
250 let iter = selector.getSelectors("", document, document.sheet);
251 let value = iter.next();
252 test.ok(!value.done);
253 test.equal(value.value[0], "#middle1");
254
255 iter = selector.getElements("", document, document.sheet);
256 value = iter.next();
257 test.ok(!value.done);
258 test.equal(value.value.id, "middle1");
259 value = iter.next();
260 test.ok(!value.done);
261 test.equal(value.value.id, "sibling21");
262 value = iter.next();
263 test.ok(value.done);
264 }).catch(unexpectedError.bind(test)).then(() => test.done());
265 };
266
267 exports.testSplitStyleRule = function(test)
268 {
269 loadElemHideEmulation().then(() =>
270 {
271 let selectors = splitSelector("div:-abp-has(div) > [-abp-properties='backgro und-color: rgb(0, 0, 0)'] > span");
272 test.ok(selectors);
273 test.equal(selectors.length, 1, "There is only one selector");
274
275 selectors = splitSelector("div:-abp-has(div), [-abp-properties='background-c olor: rgb(0, 0, 0)']");
276 test.ok(selectors);
277 test.equal(selectors.length, 2, "There are two selectors");
278 }).catch(unexpectedError.bind(test)).then(() => test.done());
279 };
116 280
117 exports.testVerbatimPropertySelector = function(test) 281 exports.testVerbatimPropertySelector = function(test)
118 { 282 {
119 let toHide = createElementWithStyle("{background-color: #000}"); 283 let toHide = createElementWithStyle("{background-color: #000}");
120 applyElemHideEmulation( 284 applyElemHideEmulation(
121 ["[-abp-properties='background-color: rgb(0, 0, 0)']"] 285 [":-abp-properties('background-color: rgb(0, 0, 0)')"]
122 ).then(() => 286 ).then(() =>
123 { 287 {
288 expectHidden(test, toHide);
289 }).catch(unexpectedError.bind(test)).then(() => test.done());
290 };
291
292 exports.testVerbatimPropertySelectorWithPrefix = function(test)
293 {
294 let parent = createElementWithStyle("{background-color: #000}");
295 let toHide = createElementWithStyle("{background-color: #000}", parent);
296 applyElemHideEmulation(
297 ["div > :-abp-properties('background-color: rgb(0, 0, 0)')"]
298 ).then(() =>
299 {
300 expectVisible(test, parent);
301 expectHidden(test, toHide);
302 }).catch(unexpectedError.bind(test)).then(() => test.done());
303 };
304
305 exports.testVerbatimPropertySelectorWithPrefixNoMatch = function(test)
306 {
307 let parent = createElementWithStyle("{background-color: #000}");
308 let toHide = createElementWithStyle("{background-color: #fff}", parent);
309 applyElemHideEmulation(
310 ["div > :-abp-properties('background-color: rgb(0, 0, 0)')"]
311 ).then(() =>
312 {
313 expectVisible(test, parent);
314 expectVisible(test, toHide);
315 }).catch(unexpectedError.bind(test)).then(() => test.done());
316 };
317
318 exports.testVerbatimPropertySelectorWithSuffix = function(test)
319 {
320 let parent = createElementWithStyle("{background-color: #000}");
321 let toHide = createElementWithStyle("{background-color: #000}", parent);
322 applyElemHideEmulation(
323 [":-abp-properties('background-color: rgb(0, 0, 0)') > div"]
324 ).then(() =>
325 {
326 expectVisible(test, parent);
327 expectHidden(test, toHide);
328 }).catch(unexpectedError.bind(test)).then(() => test.done());
329 };
330
331 exports.testVerbatimPropertyPseudoSelectorWithPrefixAndSuffix = function(test)
332 {
333 let parent = createElementWithStyle("{background-color: #000}");
334 let middle = createElementWithStyle("{background-color: #000}", parent);
335 let toHide = createElementWithStyle("{background-color: #000}", middle);
336 applyElemHideEmulation(
337 ["div > :-abp-properties('background-color: rgb(0, 0, 0)') > div"]
338 ).then(() =>
339 {
340 expectVisible(test, parent);
341 expectVisible(test, middle);
124 expectHidden(test, toHide); 342 expectHidden(test, toHide);
125 }).catch(unexpectedError.bind(test)).then(() => test.done()); 343 }).catch(unexpectedError.bind(test)).then(() => test.done());
126 }; 344 };
127 345
128 exports.testPropertySelectorWithWildcard = function(test) 346 exports.testPropertySelectorWithWildcard = function(test)
129 { 347 {
130 let toHide = createElementWithStyle("{background-color: #000}"); 348 let toHide = createElementWithStyle("{background-color: #000}");
131 applyElemHideEmulation( 349 applyElemHideEmulation(
132 ["[-abp-properties='*color: rgb(0, 0, 0)']"] 350 [":-abp-properties('*color: rgb(0, 0, 0)')"]
133 ).then(() => 351 ).then(() =>
134 { 352 {
135 expectHidden(test, toHide); 353 expectHidden(test, toHide);
136 }).catch(unexpectedError.bind(test)).then(() => test.done()); 354 }).catch(unexpectedError.bind(test)).then(() => test.done());
137 }; 355 };
138 356
139 exports.testPropertySelectorWithRegularExpression = function(test) 357 exports.testPropertySelectorWithRegularExpression = function(test)
140 { 358 {
141 let toHide = createElementWithStyle("{background-color: #000}"); 359 let toHide = createElementWithStyle("{background-color: #000}");
142 applyElemHideEmulation( 360 applyElemHideEmulation(
143 ["[-abp-properties='/.*color: rgb\\(0, 0, 0\\)/']"] 361 [":-abp-properties('/.*color: rgb\\(0, 0, 0\\)/')"]
144 ).then(() => 362 ).then(() =>
145 { 363 {
146 expectHidden(test, toHide); 364 expectHidden(test, toHide);
147 }).catch(unexpectedError.bind(test)).then(() => test.done()); 365 }).catch(unexpectedError.bind(test)).then(() => test.done());
148 }; 366 };
149 367
150 exports.testPropertySelectorWithEscapedBrace = function(test) 368 exports.testPropertySelectorWithEscapedBrace = function(test)
151 { 369 {
152 let toHide = createElementWithStyle("{background-color: #000}"); 370 let toHide = createElementWithStyle("{background-color: #000}");
153 applyElemHideEmulation( 371 applyElemHideEmulation(
154 ["[-abp-properties='/background.\\x7B 0,6\\x7D : rgb\\(0, 0, 0\\)/']"] 372 [":-abp-properties('/background.\\x7B 0,6\\x7D : rgb\\(0, 0, 0\\)/')"]
155 ).then(() => 373 ).then(() =>
156 { 374 {
157 expectHidden(test, toHide); 375 expectHidden(test, toHide);
158 }).catch(unexpectedError.bind(test)).then(() => test.done()); 376 }).catch(unexpectedError.bind(test)).then(() => test.done());
159 }; 377 };
160 378
161 exports.testPropertySelectorWithImproperlyEscapedBrace = function(test) 379 exports.testPropertySelectorWithImproperlyEscapedBrace = function(test)
162 { 380 {
163 let toHide = createElementWithStyle("{background-color: #000}"); 381 let toHide = createElementWithStyle("{background-color: #000}");
164 applyElemHideEmulation( 382 applyElemHideEmulation(
165 ["[-abp-properties='/background.\\x7B0,6\\x7D: rgb\\(0, 0, 0\\)/']"] 383 [":-abp-properties('/background.\\x7B0,6\\x7D: rgb\\(0, 0, 0\\)/')"]
166 ).then(() => 384 ).then(() =>
167 { 385 {
168 expectVisible(test, toHide); 386 expectVisible(test, toHide);
169 }).catch(unexpectedError.bind(test)).then(() => test.done()); 387 }).catch(unexpectedError.bind(test)).then(() => test.done());
170 }; 388 };
171 389
172 exports.testDynamicallyChangedProperty = function(test) 390 exports.testDynamicallyChangedProperty = function(test)
173 { 391 {
174 let toHide = createElementWithStyle("{}"); 392 let toHide = createElementWithStyle("{}");
175 applyElemHideEmulation( 393 applyElemHideEmulation(
176 ["[-abp-properties='background-color: rgb(0, 0, 0)']"] 394 [":-abp-properties('background-color: rgb(0, 0, 0)')"]
177 ).then(() => 395 ).then(() =>
178 { 396 {
179 expectVisible(test, toHide); 397 expectVisible(test, toHide);
180 insertStyleRule("#" + toHide.id + " {background-color: #000}"); 398 insertStyleRule("#" + toHide.id + " {background-color: #000}");
181 return new Promise((resolve, reject) => 399 return new Promise((resolve, reject) =>
182 { 400 {
183 window.setTimeout(() => 401 window.setTimeout(() =>
184 { 402 {
185 expectHidden(test, toHide); 403 expectHidden(test, toHide);
186 resolve(); 404 resolve();
187 }, 0); 405 }, 0);
188 }); 406 });
189 }).catch(unexpectedError.bind(test)).then(() => test.done()); 407 }).catch(unexpectedError.bind(test)).then(() => test.done());
190 }; 408 };
409
410 exports.testPseudoClassHasSelector = function(test)
411 {
412 let toHide = createElementWithStyle("{}");
413 applyElemHideEmulation(
414 ["div:-abp-has(div)"]
415 ).then(() =>
416 {
417 expectVisible(test, toHide);
418 }).catch(unexpectedError.bind(test)).then(() => test.done());
419 };
420
421 exports.testPseudoClassHasSelectorWithPrefix = function(test)
422 {
423 let parent = createElementWithStyle("{}");
424 let child = createElementWithStyle("{}", parent);
425 applyElemHideEmulation(
426 ["div:-abp-has(div)"]
427 ).then(() =>
428 {
429 expectHidden(test, parent);
430 expectVisible(test, child);
431 }).catch(unexpectedError.bind(test)).then(() => test.done());
432 };
433
434 exports.testPseudoClassHasSelectorWithSuffix = function(test)
435 {
436 let parent = createElementWithStyle("{}");
437 let middle = createElementWithStyle("{}", parent);
438 let child = createElementWithStyle("{}", middle);
439 applyElemHideEmulation(
440 ["div:-abp-has(div) > div"]
441 ).then(() =>
442 {
443 expectVisible(test, parent);
444 expectHidden(test, middle);
445 expectHidden(test, child);
446 }).catch(unexpectedError.bind(test)).then(() => test.done());
447 };
448
449 exports.testPseudoClassHasSelectorWithSuffixSibling = function(test)
450 {
451 let parent = createElementWithStyle("{}");
452 let middle = createElementWithStyle("{}", parent);
453 let toHide = createElementWithStyle("{}");
454 applyElemHideEmulation(
455 ["div:-abp-has(div) + div"]
456 ).then(() =>
457 {
458 expectVisible(test, parent);
459 expectVisible(test, middle);
460 expectHidden(test, toHide);
461 }).catch(unexpectedError.bind(test)).then(() => test.done());
462 };
463
464 exports.testPseudoClassHasSelectorWithSuffixSiblingChild = function(test)
465 {
466 // <div>
467 // <div></div>
468 // <div>
469 // <div>to hide</div>
470 // </div>
471 // </div>
472 let parent = createElementWithStyle("{}");
473 let middle = createElementWithStyle("{}", parent);
474 let sibling = createElementWithStyle("{}");
475 let toHide = createElementWithStyle("{}", sibling);
476 applyElemHideEmulation(
477 ["div:-abp-has(div) + div > div"]
478 ).then(() =>
479 {
480 expectVisible(test, parent);
481 expectVisible(test, middle);
482 expectVisible(test, sibling);
483 expectHidden(test, toHide);
484 }).catch(unexpectedError.bind(test)).then(() => test.done());
485 };
486
487 function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, selector )
488 {
489 document.body.innerHTML = `<div id="parent">
490 <div id="middle">
491 <div id="middle1"><div id="inside" class="inside"></div></div>
492 </div>
493 <div id="sibling">
494 <div id="tohide">to hide</div>
495 </div>
496 <div id="sibling2">
497 <div id="sibling21"><div id="sibling211" class="inside"></div></div>
498 </div>
499 </div>`;
500 let parent = document.getElementById("parent");
501 let middle = document.getElementById("middle");
502 let inside = document.getElementById("inside");
503 let sibling = document.getElementById("sibling");
504 let sibling2 = document.getElementById("sibling2");
505 let toHide = document.getElementById("tohide");
506
507 insertStyleRule(".inside {}");
508
509 applyElemHideEmulation(
510 [selector]
511 ).then(() =>
512 {
513 expectVisible(test, parent);
514 expectVisible(test, middle);
515 expectVisible(test, inside);
516 expectVisible(test, sibling);
517 expectVisible(test, sibling2);
518 expectHidden(test, toHide);
519 }).catch(unexpectedError.bind(test)).then(() => test.done());
520 }
521
522 exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling = function(test)
523 {
524 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, "div:-abp-has(: -abp-has(div.inside)) + div > div");
525 };
526
527 exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling2 = function(test)
528 {
529 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, "div:-abp-has(: -abp-has(> div.inside)) + div > div");
530 };
531
532 exports.testPseudoClassHasSelectorWithPropSelector = function(test)
533 {
534 let parent = createElementWithStyle("{}");
535 let child = createElementWithStyle("{background-color: #000}", parent);
536 applyElemHideEmulation(
537 ["div:-abp-has(:-abp-properties(\"background-color: rgb(0, 0, 0)\"))"]
538 ).then(() =>
539 {
540 expectVisible(test, child);
541 expectHidden(test, parent);
542 }).catch(unexpectedError.bind(test)).then(() => test.done());
543 };
OLDNEW

Powered by Google App Engine
This is Rietveld