diff --git a/.eslintrc b/.eslintrc index a149d14..13ed046 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,5 +1,8 @@ { "root": true, + + "parser": "babel-eslint", + "parserOptions": { "ecmaVersion": 6, }, @@ -429,7 +432,7 @@ "spaced-comment": [2, "always"], // Require "use strict" to be defined globally in the script. - "strict": [2, "global"], + "strict": [0, "global"], // Allow vars to be declared anywhere in the scope. "vars-on-top": 0, diff --git a/.travis.yml b/.travis.yml index af9f280..1992024 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,10 @@ script: - echo "RE-RUN tests on the webpack and browserify bundled files" && npm install -g browserify webpack && ./test/run-module-bundlers-smoketests.sh +- export DISPLAY=:99.0 +- sh -e /etc/init.d/xvfb start +- echo "RUN integration tests on chrome" && + ./test/run-chrome-smoketests.sh after_script: npm run publish-coverage diff --git a/package.json b/package.json index 616e3c5..5db7228 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,14 @@ }, "homepage": "https://github.com/mozilla/webextension-polyfill", "devDependencies": { + "async-wait-until": "^1.1.5", + "babel-eslint": "^8.0.1", "babel-plugin-transform-es2015-modules-umd": "^6.24.1", - "babel-preset-babili": "0.0.10", + "babel-preset-babili": "^0.0.10", + "babel-preset-es2017": "^6.24.1", "chai": "^3.5.0", - "eslint": "3.9.1", + "eslint": "^3.9.1", + "finalhandler": "^1.1.0", "grunt": "^1.0.1", "grunt-babel": "^6.0.0", "grunt-contrib-concat": "^1.0.1", @@ -31,6 +35,8 @@ "jsdom": "^9.6.0", "mocha": "^3.1.0", "nyc": "^8.3.1", + "puppeteer": "^0.10.2", + "serve-static": "^1.13.1", "sinon": "^1.17.6" }, "nyc": { @@ -47,6 +53,7 @@ "publish-coverage": "grunt coveralls", "test": "mocha", "test-coverage": "COVERAGE=y nyc mocha", - "test-minified": "TEST_MINIFIED_POLYFILL=1 mocha" + "test-minified": "TEST_MINIFIED_POLYFILL=1 mocha", + "test-integration": "mocha -r test/mocha-babel test/integration/test-*" } } diff --git a/test/fixtures/index.html b/test/fixtures/index.html new file mode 100644 index 0000000..151a140 --- /dev/null +++ b/test/fixtures/index.html @@ -0,0 +1,10 @@ + + + + Browser Polyfill Test Page + + + +

Browser Polyfill Test Page

+ + diff --git a/test/fixtures/runtime-messaging-extension/background.js b/test/fixtures/runtime-messaging-extension/background.js new file mode 100644 index 0000000..db8d4d2 --- /dev/null +++ b/test/fixtures/runtime-messaging-extension/background.js @@ -0,0 +1,11 @@ +const {name} = browser.runtime.getManifest(); + +console.log(name, "background page loaded"); + +browser.runtime.onMessage.addListener((msg, sender) => { + console.log(name, "background received msg", {msg, sender}); + + return Promise.resolve("background page reply"); +}); + +console.log(name, "background page ready to receive a content script message..."); diff --git a/test/fixtures/runtime-messaging-extension/content.js b/test/fixtures/runtime-messaging-extension/content.js new file mode 100644 index 0000000..435d931 --- /dev/null +++ b/test/fixtures/runtime-messaging-extension/content.js @@ -0,0 +1,9 @@ +const {name} = browser.runtime.getManifest(); + +console.log(name, "content script loaded"); + +browser.runtime.sendMessage("content script message").then(reply => { + console.log(name, "content script received reply", {reply}); +}); + +console.log(name, "content script message sent"); diff --git a/test/fixtures/runtime-messaging-extension/manifest.json b/test/fixtures/runtime-messaging-extension/manifest.json new file mode 100644 index 0000000..084a423 --- /dev/null +++ b/test/fixtures/runtime-messaging-extension/manifest.json @@ -0,0 +1,24 @@ +{ + "manifest_version": 2, + "name": "test-extension-runtime-messaging", + "version": "0.1", + "description": "test-extension-runtime-messaging", + "content_scripts": [ + { + "matches": [ + "http://localhost/*" + ], + "js": [ + "browser-polyfill.js", + "content.js" + ] + } + ], + "permissions": [], + "background": { + "scripts": [ + "browser-polyfill.js", + "background.js" + ] + } +} diff --git a/test/integration/setup.js b/test/integration/setup.js new file mode 100644 index 0000000..a6de495 --- /dev/null +++ b/test/integration/setup.js @@ -0,0 +1,21 @@ +const finalhandler = require("finalhandler"); +const http = require("http"); +const serveStatic = require("serve-static"); + +exports.createHTTPServer = async (path) => { + var serve = serveStatic(path); + + var server = http.createServer((req, res) => { + serve(req, res, finalhandler(req, res)); + }); + + return new Promise((resolve, reject) => { + server.listen((err) => { + if (err) { + reject(err); + } else { + resolve(server); + } + }); + }); +}; diff --git a/test/integration/test-runtime-messaging-on-chrome.js b/test/integration/test-runtime-messaging-on-chrome.js new file mode 100644 index 0000000..a470de9 --- /dev/null +++ b/test/integration/test-runtime-messaging-on-chrome.js @@ -0,0 +1,92 @@ +"use strict"; + +const path = require("path"); + +const waitUntil = require("async-wait-until"); +const {deepEqual} = require("chai").assert; +const puppeteer = require("puppeteer"); + +const {createHTTPServer} = require("./setup"); + +const fixtureExtensionDirName = "runtime-messaging-extension"; + +const extensionName = require(`../fixtures/${fixtureExtensionDirName}/manifest.json`).name; + +describe("browser.runtime.onMessage/sendMessage", function() { + this.timeout(10000); + + it("works as expected on Chrome", async () => { + const server = await createHTTPServer(path.join(__dirname, "..", "fixtures")); + + const url = `http://localhost:${server.address().port}`; + + const browser = await puppeteer.launch({ + // Chrome Extensions are not currently supported in headless mode. + headless: false, + + // Custom chrome arguments. + args: [ + `--load-extension=${process.env.TEST_EXTENSIONS_PATH}/${fixtureExtensionDirName}`, + ], + }); + + const page = await browser.newPage(); + + const pageConsoleMessages = []; + const pageErrors = []; + + page.on("console", (...args) => { + pageConsoleMessages.push(args); + }); + + page.on("error", (error) => { + pageErrors.push(error); + }); + + await page.goto(url); + + const expectedConsoleMessages = [ + [extensionName, "content script loaded"], + [extensionName, "content script message sent"], + [extensionName, "content script received reply", {"reply": "background page reply"}], + ]; + + const lastExpectedMessage = expectedConsoleMessages.slice(-1).pop(); + + let unexpectedException; + + try { + // Wait until the last expected message has been received. + await waitUntil(() => { + return pageConsoleMessages.filter((msg) => { + return msg[0] === lastExpectedMessage[0] && msg[1] === lastExpectedMessage[1]; + }).length > 0; + }, 5000); + } catch (error) { + // Collect any unexpected exception (e.g. a timeout error raised by waitUntil), + // it will be part of the deepEqual assertion of the results. + unexpectedException = error; + } + + let actualResults = { + consoleMessages: pageConsoleMessages, + unexpectedException, + }; + + let expectedResults = { + consoleMessages: expectedConsoleMessages, + unexpectedException: undefined, + }; + + try { + deepEqual(actualResults, expectedResults, "Got the expected results"); + } finally { + // ensure that we close the browser and the test HTTP server before exiting + // the test, even when the assertions fails. + await Promise.all([ + browser.close(), + new Promise(resolve => server.close(resolve)), + ]); + } + }); +}); diff --git a/test/mocha-babel.js b/test/mocha-babel.js new file mode 100644 index 0000000..a8c2969 --- /dev/null +++ b/test/mocha-babel.js @@ -0,0 +1,3 @@ +require("babel-core/register")({ + presets: ["es2017"], +}); diff --git a/test/run-chrome-smoketests.sh b/test/run-chrome-smoketests.sh new file mode 100755 index 0000000..f91553e --- /dev/null +++ b/test/run-chrome-smoketests.sh @@ -0,0 +1,21 @@ +echo "\nTest webextension-polyfill from an extension running on chrome" +echo "===============================================" + +export TEST_EXTENSIONS_PATH=/tmp/browser-polyfill-chrome-smoketests + +MARKER_FILE=$TEST_EXTENSIONS_PATH/.created-for-run-chrome-smoketests + +# Check if the marker file exists and then remove the directory. +if [ -f $MARKER_FILE ]; then + rm -fr $TEST_EXTENSIONS_PATH +fi + +## Exits immediately if the directory already exists (which can only happen in a local +## development environment, while this test will usually run on travis). +mkdir $TEST_EXTENSIONS_PATH || exit 1 +touch $MARKER_FILE + +cp -rf test/fixtures/runtime-messaging-extension $TEST_EXTENSIONS_PATH +cp -rf dist/browser-polyfill.js* $TEST_EXTENSIONS_PATH/runtime-messaging-extension/ + +npm run test-integration