| Index: test/wrappers/pages.js | 
| =================================================================== | 
| new file mode 100644 | 
| --- /dev/null | 
| +++ b/test/wrappers/pages.js | 
| @@ -0,0 +1,165 @@ | 
| +/* | 
| + * This file is part of Adblock Plus <https://adblockplus.org/>, | 
| + * Copyright (C) 2006-present eyeo GmbH | 
| + * | 
| + * Adblock Plus is free software: you can redistribute it and/or modify | 
| + * it under the terms of the GNU General Public License version 3 as | 
| + * published by the Free Software Foundation. | 
| + * | 
| + * Adblock Plus is distributed in the hope that it will be useful, | 
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| + * GNU General Public License for more details. | 
| + * | 
| + * You should have received a copy of the GNU General Public License | 
| + * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
| + */ | 
| + | 
| +"use strict"; | 
| + | 
| +const TEST_PAGES_URL = "https://testpages.adblockplus.org/"; | 
| + | 
| +const assert = require("assert"); | 
| +const Jimp = require("jimp"); | 
| +const {By} = require("selenium-webdriver"); | 
| + | 
| +function imageFromBase64(s) | 
| +{ | 
| +  return Jimp.read(Buffer.from(s, "base64")); | 
| +} | 
| + | 
| +function takeScreenshot(element) | 
| +{ | 
| +  return element.takeScreenshot().then( | 
| +    imageFromBase64, | 
| + | 
| +    // Chrome doesn't support taking screenshots of individual elements. So as | 
| +    // a workaround, we scroll to the position of the element, take a screenshot | 
| +    // of the viewport and crop it to the size and position of our element. | 
| +    // This is not guaranteed to work on other browsers (mostly because | 
| +    // the behavior of Driver.takeScreenshot() may vary across browsers). | 
| +    () => element.getLocation().then(loc => | 
| +      element.getDriver().executeScript(` | 
| +        window.scrollTo(${loc.x}, ${loc.y}); | 
| +        return [window.scrollX, window.scrollY]; | 
| +      `).then(result => | 
| +      { | 
| +        let x = loc.x - result[0]; | 
| +        let y = loc.y - result[1]; | 
| + | 
| +        return Promise.all([ | 
| +          element.getDriver().takeScreenshot().then(imageFromBase64), | 
| +          element.getSize() | 
| +        ]).then(([img, size]) => | 
| +          img.crop(x, y, size.width, size.height) | 
| +        ); | 
| +      }) | 
| +    ) | 
| +  ).then(img => img.bitmap); | 
| +} | 
| + | 
| +function getSections(driver) | 
| +{ | 
| +  return driver.findElements(By.css("section")).then(elements => | 
| +    Promise.all(elements.map(e => | 
| +      Promise.all([ | 
| +        e.findElement(By.css("h2")).catch(() => null), | 
| +        e.findElement(By.className("testcase-container")).catch(() => null), | 
| +        e.findElements(By.css("pre")) | 
| +      ]) | 
| +    )) | 
| +  ).then(sections => sections.filter( | 
| +    ([title, demo, filters]) => title && demo && filters.length > 0 | 
| +  )); | 
| +} | 
| + | 
| +it("test pages", function() | 
| +{ | 
| +  return this.driver.navigate().to(TEST_PAGES_URL).then(() => | 
| +    this.driver.findElements(By.css(".site-pagelist a")) | 
| +  ).then(elements => | 
| +    Promise.all(elements.map(elem => elem.getAttribute("href"))) | 
| +  ).then(urls => | 
| +  { | 
| +    let p1 = Promise.resolve(); | 
| +    for (let url of urls) | 
| +      p1 = p1.then(() => | 
| +        this.driver.navigate().to(url) | 
| +      ).then(() => | 
| +        Promise.all([ | 
| +          getSections(this.driver), | 
| +          this.driver.findElement(By.css("h2")).getAttribute("textContent"), | 
| +          this.driver.executeScript("document.body.classList.add('expected');") | 
| +        ]) | 
| +      ).then(([sections, pageTitle]) => | 
| +        Promise.all(sections.map(([title, demo, filters]) => | 
| +          Promise.all([ | 
| +            title.getAttribute("textContent").then(testTitle => | 
| +              `${pageTitle.trim()} - ${testTitle.trim()}` | 
| +            ), | 
| +            takeScreenshot(demo), | 
| +            Promise.all(filters.map(elem => elem.getAttribute("textContent"))) | 
| +          ]) | 
| +        )) | 
| +      ).then(testCases => | 
| +      { | 
| +        let p2 = Promise.resolve(); | 
| +        for (let i = 0; i < testCases.length; i++) | 
| +        { | 
| +          let [title, expectedScreenshot, filters] = testCases[i]; | 
| +          let platform = this.test.parent.title; | 
| + | 
| +          if (// https://codereview.adblockplus.org/29871606/ | 
| +              title == "Element Hiding Emulation / Extended Selectors - " + | 
| +                       "Case insensative extended selectors" || | 
| +              // https://codereview.adblockplus.org/29871622/ | 
| +              title == "Element Hiding Emulation / Extended Selectors - " + | 
| +                       "Regular expression in :-abp-contains()" || | 
| +              // https://issues.adblockplus.org/ticket/6917 | 
| +              title == "$subdocument - Test case" && platform == "gecko" || | 
| +              // https://codereview.adblockplus.org/29871625/ | 
| +              title == "$xmlhttprequest Exception - Test case" || | 
| +              // Chromium doesn't support Flash | 
| +              /^\$object(-subrequest)?\b/.test(title) && platform == "chrome") | 
| +            continue; | 
| + | 
| +          p2 = p2.then(() => | 
| +            this.driver.navigate().to(this.origin + "/options.html") | 
| +          ).then(() => | 
| +            this.driver.executeAsyncScript(` | 
| +              let filters = arguments[0]; | 
| +              let callback = arguments[arguments.length - 1]; | 
| +              browser.runtime.sendMessage({type: "subscriptions.get", | 
| +                                           downloadable: true, | 
| +                                           special: true}).then(subs => | 
| +              { | 
| +                for (let subscription of subs) | 
| +                  browser.runtime.sendMessage({type: "subscriptions.remove", | 
| +                                               url: subscription.url}); | 
| +                return browser.runtime.sendMessage({type: "filters.importRaw", | 
| +                                                    text: filters}); | 
| +              }).then(() => callback(), callback); | 
| +            `, filters.join("\n")) | 
| +          ).then(error => | 
| +          { | 
| +            if (error) | 
| +              throw error; | 
| +            return this.driver.navigate().to(url); | 
| +          }).then(() => | 
| +            getSections(this.driver) | 
| +          ).then(sections => | 
| +            takeScreenshot(sections[i][1]) | 
| +          ).then(screenshot => | 
| +            assert.ok( | 
| +              screenshot.width == expectedScreenshot.width && | 
| +              screenshot.height == expectedScreenshot.height && | 
| +              screenshot.data.compare(expectedScreenshot.data) == 0, | 
| +              title | 
| +            ) | 
| +          ); | 
| +        } | 
| +        return p2; | 
| +      }); | 
| +    return p1; | 
| +  }); | 
| +}); | 
|  |