diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..9a46ce0 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,17 @@ +{ + "env": { + "browser": true, + "es6": true, + "webextensions": true, + "node": true, + "mocha": true + }, + "extends": [ + "eslint:recommended" + ], + "rules": { + "no-console": "off", + "no-trailing-spaces": "error", + "no-unused-vars": ["error", {"varsIgnorePattern": "ignore"}] + } +} diff --git a/.gitignore b/.gitignore index 6191c8c..f599d7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules/ .DS_Store *.swp - -dist +test.config.js +dist/ diff --git a/add-on/background_scripts/background.js b/add-on/background_scripts/background.js index 616ae70..5002cee 100644 --- a/add-on/background_scripts/background.js +++ b/add-on/background_scripts/background.js @@ -36,7 +36,6 @@ function (allHosts) { if (rootObject.runtime.lastError && !allHosts) { - // rootObject.browserAction.disable(); rootObject.browserAction.setBadgeText({text: "-"}); return; } @@ -49,7 +48,6 @@ text: numFrames, tabId: tabId }); - rootObject.browserAction.enable(); } ); }; @@ -102,7 +100,33 @@ urls: [""], types: ["main_frame", "sub_frame"] }; - const requestOptions = ["blocking", "responseHeaders"]; + + const cookieRemoverRegex = new RegExp(constants.cookieName + "=.*?;"); + + // Make sure we never send the cookie value that contains what + // standards should be blocked to any server, anytime. In the common + // case this will be a NOOP (since the cookie is deleted after being + // read), but there are some inconsitancy / timing situations where + // making multiple, simultanious requests to the same domain where + // we might make a request before deleting the cookie, so the below + // adds at least some (incertain) extra protection. + rootObject.webRequest.onBeforeSendHeaders.addListener(function (details) { + + const newHeaders = details.requestHeaders.map(function (header) { + + if (header.name.indexOf("Cookie") === -1) { + header; + } + + const cookieValue = header.value; + header.value = cookieValue.replace(cookieRemoverRegex, "").trim(); + return header; + }); + + return { + requestHeaders: newHeaders + }; + }, requestFilter, ["blocking", "requestHeaders"]); // Inject the blocking settings for each visited domain / frame. // This needs to be done syncronously, so that the DOM of the visited @@ -152,22 +176,15 @@ } } - // If there is already a set-cookie instruction being issued, - // don't overwrite it, but add our cookie to the end of it. Otherwise, - // create a new set-cookie instruction header. - const pathForCookie = window.URI(details.url).pathname(); - details.responseHeaders.push({ - name: "Set-Cookie", - value: `${constants.cookieName}=${encodedOptions};path=${pathForCookie}` - }); - - details.responseHeaders.forEach((header) => { - console.log(header.name + ": " + header.value); - }); + rootObject.cookies.set({ + url: details.url, + name: constants.cookieName, + value: encodedOptions + }) return { responseHeaders: details.responseHeaders }; - }, requestFilter, requestOptions); + }, requestFilter, ["blocking", "responseHeaders"]); }()); diff --git a/add-on/config/js/state.js b/add-on/config/js/state.js index 17cf6f7..48428be 100644 --- a/add-on/config/js/state.js +++ b/add-on/config/js/state.js @@ -1,10 +1,7 @@ -/*jslint es6: true, this: true*/ -/*global window, browser, Vue*/ (function () { "use strict"; const defaultDomain = "(default)"; - const {packingLib, standards} = window.WEB_API_MANAGER; const generateStateObject = function (initialDomain, standards) { diff --git a/add-on/content_scripts/instrument.js b/add-on/content_scripts/instrument.js index 3807337..65b5696 100644 --- a/add-on/content_scripts/instrument.js +++ b/add-on/content_scripts/instrument.js @@ -14,13 +14,18 @@ const rootElm = doc.head || doc.documentElement; const cookieValue = cookies2.get(standardsCookieName); - console.log(document.cookie); + + if (!cookieValue) { + window.console.log(`Unable to find the Web API Manager settings for ${doc.location.href}`); + return; + } + cookies2.remove(standardsCookieName, {path: window.document.location.pathname}); - console.log(document.cookie); if (!cookieValue) { return; } + const [standardsToBlock, shouldLog] = cookieEncodingLib.fromCookieValue(cookieValue); const [scriptToInject, scriptHash] = proxyBlockLib.generateScriptPayload( diff --git a/add-on/lib/cookieencoding.js b/add-on/lib/cookieencoding.js index a4c3588..7014d4c 100644 --- a/add-on/lib/cookieencoding.js +++ b/add-on/lib/cookieencoding.js @@ -1,5 +1,3 @@ -/*jslint es6: true*/ -/*global window*/ (function () { "use strict"; const {packingLib, standards, constants} = window.WEB_API_MANAGER; @@ -38,7 +36,7 @@ // Last, replace "=" with "-" in the base64 string, to avoid // silly ambiguities in the cookie value. - return packedValues.replace(/\=/g, "-"); + return packedValues.replace(/=/g, "-"); }; /** diff --git a/add-on/lib/domainmatcher.js b/add-on/lib/domainmatcher.js index 35388d0..3ede33b 100644 --- a/add-on/lib/domainmatcher.js +++ b/add-on/lib/domainmatcher.js @@ -11,37 +11,37 @@ if (typeof aString !== 'string') { throw new TypeError('Expected a string'); } - + return aString.replace(matchOperatorsRe, '\\$&'); }; // From https://www.npmjs.com/package/matcher const reCache = new Map(); - + const makeRe = function (pattern, shouldNegate) { const cacheKey = pattern + shouldNegate; - + if (reCache.has(cacheKey)) { return reCache.get(cacheKey); } - + const negated = pattern[0] === '!'; - + if (negated) { pattern = pattern.slice(1); } - + pattern = escapeStringRegexp(pattern).replace(/\\\*/g, '.*'); - + if (negated && shouldNegate) { pattern = `(?!${pattern})`; } - + const re = new RegExp(`^${pattern}$`, 'i'); re.negated = negated; reCache.set(cacheKey, re); - + return re; }; @@ -83,5 +83,4 @@ matchHostName, matchUrl }; - }()); \ No newline at end of file diff --git a/add-on/lib/init.js b/add-on/lib/init.js index 8f067ad..43e488a 100644 --- a/add-on/lib/init.js +++ b/add-on/lib/init.js @@ -5,7 +5,7 @@ "use strict"; window.WEB_API_MANAGER = { constants: { - cookieName: "__wamtc", + cookieName: "_wamtcstandards", shouldLogKey: "shouldLogKey" } }; diff --git a/add-on/lib/proxyblock.js b/add-on/lib/proxyblock.js index 6267e6f..7edd05f 100644 --- a/add-on/lib/proxyblock.js +++ b/add-on/lib/proxyblock.js @@ -109,7 +109,7 @@ logKeyPath(); return blockingProxy; }, - ownKeys: function (ignore) { + ownKeys: function () { return unconfigurablePropNames; }, has: function (ignore, property) { diff --git a/package-lock.json b/package-lock.json index a57a028..690c6c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,6 +72,12 @@ "yauzl": "2.8.0" }, "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, "ansi-styles": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", @@ -92,6 +98,60 @@ "supports-color": "4.5.0" } }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "eslint": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.8.0.tgz", + "integrity": "sha1-Ip7w41Tg5h2DfHqA/fuoJeGZgV4=", + "dev": true, + "requires": { + "ajv": "5.2.3", + "babel-code-frame": "6.26.0", + "chalk": "2.1.0", + "concat-stream": "1.6.0", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.0.0", + "eslint-scope": "3.7.1", + "espree": "3.5.1", + "esquery": "1.0.0", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "9.18.0", + "ignore": "3.3.5", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.0.0", + "js-yaml": "3.10.0", + "json-stable-stringify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "require-uncached": "1.0.3", + "semver": "5.4.1", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + } + }, "first-chunk-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", @@ -101,12 +161,41 @@ "readable-stream": "2.3.3" } }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.3.3", + "path-is-absolute": "1.0.1" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", @@ -137,6 +226,15 @@ "safe-buffer": "5.1.1" } }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, "supports-color": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", @@ -2049,9 +2147,9 @@ } }, "eslint": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.8.0.tgz", - "integrity": "sha1-Ip7w41Tg5h2DfHqA/fuoJeGZgV4=", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.9.0.tgz", + "integrity": "sha1-doedJ0BoJhsZH+Dy9Wx0wvQgjos=", "dev": true, "requires": { "ajv": "5.2.3", diff --git a/package.json b/package.json index a1552ce..571dbf1 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,12 @@ "scripts": { "bundle": "gulp && web-ext -s add-on -a dist build --overwrite-dest", "firefox": "web-ext -s add-on run", - "test": "rm dist/* && npm run bundle && ln -s `ls dist/` dist/webapi_manager.zip && node_modules/mocha/bin/mocha test/functional/*.js" + "test:lint": "node_modules/eslint/bin/eslint.js test/functional/*.js test/functional/**/*.js add-on/background_scripts/*.js add-on/config/js/*.js add-on/config/js/components/*.js add-on/lib/*.js add-on/content_scripts/*.js", + "test:func": "rm dist/* && npm run bundle && ln -s `ls dist/` dist/webapi_manager.zip && node_modules/mocha/bin/mocha test/functional/*.js", + "test": "npm run test:lint && npm run test:func" }, "devDependencies": { + "eslint": "^4.9.0", "geckodriver": "^1.9.0", "gulp": "^3.9.1", "mocha": "^4.0.1", diff --git a/test.config.example.js b/test.config.example.js new file mode 100644 index 0000000..dc6a1f1 --- /dev/null +++ b/test.config.example.js @@ -0,0 +1,16 @@ +// This file contains the parameters needed for the test suite, primarly +// login credentials for sites that should not be shared. +// +// To run the test suite, copy this file to "test.config.js" and +// fill in the below properties. + +module.exports = { + github: { + username: "", + password: "" + }, + google: { + username: "", + password: "" + } +}; \ No newline at end of file diff --git a/test/functional/block.js b/test/functional/block.js index dd6919a..bd239c4 100644 --- a/test/functional/block.js +++ b/test/functional/block.js @@ -1,6 +1,5 @@ "use strict"; -const assert = require("assert"); const http = require("http"); const utils = require("./lib/utils"); const injected = require("./lib/injected"); @@ -40,22 +39,22 @@ describe("Basic", function () { httpServer.close(); }); - describe("Blocking", function () { + describe("blocking", function () { it("SVG Not Blocking", function (done) { const standardsToBlock = []; let driverReference; utils.promiseGetDriver() - .then(function (driver, addonId) { + .then(function (driver) { driverReference = driver; return utils.promiseSetBlockingRules(driver, standardsToBlock); }) - .then(function (result) { - return driverReference.get(testUrl); - }) + .then(() => driverReference.get(testUrl)) + .then(() => driverReference.executeAsyncScript(svgTestScript)) .then(function () { - return driverReference.executeAsyncScript(svgTestScript); + driverReference.quit(); + done(new Error("SVG acted as if it was being blocked")); }) .catch(function () { // Since we're not blocking the SVG API, then the sample @@ -65,24 +64,25 @@ describe("Basic", function () { }); }); - it("SVG Blocking", function (done) { - const standardsToBlock = ["Scalable Vector Graphics (SVG) 1.1 (Second Edition)"]; + it("SVG blocking", function (done) { + + const standardsToBlock = utils.constants.svgBlockRule; let driverReference; - + utils.promiseGetDriver() - .then(function (driver, addonId) { + .then(function (driver) { driverReference = driver; return utils.promiseSetBlockingRules(driver, standardsToBlock); }) - .then(function (result) { - return driverReference.get(testUrl); - }) - .then(function () { - return driverReference.executeAsyncScript(svgTestScript); - }) + .then(() => driverReference.get(testUrl)) + .then(() => driverReference.executeAsyncScript(svgTestScript)) .then(function () { driverReference.quit(); done(); + }) + .catch(function (e) { + driverReference.quit(); + done(e); }); }); }); diff --git a/test/functional/lib/injected.js b/test/functional/lib/injected.js index dce2a7c..d288cfc 100644 --- a/test/functional/lib/injected.js +++ b/test/functional/lib/injected.js @@ -20,28 +20,29 @@ module.exports.temporaryAddOnInstallScript = (function () { const funcToInject = function () { - let fileUtils = Components.utils.import('resource://gre/modules/FileUtils.jsm'); - let FileUtils = fileUtils.FileUtils; - let callback = arguments[arguments.length - 1]; - Components.utils.import('resource://gre/modules/AddonManager.jsm'); + const {Components, AddonManager} = window; + let fileUtils = Components.utils.import('resource://gre/modules/FileUtils.jsm'); + let FileUtils = fileUtils.FileUtils; + let callback = arguments[arguments.length - 1]; + Components.utils.import('resource://gre/modules/AddonManager.jsm'); - let listener = { - onInstallEnded: function(install, addon) { - callback([addon.id, 0]); + let listener = { + onInstallEnded: function(install, addon) { + callback([addon.id, 0]); }, - onInstallFailed: function(install) { - callback([null, install.error]); + onInstallFailed: function(install) { + callback([null, install.error]); }, - onInstalled: function(addon) { - AddonManager.removeAddonListener(listener); - callback([addon.id, 0]); - } + onInstalled: function(addon) { + AddonManager.removeAddonListener(listener); + callback([addon.id, 0]); + } }; - let file = new FileUtils.File(arguments[0]); + let file = new FileUtils.File(arguments[0]); - AddonManager.addAddonListener(listener); - AddonManager.installTemporaryAddon(file).catch(error => { + AddonManager.addAddonListener(listener); + AddonManager.installTemporaryAddon(file).catch(error => { Components.utils.reportError(error); callback([null, error]); }); @@ -84,8 +85,8 @@ module.exports.testSVGTestScript = (function () { }; const funcSource = stripFuncFromSource(funcToInject.toString()); - - return function (standardsToBlock) { + + return function () { return funcSource; - }; + }; }()); \ No newline at end of file diff --git a/test/functional/lib/utils.js b/test/functional/lib/utils.js index b8adce8..c7abbd0 100644 --- a/test/functional/lib/utils.js +++ b/test/functional/lib/utils.js @@ -6,18 +6,51 @@ require("geckodriver"); const firefox = require("selenium-webdriver/firefox"); const webdriver = require("selenium-webdriver"); -const FxRunnerUtils = require("fx-runner/lib/utils"); const injectedScripts = require("./injected"); -const fs = require("fs"); -const By = webdriver.By; +const by = webdriver.By; const Context = firefox.Context; const until = webdriver.until; +const keys = webdriver.Key; const path = require("path"); +module.exports.constants = { + svgBlockRule: ["Scalable Vector Graphics (SVG) 1.1 (Second Edition)"] +}; + +module.exports.pause = function (ms = 2000) { + return new Promise(function (resolve) { + setTimeout(resolve, ms) + }); +}; + +module.exports.promiseSetFormAndSubmit = function (driver, values) { + driver.setContext(Context.CONTENT); + const numberOfPairs = values.length; + + const setFormValue = function (index = 0) { + + const [name, value] = values[index]; + + if (index === numberOfPairs - 1) { + + return driver.findElement(by.name(name)) + .sendKeys(value, keys.ENTER); + + } else { + + return driver.findElement(by.name(name)) + .sendKeys(value) + .then(() => setFormValue(index + 1)); + } + }; + + return setFormValue(); +}; + module.exports.promiseAddonButton = function (driver) { driver.setContext(Context.CHROME); return driver.wait(until.elementLocated( - By.css("[tooltiptext='WebAPI Manager']") + by.css("[tooltiptext='WebAPI Manager']") ), 2000); }; @@ -36,7 +69,7 @@ module.exports.promiseExtensionConfigPage = function (driver) { module.exports.promiseAddonConfigButton = function (driver) { driver.setContext(Context.CHROME); return driver.wait(until.elementLocated( - By.id("config-page-link") + by.id("config-page-link") ), 2000); }; @@ -48,7 +81,7 @@ module.exports.promiseSetBlockingRules = function (driver, standardsToBlock) { .then(driver.executeAsyncScript(setStandardsScript)); }; -module.exports.promiseGetDriver = function (callback) { +module.exports.promiseGetDriver = function () { let driver = new webdriver.Builder() .forBrowser('firefox') @@ -74,6 +107,7 @@ module.exports.promiseGetDriver = function (callback) { }); } + driver.setContext(Context.CONTENT); return Promise.resolve(driver, result[0]); }); }; \ No newline at end of file diff --git a/test/functional/logins.js b/test/functional/logins.js index 6d5ee37..6607092 100644 --- a/test/functional/logins.js +++ b/test/functional/logins.js @@ -1,30 +1,148 @@ "use strict"; -let assert = require("assert"); -let utils = require("./lib/utils"); +const utils = require("./lib/utils"); +let testParams +try { + testParams = require("../../test.config.js"); +} catch (e) { + throw "Unable to load a test.config.js module in the project root. Copy test.config.example.js to test.config.js and try again"; +} +const injected = require("./lib/injected"); +const webdriver = require("selenium-webdriver"); +const keys = webdriver.Key; +const by = webdriver.By; +const until = webdriver.until; -describe("Test logging into popular sites", function () { - this.timeout = function () { - return 10000; - }; +describe("Logging into popular sites", function () { describe("GitHub", function () { - it("Log into site", function (done) { + const formValues = [ + ["login", testParams.github.username], + ["password", testParams.github.password] + ]; + + this.timeout = function () { + return 10000; + }; + + it("Log in", function (done) { + + let driverReference; - const standardsToBlock = ["Beacon"]; - let driver; - utils.promiseGetDriver() - .then(function (driver, addonId) { - driver = driver; - return utils.promiseSetBlockingRules(driver, standardsToBlock); + .then(function (driver) { + driverReference = driver; + return driverReference.get("https://github.com/login"); + }) + .then(function () { + return driverReference.wait(until.elementLocated( + by.name("password") + ), 2000); + }) + .then(() => utils.promiseSetFormAndSubmit(driverReference, formValues)) + .then(function () { + return driverReference.wait(until.elementLocated( + by.css("body.logged-in") + ), 2000); + }) + .then(function () { + driverReference.quit(); + done(); + }) + .catch(function () { + driverReference.quit(); + done(new Error("Was not able to log in")); + }); + }); + + it("Log in with SVG blocking", function (done) { + + const standardsToBlock = utils.constants.svgBlockRule; + const svgTestScript = injected.testSVGTestScript(); + let driverReference; + + utils.promiseGetDriver() + .then(function (driver) { + driverReference = driver; + return utils.promiseSetBlockingRules(driver, standardsToBlock); + }) + .then(() => driverReference.get("https://github.com/login")) + .then(function () { + return driverReference.wait(until.elementLocated( + by.name("password") + ), 2000); + }) + .then(() => utils.promiseSetFormAndSubmit(driverReference, formValues)) + .then(function () { + return driverReference.wait(until.elementLocated( + by.css("body.logged-in") + ), 2000); + }) + .then(() => driverReference.executeAsyncScript(svgTestScript)) + .then(function () { + driverReference.quit(); + done(); + }) + .catch(function (e) { + driverReference.quit(); + done(e); + }); + }); + }); + + describe("YouTube", function () { + + this.timeout = function () { + return 20000; + }; + + it("Log in", function (done) { + + let driverReference; + + utils.promiseGetDriver() + .then(function (driver) { + driverReference = driver; + return driverReference.get("https://www.youtube.com"); + }) + .then(function () { + return driverReference.wait(until.elementsLocated( + by.css("#buttons ytd-button-renderer a") + ), 2000); + }) + .then(anchors => anchors[anchors.length - 1].click()) + .then(() => utils.pause(2000)) + .then(function () { + return driverReference.wait(until.elementLocated( + by.name("identifier") + ), 3000); + }) + .then(identifierElm => driverReference.wait(until.elementIsVisible(identifierElm))) + .then(identifierElm => identifierElm.sendKeys(testParams.google.username, keys.ENTER)) + .then(() => utils.pause(2000)) + .then(function () { + return driverReference.wait(until.elementLocated( + by.name("password") + ), 3000); + }) + .then(passwordElm => driverReference.wait(until.elementIsVisible(passwordElm))) + .then(passwordElm => passwordElm.sendKeys(testParams.google.password, keys.ENTER)) + .then(function () { + return driverReference.wait(until.elementLocated( + by.css("ytd-app") + ), 40000); + }) + .then(function () { + driverReference.quit(); + done(); + }) + .catch(function (e) { + driverReference.quit(); + console.log(e); + done(new Error("Was not able to log in")); }); - // .then(_ => utils.promiseAddonConfigButton(driver)) - // .then(function (configButton) { - // configButton.click(); - // }); }); }); });