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: Moved unwrap to filterClass, ES6 syntax, use :-abp-has(), don't modify DOM to select, rebased on 29… Created April 27, 2017, 4:10 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 | « lib/filterClasses.js ('k') | test/filterClasses.js » ('j') | 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, pseudoClassHasSelectorRegExp, splitSelector,
21 parsePattern, PseudoHasMatcher */
21 22
22 let myUrl = document.currentScript.src; 23 let myUrl = document.currentScript.src;
23 24
24 exports.tearDown = function(callback) 25 exports.tearDown = function(callback)
25 { 26 {
26 let styleElements = document.head.getElementsByTagName("style"); 27 let styleElements = document.head.getElementsByTagName("style");
27 while (styleElements.length) 28 while (styleElements.length)
28 styleElements[0].parentNode.removeChild(styleElements[0]); 29 styleElements[0].parentNode.removeChild(styleElements[0]);
30
31 let child;
32 while (child = document.body.firstChild)
33 document.body.removeChild(child);
34
29 callback(); 35 callback();
30 }; 36 };
31 37
32 function unexpectedError(error) 38 function unexpectedError(error)
33 { 39 {
34 console.error(error); 40 console.error(error);
35 this.ok(false, "Unexpected error: " + error); 41 this.ok(false, "Unexpected error: " + error);
36 } 42 }
37 43
38 function expectHidden(test, element) 44 function expectHidden(test, element)
(...skipping 23 matching lines...) Expand all
62 if (styleElements.length) 68 if (styleElements.length)
63 styleElement = styleElements[0]; 69 styleElement = styleElements[0];
64 else 70 else
65 { 71 {
66 styleElement = document.createElement("style"); 72 styleElement = document.createElement("style");
67 document.head.appendChild(styleElement); 73 document.head.appendChild(styleElement);
68 } 74 }
69 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length); 75 styleElement.sheet.insertRule(rule, styleElement.sheet.cssRules.length);
70 } 76 }
71 77
72 function createElementWithStyle(styleBlock) 78 // insert a <div> with a unique id and and empty CSS rule
79 // for the the selector matching the id.
80 function createElementWithStyle(styleBlock, parent)
73 { 81 {
74 let element = document.createElement("div"); 82 let element = document.createElement("div");
75 element.id = findUniqueId(); 83 element.id = findUniqueId();
76 document.body.appendChild(element); 84 if (!parent)
85 document.body.appendChild(element);
86 else
87 parent.appendChild(element);
77 insertStyleRule("#" + element.id + " " + styleBlock); 88 insertStyleRule("#" + element.id + " " + styleBlock);
78 return element; 89 return element;
79 } 90 }
80 91
81 function applyElemHideEmulation(selectors) 92 // Will ensure the class ElemHideEmulation is loaded
93 // and then will call the callback.
94 // NOTE: if it never loads, this will probably hang in an infinite
95 // loop
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 // instantiate a ElemHideEmulation 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 },
135 elements =>
136 {
137 if (!elements.length)
138 return;
139 for (let element of elements)
140 element.style.display = "none";
141 }
142 );
143
144 elemHideEmulation.apply();
145 return Promise.resolve();
146 });
147 }
148
149 exports.testPseudoHasRule = function(test)
150 {
151 loadElemHideEmulation().then(() =>
152 {
153 let selector = "div:-abp-has(span)";
154 // testing the regexp
155 let match = pseudoClassHasSelectorRegExp.exec(selector);
156 test.ok(match);
157 test.equal(match[1], "span");
158
159 selector = ":-abp-has(div.inside)";
160 match = pseudoClassHasSelectorRegExp.exec(selector);
161 test.ok(match);
162 test.equal(match[1], "div.inside");
163 }).catch(unexpectedError.bind(test)).then(() => test.done());
164 };
165
166 exports.testSplitStyleRule = function(test)
167 {
168 loadElemHideEmulation().then(() =>
169 {
170 let selectors = splitSelector("div:-abp-has(div) > [-abp-properties='backgro und-color: rgb(0, 0, 0)'] > span");
171 test.ok(selectors);
172 test.equal(selectors.length, 1, "There is only one selector");
173
174 selectors = splitSelector("div:-abp-has(div), [-abp-properties='background-c olor: rgb(0, 0, 0)']");
175 test.ok(selectors);
176 test.equal(selectors.length, 2, "There are two selectors");
177 }).catch(unexpectedError.bind(test)).then(() => test.done());
178 };
179
180 exports.testParsePattern = function(test)
181 {
182 loadElemHideEmulation().then(() =>
183 {
184 let pattern = parsePattern({selector: "[-abp-properties='background-color: r gb(0, 0, 0)']"});
185 test.ok(pattern);
186 test.equal(pattern.type, "props");
187 pattern = parsePattern({selector: "[-abp-properties='background-color: rgb(0 , 0, 0)']"});
188 test.ok(pattern);
189 test.equal(pattern.type, "props");
190
191 pattern = parsePattern({selector: ":-abp-has(div)"});
192 test.ok(pattern);
193 test.equal(pattern.type, "has");
194
195 pattern = parsePattern({selector: ":-abp-properties('background-color: rgb(0 , 0, 0)')"});
196 test.ok(pattern);
197 test.equal(pattern.type, "props");
198 }).catch(unexpectedError.bind(test)).then(() => test.done());
199 };
200
201 function runTestVerbatimPropertySelector(test, selector)
202 {
203 let toHide = createElementWithStyle("{background-color: #000}");
204 applyElemHideEmulation(
205 [selector]
206 ).then(() =>
207 {
208 expectHidden(test, toHide);
209 }).catch(unexpectedError.bind(test)).then(() => test.done());
115 } 210 }
116 211
117 exports.testVerbatimPropertySelector = function(test) 212 exports.testVerbatimPropertySelector = function(test)
118 { 213 {
214 runTestVerbatimPropertySelector(test, "[-abp-properties='background-color: rgb (0, 0, 0)']");
215 };
216
217 /* Testing the new syntax */
218 exports.testVerbatimPropertyPseudoSelector = function(test)
219 {
220 runTestVerbatimPropertySelector(test, ":-abp-properties('background-color: rgb (0, 0, 0)')");
221 };
222
223 function runTestVerbatimPropertySelectorWithPrefix(test, selector)
224 {
225 let parent = createElementWithStyle("{background-color: #000}");
226 let toHide = createElementWithStyle("{background-color: #000}", parent);
227 applyElemHideEmulation(
228 [selector]
229 ).then(() =>
230 {
231 expectVisible(test, parent);
232 expectHidden(test, toHide);
233 }).catch(unexpectedError.bind(test)).then(() => test.done());
234 }
235
236 exports.testVerbatimPropertySelectorWithPrefix = function(test)
237 {
238 runTestVerbatimPropertySelectorWithPrefix(test, "div > [-abp-properties='backg round-color: rgb(0, 0, 0)']");
239 };
240
241 // testing the new syntax
242 exports.testVerbatimPropertyPseudoSelectorWithPrefix = function(test)
243 {
244 runTestVerbatimPropertySelectorWithPrefix(test, "div > :-abp-properties('backg round-color: rgb(0, 0, 0)')");
245 };
246
247 exports.testVerbatimPropertySelectorWithPrefixNoMatch = function(test)
248 {
249 let parent = createElementWithStyle("{background-color: #000}");
250 let toHide = createElementWithStyle("{background-color: #fff}", parent);
251 applyElemHideEmulation(
252 ["div > [-abp-properties='background-color: rgb(0, 0, 0)']"]
253 ).then(() =>
254 {
255 expectVisible(test, parent);
256 expectVisible(test, toHide);
257 }).catch(unexpectedError.bind(test)).then(() => test.done());
258 };
259
260 function runTestVerbatimPropertySelectorWithSuffix(test, selector)
261 {
262 let parent = createElementWithStyle("{background-color: #000}");
263 let toHide = createElementWithStyle("{background-color: #000}", parent);
264 applyElemHideEmulation(
265 [selector]
266 ).then(() =>
267 {
268 expectVisible(test, parent);
269 expectHidden(test, toHide);
270 }).catch(unexpectedError.bind(test)).then(() => test.done());
271 }
272
273 exports.testVerbatimPropertySelectorWithSuffix = function(test)
274 {
275 runTestVerbatimPropertySelectorWithSuffix(test, "[-abp-properties='background- color: rgb(0, 0, 0)'] > div");
276 };
277
278 exports.testVerbatimPropertyPseudoSelectorWithSuffix = function(test)
279 {
280 runTestVerbatimPropertySelectorWithSuffix(test, ":-abp-properties('background- color: rgb(0, 0, 0)') > div");
281 };
282
283 function runTestVerbatimPropertySelectorWithPrefixAndSuffix(test, selector)
284 {
285 let parent = createElementWithStyle("{background-color: #000}");
286 let middle = createElementWithStyle("{background-color: #000}", parent);
287 let toHide = createElementWithStyle("{background-color: #000}", middle);
288 applyElemHideEmulation(
289 [selector]
290 ).then(() =>
291 {
292 expectVisible(test, parent);
293 expectVisible(test, middle);
294 expectHidden(test, toHide);
295 }).catch(unexpectedError.bind(test)).then(() => test.done());
296 }
297
298 exports.testVerbatimPropertySelectorWithPrefixAndSuffix = function(test)
299 {
300 runTestVerbatimPropertySelectorWithPrefixAndSuffix(test, "div > [-abp-properti es='background-color: rgb(0, 0, 0)'] > div");
301 };
302
303 exports.testVerbatimPropertyPseudoSelectorWithPrefixAndSuffix = function(test)
304 {
305 runTestVerbatimPropertySelectorWithPrefixAndSuffix(test, "div > :-abp-properti es('background-color: rgb(0, 0, 0)') > div");
306 };
307
308 exports.testPropertySelectorWithWildcard = function(test)
309 {
119 let toHide = createElementWithStyle("{background-color: #000}"); 310 let toHide = createElementWithStyle("{background-color: #000}");
120 applyElemHideEmulation( 311 applyElemHideEmulation(
121 ["[-abp-properties='background-color: rgb(0, 0, 0)']"]
122 ).then(() =>
123 {
124 expectHidden(test, toHide);
125 }).catch(unexpectedError.bind(test)).then(() => test.done());
126 };
127
128 exports.testPropertySelectorWithWildcard = function(test)
129 {
130 let toHide = createElementWithStyle("{background-color: #000}");
131 applyElemHideEmulation(
132 ["[-abp-properties='*color: rgb(0, 0, 0)']"] 312 ["[-abp-properties='*color: rgb(0, 0, 0)']"]
133 ).then(() => 313 ).then(() =>
134 { 314 {
135 expectHidden(test, toHide); 315 expectHidden(test, toHide);
136 }).catch(unexpectedError.bind(test)).then(() => test.done()); 316 }).catch(unexpectedError.bind(test)).then(() => test.done());
137 }; 317 };
138 318
139 exports.testPropertySelectorWithRegularExpression = function(test) 319 exports.testPropertySelectorWithRegularExpression = function(test)
140 { 320 {
141 let toHide = createElementWithStyle("{background-color: #000}"); 321 let toHide = createElementWithStyle("{background-color: #000}");
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 return new Promise((resolve, reject) => 361 return new Promise((resolve, reject) =>
182 { 362 {
183 window.setTimeout(() => 363 window.setTimeout(() =>
184 { 364 {
185 expectHidden(test, toHide); 365 expectHidden(test, toHide);
186 resolve(); 366 resolve();
187 }, 0); 367 }, 0);
188 }); 368 });
189 }).catch(unexpectedError.bind(test)).then(() => test.done()); 369 }).catch(unexpectedError.bind(test)).then(() => test.done());
190 }; 370 };
371
372 exports.testPseudoClassHasMatcher = function(test)
373 {
374 let parent = createElementWithStyle("{}");
375 let child = createElementWithStyle("{}", parent);
376 loadElemHideEmulation().then(() =>
377 {
378 let matcher = new PseudoHasMatcher("div");
379 test.equal(matcher.match(parent), true, "Parent should contain what is expec ted");
380 test.equal(matcher.match(child), false, "Child shouldn't match");
381
382 let matcher2 = new PseudoHasMatcher("span");
383 test.equal(matcher2.match(parent), false, "Doesn't have a <span> child, shou ldn't match");
384 test.equal(matcher2.match(child), false, "Child shouldn't match");
385 }).catch(unexpectedError.bind(test)).then(() => test.done());
386 };
387
388 exports.testPseudoClassHasSelector = function(test)
389 {
390 let toHide = createElementWithStyle("{}");
391 applyElemHideEmulation(
392 ["div:-abp-has(div)"]
393 ).then(() =>
394 {
395 expectVisible(test, toHide);
396 }).catch(unexpectedError.bind(test)).then(() => test.done());
397 };
398
399 exports.testPseudoClassHasSelectorWithPrefix = function(test)
400 {
401 let parent = createElementWithStyle("{}");
402 let child = createElementWithStyle("{}", parent);
403 applyElemHideEmulation(
404 ["div:-abp-has(div)"]
405 ).then(() =>
406 {
407 expectHidden(test, parent);
408 expectVisible(test, child);
409 }).catch(unexpectedError.bind(test)).then(() => test.done());
410 };
411
412 exports.testPseudoClassHasSelectorWithSuffix = function(test)
413 {
414 let parent = createElementWithStyle("{}");
415 let middle = createElementWithStyle("{}", parent);
416 let child = createElementWithStyle("{}", middle);
417 applyElemHideEmulation(
418 ["div:-abp-has(div) > div"]
419 ).then(() =>
420 {
421 expectVisible(test, parent);
422 expectHidden(test, middle);
423 expectHidden(test, child);
424 }).catch(unexpectedError.bind(test)).then(() => test.done());
425 };
426
427 exports.testPseudoClassHasSelectorWithSuffixSibling = function(test)
428 {
429 let parent = createElementWithStyle("{}");
430 let middle = createElementWithStyle("{}", parent);
431 let toHide = createElementWithStyle("{}");
432 applyElemHideEmulation(
433 ["div:-abp-has(div) + div"]
434 ).then(() =>
435 {
436 expectVisible(test, parent);
437 expectVisible(test, middle);
438 expectHidden(test, toHide);
439 }).catch(unexpectedError.bind(test)).then(() => test.done());
440 };
441
442 exports.testPseudoClassHasSelectorWithSuffixSiblingChild = function(test)
443 {
444 // <div>
445 // <div></div>
446 // <div>
447 // <div>to hide</div>
448 // </div>
449 // </div>
450 let parent = createElementWithStyle("{}");
451 let middle = createElementWithStyle("{}", parent);
452 let sibling = createElementWithStyle("{}");
453 let toHide = createElementWithStyle("{}", sibling);
454 applyElemHideEmulation(
455 ["div:-abp-has(div) + div > div"]
456 ).then(() =>
457 {
458 expectVisible(test, parent);
459 expectVisible(test, middle);
460 expectVisible(test, sibling);
461 expectHidden(test, toHide);
462 }).catch(unexpectedError.bind(test)).then(() => test.done());
463 };
464
465 function runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, selector )
466 {
467 document.body.innerHTML = `<div id="parent">
468 <div id="middle">
469 <div id="middle.1"><div id="inside" class="inside"></div></div>
470 </div>
471 <div id="sibling">
472 <div id="tohide">to hide</div>
473 </div>
474 <div id="sibling2">
475 <div id="sibling2.1"><div id="sibling2.1.1" class="inside"></div></div>
476 </div>
477 </div>`;
478 let parent = document.getElementById("parent");
479 let middle = document.getElementById("middle");
480 let inside = document.getElementById("inside");
481 let sibling = document.getElementById("sibling");
482 let sibling2 = document.getElementById("sibling2");
483 let toHide = document.getElementById("tohide");
484
485 applyElemHideEmulation(
486 [selector]
487 ).then(() =>
488 {
489 expectVisible(test, parent);
490 expectVisible(test, middle);
491 expectVisible(test, inside);
492 expectVisible(test, sibling);
493 expectVisible(test, sibling2);
494 expectHidden(test, toHide);
495 }).catch(unexpectedError.bind(test)).then(() => test.done());
496 }
497
498 exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling = function(test)
499 {
500 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, "div:-abp-has(: -abp-has(div.inside)) + div > div");
501 };
502
503 exports.testPseudoClassHasSelectorWithHasAndWithSuffixSibling2 = function(test)
504 {
505 runTestPseudoClassHasSelectorWithHasAndWithSuffixSibling(test, "div:-abp-has(: -abp-has(> div.inside)) + div > div");
506 };
507
508 exports.testPseudoClassHasSelectorWithPropSelector = function(test)
509 {
510 let parent = createElementWithStyle("{}");
511 let child = createElementWithStyle("{background-color: #000}", parent);
512 applyElemHideEmulation(
513 ["div:-abp-has(:-abp-properties(\"background-color: rgb(0, 0, 0)\"))"]
514 ).then(() =>
515 {
516 expectVisible(test, child);
517 expectHidden(test, parent);
518 }).catch(unexpectedError.bind(test)).then(() => test.done());
519 };
OLDNEW
« no previous file with comments | « lib/filterClasses.js ('k') | test/filterClasses.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld