code cleanup, better eslint rules and related test configuration

This commit is contained in:
Peter Snyder 2017-10-23 03:29:59 -05:00
parent 5580148632
commit ae18079a67
35 changed files with 195 additions and 151 deletions

5
.eslintignore Normal file
View file

@ -0,0 +1,5 @@
node_modules/
add-on/lib/third_party/
add-on/lib/standards.js
add-on/config/js/third_party/
test.config.js

View file

@ -7,12 +7,22 @@
"mocha": true "mocha": true
}, },
"extends": [ "extends": [
"eslint:recommended" "eslint:recommended"
], ],
"rules": { "rules": {
"no-console": "off", "no-console": "off",
"no-trailing-spaces": "error",
"no-unused-vars": ["error", {"varsIgnorePattern": "ignore"}], "no-unused-vars": ["error", {"varsIgnorePattern": "ignore"}],
"semi": ["error", "always"] "semi": ["error", "always"],
"indent": ["error", 4],
"eol-last": "error",
"quotes": ["error", "double"],
"comma-dangle": ["error", "only-multiline"],
"function-paren-newline": ["error"],
"max-len": ["error", {"ignoreStrings": true, "code": 100}],
"require-jsdoc": "error",
"valid-jsdoc": "error",
"prefer-const": "error",
"no-template-curly-in-string": "error",
"no-unused-expressions": "error"
} }
} }

View file

@ -81,7 +81,8 @@
if (label === "rulesForDomains") { if (label === "rulesForDomains") {
const matchHostNameBound = domainMatcherLib.matchHostName.bind(undefined, Object.keys(domainRules)); const matchHostName = domainMatcherLib.matchHostName;
const matchHostNameBound = matchHostName.bind(undefined, Object.keys(domainRules));
const rulesForDomains = data.map(matchHostNameBound); const rulesForDomains = data.map(matchHostNameBound);
const domainToRuleMapping = {}; const domainToRuleMapping = {};
@ -113,7 +114,7 @@
const newHeaders = details.requestHeaders.map(function (header) { const newHeaders = details.requestHeaders.map(function (header) {
if (header.name.indexOf("Cookie") === -1) { if (header.name.indexOf("Cookie") === -1) {
header; return header;
} }
const cookieValue = header.value; const cookieValue = header.value;

View file

@ -40,7 +40,7 @@
<script src="../lib/defaults.js"></script> <script src="../lib/defaults.js"></script>
<script src="../lib/standards.js"></script> <script src="../lib/standards.js"></script>
<script src="../lib/storage.js"></script> <script src="../lib/storage.js"></script>
<script src="js/lib/vue.js"></script> <script src="js/third_party/vue.js"></script>
<script src="js/state.js"></script> <script src="js/state.js"></script>
<script src="js/components/domain-rules.vue.js"></script> <script src="js/components/domain-rules.vue.js"></script>
<script src="js/components/web-api-standards.vue.js"></script> <script src="js/components/web-api-standards.vue.js"></script>

View file

@ -27,10 +27,15 @@
<div class="form-group" v-bind:class="{ 'has-error': errorMessage }"> <div class="form-group" v-bind:class="{ 'has-error': errorMessage }">
<label for="newDomainName">Add New Domain Rule</label> <label for="newDomainName">Add New Domain Rule</label>
<input class="form-control" v-model.trim="newDomain" placeholder="*.example.org"> <input
class="form-control"
v-model.trim="newDomain"
placeholder="*.example.org">
</div> </div>
<button type="submit" class="btn btn-default btn-block" @click="newDomainSubmitted">Add Rule</button> <button type="submit"
class="btn btn-default btn-block"
@click="newDomainSubmitted">Add Rule</button>
</div> </div>
`, `,
data: function () { data: function () {

View file

@ -10,7 +10,7 @@
const standardsCookieName = constants.cookieName; const standardsCookieName = constants.cookieName;
const doc = window.document; const doc = window.document;
const script = doc.createElement('script'); const script = doc.createElement("script");
const rootElm = doc.head || doc.documentElement; const rootElm = doc.head || doc.documentElement;
// First see if we can read the standards to block out of the cookie // First see if we can read the standards to block out of the cookie

View file

@ -15,12 +15,12 @@
* The `standardsToBlock` array must be a subset of all the standards * The `standardsToBlock` array must be a subset of all the standards
* documented in data/standards. * documented in data/standards.
* *
* @param array standardsToBlock * @param {array} standardsToBlock
* An array of strings, each a standard that should be blocked. * An array of strings, each a standard that should be blocked.
* @param bool shouldLog * @param {boolean} shouldLog
* Whether logging should be enabled. * Whether logging should be enabled.
* *
* @return string * @return {string}
* A cookie safe string encoding the above values. * A cookie safe string encoding the above values.
*/ */
const toCookieValue = function (standardsToBlock, shouldLog) { const toCookieValue = function (standardsToBlock, shouldLog) {
@ -45,10 +45,10 @@
* standard names, and two, a boolean flag of whether the logging option * standard names, and two, a boolean flag of whether the logging option
* is enabled. * is enabled.
* *
* @param string data * @param {string} data
* A string created from `toCookieValue` * A string created from `toCookieValue`
* *
* @return [array, bool] * @return {[array, bool]}
* An array of strings of standard names (representing standards to * An array of strings of standard names (representing standards to
* block), and a boolean describing whether to log blocking * block), and a boolean describing whether to log blocking
* behavior. * behavior.

View file

@ -17,7 +17,7 @@ window.WEB_API_MANAGER.defaults.lite = [
"WebRTC 1.0: Real-time Communication Between Browser", "WebRTC 1.0: Real-time Communication Between Browser",
"WebGL Specification", "WebGL Specification",
"Geometry Interfaces Module Level 1", "Geometry Interfaces Module Level 1",
"Web Notifications", "Web Notifications"
]; ];
window.WEB_API_MANAGER.defaults.conservative = [ window.WEB_API_MANAGER.defaults.conservative = [
@ -35,7 +35,7 @@ window.WEB_API_MANAGER.defaults.conservative = [
"UI Events Specification", "UI Events Specification",
"WebGL Specification", "WebGL Specification",
"Web Audio API", "Web Audio API",
"Scalable Vector Graphics (SVG) 1.1 (Second Edition)", "Scalable Vector Graphics (SVG) 1.1 (Second Edition)"
]; ];
window.WEB_API_MANAGER.defaults.aggressive = window.WEB_API_MANAGER.defaults.conservative.concat([ window.WEB_API_MANAGER.defaults.aggressive = window.WEB_API_MANAGER.defaults.conservative.concat([

View file

@ -6,11 +6,11 @@
const matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; const matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
const escapeStringRegexp = function (aString) { const escapeStringRegexp = function (aString) {
if (typeof aString !== 'string') { if (typeof aString !== "string") {
throw new TypeError('Expected a string'); throw new TypeError("Expected a string");
} }
return aString.replace(matchOperatorsRe, '\\$&'); return aString.replace(matchOperatorsRe, "\\$&");
}; };
// From https://www.npmjs.com/package/matcher // From https://www.npmjs.com/package/matcher
@ -24,19 +24,19 @@
return reCache.get(cacheKey); return reCache.get(cacheKey);
} }
const negated = pattern[0] === '!'; const negated = pattern[0] === "!";
if (negated) { if (negated) {
pattern = pattern.slice(1); pattern = pattern.slice(1);
} }
pattern = escapeStringRegexp(pattern).replace(/\\\*/g, '.*'); pattern = escapeStringRegexp(pattern).replace(/\\\*/g, ".*");
if (negated && shouldNegate) { if (negated && shouldNegate) {
pattern = `(?!${pattern})`; pattern = `(?!${pattern})`;
} }
const re = new RegExp(`^${pattern}$`, 'i'); const re = new RegExp(`^${pattern}$`, "i");
re.negated = negated; re.negated = negated;
reCache.set(cacheKey, re); reCache.set(cacheKey, re);
@ -61,10 +61,23 @@
return prev; return prev;
}; };
const matchHostName = function (domainRegExes, hostName) { /**
// of the URL being requested. * Returns the match patern that matches given host name.
*
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Match_patterns
*
* @param {array} matchPatterns
* An array of strings, each describing a match patern.
* @param {string} hostName
* A string depicting a host name.
*
* @return {string|undefined}
* A match patern string that matches the hostname, or undefined if no
* patterns match.
*/
const matchHostName = function (matchPatterns, hostName) {
const matchingUrlReduceFunctionBound = matchingUrlReduceFunction.bind(undefined, hostName); const matchingUrlReduceFunctionBound = matchingUrlReduceFunction.bind(undefined, hostName);
const matchingPattern = domainRegExes const matchingPattern = matchPatterns
.filter((aRule) => aRule !== defaultKey) .filter((aRule) => aRule !== defaultKey)
.sort() .sort()
.reduce(matchingUrlReduceFunctionBound, undefined); .reduce(matchingUrlReduceFunctionBound, undefined);
@ -72,9 +85,23 @@
return matchingPattern || undefined; return matchingPattern || undefined;
}; };
const matchUrl = function (domainRegExes, url) { /**
* Returns the match patern that matches the host of a given url.
*
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Match_patterns
*
* @param {array} matchPatterns
* An array of strings, each describing a match patern.
* @param {string} url
* A string depicting a url.
*
* @return {string|undefined}
* A match patern string that matches the host portion of the given
* url, or undefined if no patterns match.
*/
const matchUrl = function (matchPatterns, url) {
const hostName = extractHostNameFromUrl(url); const hostName = extractHostNameFromUrl(url);
return matchHostName(domainRegExes, hostName); return matchHostName(matchPatterns, hostName);
}; };
window.WEB_API_MANAGER.domainMatcherLib = { window.WEB_API_MANAGER.domainMatcherLib = {

View file

@ -16,10 +16,10 @@
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/HttpHeaders * @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/HttpHeaders
* @see https://w3c.github.io/webappsec-csp/ * @see https://w3c.github.io/webappsec-csp/
* *
* @param object header * @param {object} header
* An object describing a HTTP header * An object describing a HTTP header
* *
* @return boolean * @return {boolean}
* true if the given object depicts a CSP policy with the above stated * true if the given object depicts a CSP policy with the above stated
* properties, and false in all other cases. * properties, and false in all other cases.
*/ */
@ -63,13 +63,13 @@
* @see https://w3c.github.io/webappsec-csp/#strict-dynamic-usage * @see https://w3c.github.io/webappsec-csp/#strict-dynamic-usage
* @see https://w3c.github.io/webappsec-csp/#grammardef-hash-source * @see https://w3c.github.io/webappsec-csp/#grammardef-hash-source
* *
* @param string cspInstruction * @param {string} cspInstruction
* The value of a HTTP header defining a CSP instruction. * The value of a HTTP header defining a CSP instruction.
* @param string scriptHash * @param {string} scriptHash
* A hash value, in the form of "sha256-<some hash>", that is a valid * A hash value, in the form of "sha256-<some hash>", that is a valid
* hash source description. * hash source description.
* *
* @return string|false * @return {string|false}
* Returns false if the CSP instruction looks malformed (ie we * Returns false if the CSP instruction looks malformed (ie we
* couldn't find either a "script-src" or "default-src" section), * couldn't find either a "script-src" or "default-src" section),
* otherwise, a new value CSP instruction with the given hash allowed. * otherwise, a new value CSP instruction with the given hash allowed.

View file

@ -4,7 +4,13 @@
"use strict"; "use strict";
window.WEB_API_MANAGER = { window.WEB_API_MANAGER = {
constants: { constants: {
// The name of the cookie that will be used to push domain
// configuration information into pages.
cookieName: "_wamtcstandards", cookieName: "_wamtcstandards",
// The value in the packed array of options thats used to
// include the shouldLog option in the in bitfield encoded in
// the above cookie.
shouldLogKey: "shouldLogKey" shouldLogKey: "shouldLogKey"
} }
}; };

View file

@ -18,10 +18,19 @@
const bucketSize = 8; const bucketSize = 8;
/**
* Encodes a buffer (such as a Uint8Array) to a base64 encoded string.
*
* @param {ArrayBuffer} buf
* A buffer of binary data.
*
* @return {string}
* A base64 encoded string.
*/
const bufferToBase64 = function (buf) { const bufferToBase64 = function (buf) {
const binstr = Array.prototype.map.call(buf, function (ch) { const binstr = Array.prototype.map.call(buf, function (ch) {
return String.fromCharCode(ch); return String.fromCharCode(ch);
}).join(''); }).join("");
return window.btoa(binstr); return window.btoa(binstr);
}; };
@ -61,12 +70,12 @@
* *
* This function is the inverse of the `unpack` function from this module. * This function is the inverse of the `unpack` function from this module.
* *
* @param array options * @param {array} options
* An array of all possible options that might need to be encoded. * An array of all possible options that might need to be encoded.
* @param array selected * @param {array} selected
* An array containing zero or more elements from option. * An array containing zero or more elements from option.
* *
* @return string * @return {string}
* A base64 encoded string, which encodes which elements in `options` * A base64 encoded string, which encodes which elements in `options`
* were in the provided `selected` array. * were in the provided `selected` array.
*/ */
@ -83,11 +92,11 @@
for (i = 0; i < numBuckets; i += 1) { for (i = 0; i < numBuckets; i += 1) {
let bitfield = 0; let bitfield = 0;
let currentBucket = binnedOptions[i]; const currentBucket = binnedOptions[i];
for (j = 0; j < currentBucket.length; j += 1) { for (j = 0; j < currentBucket.length; j += 1) {
let currentOption = currentBucket[j]; const currentOption = currentBucket[j];
if (selected.indexOf(currentOption) !== -1) { if (selected.indexOf(currentOption) !== -1) {
bitfield |= 1 << j; bitfield |= 1 << j;
} }
@ -108,13 +117,13 @@
* *
* This function is the inverse of the `pack` function from this module. * This function is the inverse of the `pack` function from this module.
* *
* @param array options * @param {array} options
* An array of all possible options that might need to be encoded. * An array of all possible options that might need to be encoded.
* @param string data * @param {string} data
* A base64 encoded string, generated from the `pack` function in * A base64 encoded string, generated from the `pack` function in
* this module. * this module.
* *
* @return array * @return {array}
* An array of zero or more elements, each of which will be in the * An array of zero or more elements, each of which will be in the
* options array. * options array.
*/ */
@ -131,12 +140,12 @@
let i, j; let i, j;
for (i = 0; i < bitFields.length; i += 1) { for (i = 0; i < bitFields.length; i += 1) {
let currentBitField = bitFields[i]; const currentBitField = bitFields[i];
let currentOptionsBin = binnedOptions[i]; const currentOptionsBin = binnedOptions[i];
for (j = 0; j < bucketSize; j += 1) { for (j = 0; j < bucketSize; j += 1) {
if (currentBitField & (1 << j)) { if (currentBitField & (1 << j)) {
let currentOption = currentOptionsBin[j]; const currentOption = currentOptionsBin[j];
result.push(currentOption); result.push(currentOption);
} }
} }

View file

@ -85,8 +85,7 @@
} }
}; };
let blockingProxy; const blockingProxy = new Proxy(defaultFunction, {
blockingProxy = new Proxy(defaultFunction, {
get: function (ignore, property) { get: function (ignore, property) {
logKeyPath(); logKeyPath();
@ -189,16 +188,16 @@
* but with the window.WEB_API_MANAGER_PAGE object set up * but with the window.WEB_API_MANAGER_PAGE object set up
* correctly to block the desired functions. * correctly to block the desired functions.
* *
* @param object standards * @param {object} standards
* A mapping of standard names to information about those standards. * A mapping of standard names to information about those standards.
* The structure of this object should match whats in data/standards.js * The structure of this object should match whats in data/standards.js
* @param array standardNamesToBlock * @param {array} standardNamesToBlock
* An array of strings, which must be a subset of the keys of the * An array of strings, which must be a subset of the keys of the
* standards object. * standards object.
* @param bool shouldLog * @param {boolean} shouldLog
* Whether to log the behavior of the blocking proxy. * Whether to log the behavior of the blocking proxy.
* *
* @return [string, hash] * @return {[string, string]}
* Returns an array containing two values. First, JavaScript code * Returns an array containing two values. First, JavaScript code
* that instruments the DOM of page's its injected into to render the * that instruments the DOM of page's its injected into to render the
* standardNamesToBlock standards un-reachable, and second, a * standardNamesToBlock standards un-reachable, and second, a

File diff suppressed because one or more lines are too long

View file

@ -37,8 +37,8 @@
{ {
"matches": ["*://*/*"], "matches": ["*://*/*"],
"js": [ "js": [
"lib/vendor/js.cookie.js", "lib/third_party/js.cookie.js",
"lib/vendor/sjcl.js", "lib/third_party/sjcl.js",
"lib/init.js", "lib/init.js",
"lib/standards.js", "lib/standards.js",
"lib/pack.js", "lib/pack.js",
@ -52,8 +52,8 @@
], ],
"background": { "background": {
"scripts": [ "scripts": [
"lib/vendor/URI.js", "lib/third_party/URI.js",
"lib/vendor/sjcl.js", "lib/third_party/sjcl.js",
"lib/init.js", "lib/init.js",
"lib/standards.js", "lib/standards.js",
"lib/pack.js", "lib/pack.js",

View file

@ -9,7 +9,7 @@
const configureButton = doc.getElementById("config-page-link"); const configureButton = doc.getElementById("config-page-link");
const listGroupElm = doc.querySelector("ul.list-group"); const listGroupElm = doc.querySelector("ul.list-group");
const addDomainRuleToListElm = function (hostToRuleMapping, listElm, aHostName) { const addRuleToList = function (hostToRuleMapping, listElm, aHostName) {
const domainRule = hostToRuleMapping[aHostName]; const domainRule = hostToRuleMapping[aHostName];
@ -53,9 +53,9 @@
doc.body.className = "loaded"; doc.body.className = "loaded";
const domainNames = Object.keys(response); const domainNames = Object.keys(response);
const addDomainRuleToListElmBound = addDomainRuleToListElm.bind(undefined, response, listGroupElm); const addRuleToListBound = addRuleToList.bind(undefined, response, listGroupElm);
domainNames.forEach(addDomainRuleToListElmBound); domainNames.forEach(addRuleToListBound);
}); });
} }
); );

View file

@ -1,17 +1,7 @@
const gulp = require("gulp"); const gulp = require("gulp");
const fs = require("fs"); const fs = require("fs");
gulp.task('default', function () { gulp.task("default", function () {
const isLineAComment = function (aLine) {
const lineStartsWithComment = (
aLine.indexOf("// ") === 0 ||
aLine.indexOf("/*") === 0 ||
aLine.indexOf(" */") === 0 ||
aLine.indexOf(" * ") === 0
);
return lineStartsWithComment;
};
const builtScriptComment = "/** This file is automatically generated. **/\n"; const builtScriptComment = "/** This file is automatically generated. **/\n";
const standardsDefDir = "data/standards"; const standardsDefDir = "data/standards";
@ -26,14 +16,20 @@ gulp.task('default', function () {
const fileContents = fs.readFileSync(standardsDefDir + "/" + next, {encoding: "utf8"}); const fileContents = fs.readFileSync(standardsDefDir + "/" + next, {encoding: "utf8"});
const standardContents = JSON.parse(fileContents); const standardContents = JSON.parse(fileContents);
const nameParts = [standardContents.info.name, standardContents.info.subsection_name].filter(part => !!part);
const stdName = standardContents.info.name;
const stdSubName = standardContents.info.subsection_name;
const nameParts = [stdName, stdSubName].filter(part => !!part);
const standardIdentifier = nameParts.join(": ").trim(); const standardIdentifier = nameParts.join(": ").trim();
standardContents.info.identifier = standardIdentifier; standardContents.info.identifier = standardIdentifier;
prev[standardIdentifier] = standardContents; prev[standardIdentifier] = standardContents;
return prev; return prev;
}, {}); }, {});
const renderedStandardsModule = builtScriptComment + `window.WEB_API_MANAGER.standards = ${JSON.stringify(combinedStandards)};`; let renderedStandardsModule = builtScriptComment + "\n";
renderedStandardsModule += "window.WEB_API_MANAGER.standards = ";
renderedStandardsModule += JSON.stringify(combinedStandards) + ";";
fs.writeFileSync("add-on/lib/standards.js", renderedStandardsModule); fs.writeFileSync("add-on/lib/standards.js", renderedStandardsModule);
}); });

2
package-lock.json generated
View file

@ -1,6 +1,6 @@
{ {
"name": "web-api-manager", "name": "web-api-manager",
"version": "0.9.2", "version": "0.9.3",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View file

@ -24,7 +24,8 @@
"clean": "rm -Rf dist/", "clean": "rm -Rf dist/",
"bundle": "gulp && web-ext -s add-on -a dist build --overwrite-dest", "bundle": "gulp && web-ext -s add-on -a dist build --overwrite-dest",
"firefox": "web-ext -s add-on run", "firefox": "web-ext -s add-on run",
"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:lint": "node_modules/eslint/bin/eslint.js .",
"test:lint:fix": "node_modules/eslint/bin/eslint.js --fix .",
"test:func": "npm run clean; npm run bundle && ln -s `ls dist/` dist/webapi_manager.zip && node_modules/mocha/bin/mocha test/functional/*.js", "test:func": "npm run clean; 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" "test": "npm run test:lint && npm run test:func"
}, },

View file

@ -14,7 +14,16 @@ describe("Content-Security-Protocol tests", function () {
const [server, testUrl] = testServer.start(function (headers) { const [server, testUrl] = testServer.start(function (headers) {
// Add the CSP header to every request // Add the CSP header to every request
headers['Content-Security-Protocol'] = "default-src https: data: 'unsafe-inline' 'unsafe-eval'; child-src https: data: blob:; connect-src https: data: blob:; font-src https: data:; img-src https: data: blob:; media-src https: data: blob:; object-src https:; script-src https: data: blob: 'unsafe-inline' 'unsafe-eval'; style-src https: 'unsafe-inline'; block-all-mixed-content; upgrade-insecure-requests; report-uri https://capture.condenastdigital.com/csp/pitchfork;"; const pitchforkCSP = [
"default-src https: data: 'unsafe-inline' 'unsafe-eval';",
"child-src https: data: blob:; connect-src https: data: blob:;",
"font-src https: data:; img-src https: data: blob:;",
"media-src https: data: blob:;",
"object-src https:;",
"script-src https: data: blob: 'unsafe-inline' 'unsafe-eval';",
"style-src https: 'unsafe-inline';",
];
headers["Content-Security-Protocol"] = pitchforkCSP.join(" ");
}); });
const svgTestScript = injected.testSVGTestScript(); const svgTestScript = injected.testSVGTestScript();

View file

@ -21,12 +21,12 @@ module.exports.temporaryAddOnInstallScript = (function () {
const funcToInject = function () { const funcToInject = function () {
const {Components, AddonManager} = window; const {Components, AddonManager} = window;
let fileUtils = Components.utils.import('resource://gre/modules/FileUtils.jsm'); const fileUtils = Components.utils.import("resource://gre/modules/FileUtils.jsm");
let FileUtils = fileUtils.FileUtils; const FileUtils = fileUtils.FileUtils;
let callback = arguments[arguments.length - 1]; const callback = arguments[arguments.length - 1];
Components.utils.import('resource://gre/modules/AddonManager.jsm'); Components.utils.import("resource://gre/modules/AddonManager.jsm");
let listener = { const listener = {
onInstallEnded: function(install, addon) { onInstallEnded: function(install, addon) {
callback([addon.id, 0]); callback([addon.id, 0]);
}, },
@ -39,7 +39,7 @@ module.exports.temporaryAddOnInstallScript = (function () {
} }
}; };
let file = new FileUtils.File(arguments[0]); const file = new FileUtils.File(arguments[0]);
AddonManager.addAddonListener(listener); AddonManager.addAddonListener(listener);
AddonManager.installTemporaryAddon(file).catch(error => { AddonManager.installTemporaryAddon(file).catch(error => {
@ -73,7 +73,7 @@ module.exports.setStandardsAsBlockedScript = (function () {
const funcSource = stripFuncFromSource(funcToInject.toString()); const funcSource = stripFuncFromSource(funcToInject.toString());
return function (standardsToBlock) { return function (standardsToBlock) {
return funcSource.replace('"###REPLACE###"', JSON.stringify(standardsToBlock)); return funcSource.replace("\"###REPLACE###\"", JSON.stringify(standardsToBlock));
}; };
}()); }());

View file

@ -20,7 +20,7 @@ module.exports.start = function (callback) {
const httpServer = http.createServer(function (req, res) { const httpServer = http.createServer(function (req, res) {
let headers = {"Content-Type": "text/html; charset=utf-8"}; const headers = {"Content-Type": "text/html; charset=utf-8"};
if (callback !== undefined) { if (callback !== undefined) {
callback(headers); callback(headers);

View file

@ -49,9 +49,7 @@ module.exports.promiseSetFormAndSubmit = function (driver, values) {
module.exports.promiseAddonButton = function (driver) { module.exports.promiseAddonButton = function (driver) {
driver.setContext(Context.CHROME); driver.setContext(Context.CHROME);
return driver.wait(until.elementLocated( return driver.wait(until.elementLocated(by.css("[tooltiptext='WebAPI Manager']")), 2000);
by.css("[tooltiptext='WebAPI Manager']")
), 2000);
}; };
module.exports.promiseExtensionConfigPage = function (driver) { module.exports.promiseExtensionConfigPage = function (driver) {
@ -68,9 +66,7 @@ module.exports.promiseExtensionConfigPage = function (driver) {
module.exports.promiseAddonConfigButton = function (driver) { module.exports.promiseAddonConfigButton = function (driver) {
driver.setContext(Context.CHROME); driver.setContext(Context.CHROME);
return driver.wait(until.elementLocated( return driver.wait(until.elementLocated(by.id("config-page-link")), 2000);
by.id("config-page-link")
), 2000);
}; };
module.exports.promiseSetBlockingRules = function (driver, standardsToBlock) { module.exports.promiseSetBlockingRules = function (driver, standardsToBlock) {
@ -83,18 +79,18 @@ module.exports.promiseSetBlockingRules = function (driver, standardsToBlock) {
module.exports.promiseGetDriver = function () { module.exports.promiseGetDriver = function () {
let driver = new webdriver.Builder() const driver = new webdriver.Builder()
.forBrowser('firefox') .forBrowser("firefox")
.build(); .build();
driver.setContext(Context.CHROME); driver.setContext(Context.CHROME);
let fileLocation = path.join(process.cwd(), "dist", "webapi_manager.zip"); const fileLocation = path.join(process.cwd(), "dist", "webapi_manager.zip");
// This manually installs the add-on as a temporary add-on. // This manually installs the add-on as a temporary add-on.
// Hopefully selenium/geckodriver will get a way to do this soon: // Hopefully selenium/geckodriver will get a way to do this soon:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1298025 // https://bugzilla.mozilla.org/show_bug.cgi?id=1298025
let installAddOnPromise = driver.executeAsyncScript( const installAddOnPromise = driver.executeAsyncScript(
injectedScripts.temporaryAddOnInstallScript(), injectedScripts.temporaryAddOnInstallScript(),
fileLocation fileLocation
); );

View file

@ -5,7 +5,7 @@ let testParams;
try { try {
testParams = require("../../test.config.js"); testParams = require("../../test.config.js");
} catch (e) { } 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"; throw "Unable to load a test.config.js module in the project root. Copy test.config.example.js to test.config.js.";
} }
const injected = require("./lib/injected"); const injected = require("./lib/injected");
const webdriver = require("selenium-webdriver"); const webdriver = require("selenium-webdriver");
@ -42,15 +42,11 @@ describe("Logging into popular sites", function () {
return driverReference.get("https://github.com/login"); return driverReference.get("https://github.com/login");
}) })
.then(function () { .then(function () {
return driverReference.wait(until.elementLocated( return driverReference.wait(until.elementLocated(by.name("password")), 2000);
by.name("password")
), 2000);
}) })
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues)) .then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
.then(function () { .then(function () {
return driverReference.wait(until.elementLocated( return driverReference.wait(until.elementLocated(by.css("body.logged-in")), 2000);
by.css("body.logged-in")
), 2000);
}) })
.then(function () { .then(function () {
driverReference.quit(); driverReference.quit();
@ -75,15 +71,11 @@ describe("Logging into popular sites", function () {
}) })
.then(() => driverReference.get("https://github.com/login")) .then(() => driverReference.get("https://github.com/login"))
.then(function () { .then(function () {
return driverReference.wait(until.elementLocated( return driverReference.wait(until.elementLocated(by.name("password")), 2000);
by.name("password")
), 2000);
}) })
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues)) .then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
.then(function () { .then(function () {
return driverReference.wait(until.elementLocated( return driverReference.wait(until.elementLocated(by.css("body.logged-in")), 2000);
by.css("body.logged-in")
), 2000);
}) })
.then(() => driverReference.executeAsyncScript(svgTestScript)) .then(() => driverReference.executeAsyncScript(svgTestScript))
.then(function () { .then(function () {
@ -123,15 +115,11 @@ describe("Logging into popular sites", function () {
return driverReference.get("https://www.facebook.com/"); return driverReference.get("https://www.facebook.com/");
}) })
.then(function () { .then(function () {
return driverReference.wait(until.elementsLocated( return driverReference.wait(until.elementsLocated(by.name("email")), 5000);
by.name("email")
), 5000);
}) })
.then(() => utils.promiseSetFormAndSubmit(driverReference, formValues)) .then(() => utils.promiseSetFormAndSubmit(driverReference, formValues))
.then(function () { .then(function () {
return driverReference.wait(until.elementLocated( return driverReference.wait(until.elementLocated(by.css("div[data-click='profile_icon']")), 10000);
by.css("div[data-click='profile_icon']")
), 10000);
}) })
.then(function () { .then(function () {
driverReference.quit(); driverReference.quit();
@ -158,47 +146,38 @@ describe("Logging into popular sites", function () {
it("Log in", function (done) { it("Log in", function (done) {
let driverReference; let driver;
utils.promiseGetDriver() utils.promiseGetDriver()
.then(function (driver) { .then(function (testDriver) {
driverReference = driver; driver = testDriver;
return driverReference.get("https://www.youtube.com"); return driver.get("https://www.youtube.com");
}) })
.then(function () { .then(function () {
return driverReference.wait(until.elementsLocated( return driver.wait(until.elementsLocated(by.css("#buttons ytd-button-renderer a")), 5000);
by.css("#buttons ytd-button-renderer a")
), 5000);
}) })
.then(anchors => anchors[anchors.length - 1].click()) .then(anchors => anchors[anchors.length - 1].click())
.then(() => utils.pause(2000)) .then(() => utils.pause(2000))
.then(function () { .then(function () {
return driverReference.wait(until.elementLocated( return driver.wait(until.elementLocated(by.name("identifier")), 5000);
by.name("identifier")
), 5000);
}) })
.then(identifierElm => driverReference.wait(until.elementIsVisible(identifierElm))) .then(idElm => driver.wait(until.elementIsVisible(idElm)))
.then(identifierElm => identifierElm.sendKeys(testParams.google.username, keys.ENTER)) .then(idElm => idElm.sendKeys(testParams.google.username, keys.ENTER))
.then(() => utils.pause(2000)) .then(() => utils.pause(2000))
.then(function () { .then(function () {
return driverReference.wait(until.elementLocated( return driver.wait(until.elementLocated(by.name("password")), 5000);
by.name("password")
), 5000);
}) })
.then(passwordElm => driverReference.wait(until.elementIsVisible(passwordElm))) .then(passwordElm => driver.wait(until.elementIsVisible(passwordElm)))
.then(passwordElm => passwordElm.sendKeys(testParams.google.password, keys.ENTER)) .then(passwordElm => passwordElm.sendKeys(testParams.google.password, keys.ENTER))
.then(function () { .then(function () {
return driverReference.wait(until.elementLocated( return driver.wait(until.elementLocated(by.css("ytd-app")), 10000);
by.css("ytd-app")
), 10000);
}) })
.then(function () { .then(function () {
driverReference.quit(); driver.quit();
done(); done();
}) })
.catch(function (e) { .catch(function () {
driverReference.quit(); driver.quit();
console.log(e);
done(new Error("Was not able to log in")); done(new Error("Was not able to log in"));
}); });
}); });