mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-09 01:08:39 +09:00
Rename Toolkit's webextensions component directory to better reflect what it is.
This commit is contained in:
parent
6955450f7a
commit
d7d16e7fbb
242 changed files with 4 additions and 2 deletions
35
toolkit/components/webextensions/test/mochitest/.eslintrc.js
Normal file
35
toolkit/components/webextensions/test/mochitest/.eslintrc.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = { // eslint-disable-line no-undef
|
||||
"extends": "../../../../../testing/mochitest/mochitest.eslintrc.js",
|
||||
|
||||
"env": {
|
||||
"webextensions": true,
|
||||
},
|
||||
|
||||
"globals": {
|
||||
"ChromeWorker": false,
|
||||
"onmessage": true,
|
||||
"sendAsyncMessage": false,
|
||||
|
||||
"waitForLoad": true,
|
||||
"promiseConsoleOutput": true,
|
||||
|
||||
"ExtensionTestUtils": false,
|
||||
"NetUtil": true,
|
||||
"webrequest_test": false,
|
||||
"XPCOMUtils": true,
|
||||
|
||||
// head_webrequest.js symbols
|
||||
"addStylesheet": true,
|
||||
"addLink": true,
|
||||
"addImage": true,
|
||||
"addScript": true,
|
||||
"addFrame": true,
|
||||
"makeExtension": false,
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"no-shadow": 0,
|
||||
},
|
||||
};
|
||||
35
toolkit/components/webextensions/test/mochitest/chrome.ini
Normal file
35
toolkit/components/webextensions/test/mochitest/chrome.ini
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
chrome_head.js
|
||||
head.js
|
||||
head_cookies.js
|
||||
file_sample.html
|
||||
webrequest_chromeworker.js
|
||||
webrequest_test.jsm
|
||||
tags = webextensions
|
||||
|
||||
[test_chrome_ext_background_debug_global.html]
|
||||
skip-if = (os == 'android') # android doesn't have devtools
|
||||
[test_chrome_ext_background_page.html]
|
||||
skip-if = (toolkit == 'android') # android doesn't have devtools
|
||||
[test_chrome_ext_eventpage_warning.html]
|
||||
[test_chrome_ext_contentscript_unrecognizedprop_warning.html]
|
||||
skip-if = (os == 'android') # browser.tabs is undefined. Bug 1258975 on android.
|
||||
[test_chrome_ext_hybrid_addons.html]
|
||||
[test_chrome_ext_trustworthy_origin.html]
|
||||
[test_chrome_ext_webnavigation_resolved_urls.html]
|
||||
skip-if = (os == 'android') # browser.tabs is undefined. Bug 1258975 on android.
|
||||
[test_chrome_ext_shutdown_cleanup.html]
|
||||
[test_chrome_native_messaging_paths.html]
|
||||
skip-if = os != "mac" && os != "linux"
|
||||
[test_ext_cookies_expiry.html]
|
||||
[test_ext_cookies_permissions_bad.html]
|
||||
[test_ext_cookies_permissions_good.html]
|
||||
[test_ext_cookies_containers.html]
|
||||
[test_ext_jsversion.html]
|
||||
[test_ext_schema.html]
|
||||
[test_chrome_ext_storage_cleanup.html]
|
||||
[test_chrome_ext_idle.html]
|
||||
[test_chrome_ext_downloads_saveAs.html]
|
||||
[test_chrome_ext_webrequest_background_events.html]
|
||||
skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
const {
|
||||
classes: Cc,
|
||||
interfaces: Ci,
|
||||
utils: Cu,
|
||||
results: Cr,
|
||||
} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<iframe src="file_WebNavigation_page2.html" width="200" height="200"></iframe>
|
||||
|
||||
<form>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<a id="elt" href="file_WebNavigation_page3.html#ref">click me</a>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
"use strict";
|
||||
window.close();
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="test">Sample text</div>
|
||||
<img id="bad-image" src="http://example.org/tests/toolkit/components/extensions/test/mochitest/file_image_bad.png" />
|
||||
<script id="bad-script" type="text/javascript" src="http://example.org/tests/toolkit/components/extensions/test/mochitest/file_script_bad.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1 @@
|
|||
Content-Security-Policy: default-src 'self'
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
var {interfaces: Ci} = Components;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
Services.console.registerListener(function listener(message) {
|
||||
if (/WebExt Privilege Escalation/.test(message.message)) {
|
||||
Services.console.unregisterListener(listener);
|
||||
sendAsyncMessage("console-message", {message: message.message});
|
||||
}
|
||||
});
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 580 B |
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="test">Sample text</div>
|
||||
<img id="bad-image" src="http://example.com/tests/toolkit/components/extensions/test/mochitest/file_image_bad.png" />
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
/* globals privilegedFetch, privilegedXHR */
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
|
||||
addEventListener("message", function rcv(event) {
|
||||
removeEventListener("message", rcv, false);
|
||||
|
||||
function assertTrue(condition, description) {
|
||||
postMessage({msg: "assertTrue", condition, description}, "*");
|
||||
}
|
||||
|
||||
function passListener() {
|
||||
assertTrue(true, "Content XHR has no elevated privileges");
|
||||
postMessage({"msg": "finish"}, "*");
|
||||
}
|
||||
|
||||
function failListener() {
|
||||
assertTrue(false, "Content XHR has no elevated privileges");
|
||||
postMessage({"msg": "finish"}, "*");
|
||||
}
|
||||
|
||||
try {
|
||||
new privilegedXHR();
|
||||
assertTrue(false, "Content should not have access to privileged XHR constructor");
|
||||
} catch (e) {
|
||||
assertTrue(/Permission denied to access object/.test(e), "Content should not have access to privileged XHR constructor");
|
||||
}
|
||||
|
||||
try {
|
||||
new privilegedFetch();
|
||||
assertTrue(false, "Content should not have access to privileged fetch() constructor");
|
||||
} catch (e) {
|
||||
assertTrue(/Permission denied to access object/.test(e), "Content should not have access to privileged fetch() constructor");
|
||||
}
|
||||
|
||||
let req = new XMLHttpRequest();
|
||||
req.addEventListener("load", failListener);
|
||||
req.addEventListener("error", passListener);
|
||||
req.open("GET", "http://example.org/example.txt");
|
||||
req.send();
|
||||
}, false);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
throw new Error(`WebExt Privilege Escalation: typeof(browser) = ${typeof(browser)}`);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="test">Sample text</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
window.failure = true;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
window.success = window.success ? window.success + 1 : 1;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
"use strict";
|
||||
|
||||
window.failure = true;
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("get", "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest/xhr_resource", false);
|
||||
request.send();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
#test {
|
||||
color: green !important;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
#test {
|
||||
color: red;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
#test {
|
||||
color: green !important;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
"use strict";
|
||||
|
||||
/* globals addMessageListener */
|
||||
let {Management} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
|
||||
let events = [];
|
||||
function record(type, extensionContext) {
|
||||
let eventType = type == "proxy-context-load" ? "load" : "unload";
|
||||
let url = extensionContext.uri.spec;
|
||||
let extensionId = extensionContext.extension.id;
|
||||
events.push({eventType, url, extensionId});
|
||||
}
|
||||
|
||||
Management.on("proxy-context-load", record);
|
||||
Management.on("proxy-context-unload", record);
|
||||
addMessageListener("cleanup", () => {
|
||||
Management.off("proxy-context-load", record);
|
||||
Management.off("proxy-context-unload", record);
|
||||
});
|
||||
|
||||
addMessageListener("get-context-events", extensionId => {
|
||||
sendAsyncMessage("context-events", events);
|
||||
events = [];
|
||||
});
|
||||
sendAsyncMessage("chromescript-startup");
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="1;dummy_page.html">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1 @@
|
|||
Refresh: 1;url=dummy_page.html
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<iframe src="file_webNavigation_clientRedirect.html" width="200" height="200"></iframe>
|
||||
|
||||
<form>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<iframe src="redirection.sjs" width="200" height="200"></iframe>
|
||||
|
||||
<form>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<iframe src="file_webNavigation_manualSubframe_page1.html" width="200" height="200"></iframe>
|
||||
|
||||
<form>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<h1>page1</h1>
|
||||
<a href="file_webNavigation_manualSubframe_page2.html">page2</a>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<h1>page2</h1>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="a_b" src="about:blank"></iframe>
|
||||
<iframe srcdoc="galactica actual" src="adama"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
13
toolkit/components/webextensions/test/mochitest/head.js
Normal file
13
toolkit/components/webextensions/test/mochitest/head.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
"use strict";
|
||||
|
||||
/* exported waitForLoad */
|
||||
|
||||
function waitForLoad(win) {
|
||||
return new Promise(resolve => {
|
||||
win.addEventListener("load", function listener() {
|
||||
win.removeEventListener("load", listener, true);
|
||||
resolve();
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
167
toolkit/components/webextensions/test/mochitest/head_cookies.js
Normal file
167
toolkit/components/webextensions/test/mochitest/head_cookies.js
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
/* exported testCookies */
|
||||
|
||||
function* testCookies(options) {
|
||||
// Changing the options object is a bit of a hack, but it allows us to easily
|
||||
// pass an expiration date to the background script.
|
||||
options.expiry = Date.now() / 1000 + 3600;
|
||||
|
||||
async function background(backgroundOptions) {
|
||||
// Ask the parent scope to change some cookies we may or may not have
|
||||
// permission for.
|
||||
let awaitChanges = new Promise(resolve => {
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
browser.test.assertEq("cookies-changed", msg, "browser.test.onMessage");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
let changed = [];
|
||||
browser.cookies.onChanged.addListener(event => {
|
||||
changed.push(`${event.cookie.name}:${event.cause}`);
|
||||
});
|
||||
browser.test.sendMessage("change-cookies");
|
||||
|
||||
|
||||
// Try to access some cookies in various ways.
|
||||
let {url, domain, secure} = backgroundOptions;
|
||||
|
||||
let failures = 0;
|
||||
let tallyFailure = error => {
|
||||
failures++;
|
||||
};
|
||||
|
||||
try {
|
||||
await awaitChanges;
|
||||
|
||||
let cookie = await browser.cookies.get({url, name: "foo"});
|
||||
browser.test.assertEq(backgroundOptions.shouldPass, cookie != null, "should pass == get cookie");
|
||||
|
||||
let cookies = await browser.cookies.getAll({domain});
|
||||
if (backgroundOptions.shouldPass) {
|
||||
browser.test.assertEq(2, cookies.length, "expected number of cookies");
|
||||
} else {
|
||||
browser.test.assertEq(0, cookies.length, "expected number of cookies");
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
browser.cookies.set({url, domain, secure, name: "foo", "value": "baz", expirationDate: backgroundOptions.expiry}).catch(tallyFailure),
|
||||
browser.cookies.set({url, domain, secure, name: "bar", "value": "quux", expirationDate: backgroundOptions.expiry}).catch(tallyFailure),
|
||||
browser.cookies.remove({url, name: "deleted"}),
|
||||
]);
|
||||
|
||||
if (backgroundOptions.shouldPass) {
|
||||
// The order of eviction events isn't guaranteed, so just check that
|
||||
// it's there somewhere.
|
||||
let evicted = changed.indexOf("evicted:evicted");
|
||||
if (evicted < 0) {
|
||||
browser.test.fail("got no eviction event");
|
||||
} else {
|
||||
browser.test.succeed("got eviction event");
|
||||
changed.splice(evicted, 1);
|
||||
}
|
||||
|
||||
browser.test.assertEq("x:explicit,x:overwrite,x:explicit,x:explicit,foo:overwrite,foo:explicit,bar:explicit,deleted:explicit",
|
||||
changed.join(","), "expected changes");
|
||||
} else {
|
||||
browser.test.assertEq("", changed.join(","), "expected no changes");
|
||||
}
|
||||
|
||||
if (!(backgroundOptions.shouldPass || backgroundOptions.shouldWrite)) {
|
||||
browser.test.assertEq(2, failures, "Expected failures");
|
||||
} else {
|
||||
browser.test.assertEq(0, failures, "Expected no failures");
|
||||
}
|
||||
|
||||
browser.test.notifyPass("cookie-permissions");
|
||||
} catch (error) {
|
||||
browser.test.fail(`Error: ${error} :: ${error.stack}`);
|
||||
browser.test.notifyFail("cookie-permissions");
|
||||
}
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"permissions": options.permissions,
|
||||
},
|
||||
|
||||
background: `(${background})(${JSON.stringify(options)})`,
|
||||
});
|
||||
|
||||
|
||||
let cookieSvc = SpecialPowers.Services.cookies;
|
||||
|
||||
let domain = options.domain.replace(/^\.?/, ".");
|
||||
|
||||
// This will be evicted after we add a fourth cookie.
|
||||
cookieSvc.add(domain, "/", "evicted", "bar", options.secure, false, false, options.expiry);
|
||||
// This will be modified by the background script.
|
||||
cookieSvc.add(domain, "/", "foo", "bar", options.secure, false, false, options.expiry);
|
||||
// This will be deleted by the background script.
|
||||
cookieSvc.add(domain, "/", "deleted", "bar", options.secure, false, false, options.expiry);
|
||||
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
yield extension.awaitMessage("change-cookies");
|
||||
cookieSvc.add(domain, "/", "x", "y", options.secure, false, false, options.expiry);
|
||||
cookieSvc.add(domain, "/", "x", "z", options.secure, false, false, options.expiry);
|
||||
cookieSvc.remove(domain, "x", "/", false, {});
|
||||
extension.sendMessage("cookies-changed");
|
||||
|
||||
yield extension.awaitFinish("cookie-permissions");
|
||||
yield extension.unload();
|
||||
|
||||
|
||||
function getCookies(host) {
|
||||
let cookies = [];
|
||||
let enum_ = cookieSvc.getCookiesFromHost(host, {});
|
||||
while (enum_.hasMoreElements()) {
|
||||
cookies.push(enum_.getNext().QueryInterface(SpecialPowers.Ci.nsICookie2));
|
||||
}
|
||||
return cookies.sort((a, b) => String.localeCompare(a.name, b.name));
|
||||
}
|
||||
|
||||
let cookies = getCookies(options.domain);
|
||||
info(`Cookies: ${cookies.map(c => `${c.name}=${c.value}`)}`);
|
||||
|
||||
if (options.shouldPass) {
|
||||
is(cookies.length, 2, "expected two cookies for host");
|
||||
|
||||
is(cookies[0].name, "bar", "correct cookie name");
|
||||
is(cookies[0].value, "quux", "correct cookie value");
|
||||
|
||||
is(cookies[1].name, "foo", "correct cookie name");
|
||||
is(cookies[1].value, "baz", "correct cookie value");
|
||||
} else if (options.shouldWrite) {
|
||||
// Note: |shouldWrite| applies only when |shouldPass| is false.
|
||||
// This is necessary because, unfortunately, websites (and therefore web
|
||||
// extensions) are allowed to write some cookies which they're not allowed
|
||||
// to read.
|
||||
is(cookies.length, 3, "expected three cookies for host");
|
||||
|
||||
is(cookies[0].name, "bar", "correct cookie name");
|
||||
is(cookies[0].value, "quux", "correct cookie value");
|
||||
|
||||
is(cookies[1].name, "deleted", "correct cookie name");
|
||||
|
||||
is(cookies[2].name, "foo", "correct cookie name");
|
||||
is(cookies[2].value, "baz", "correct cookie value");
|
||||
} else {
|
||||
is(cookies.length, 2, "expected two cookies for host");
|
||||
|
||||
is(cookies[0].name, "deleted", "correct second cookie name");
|
||||
|
||||
is(cookies[1].name, "foo", "correct cookie name");
|
||||
is(cookies[1].value, "bar", "correct cookie value");
|
||||
}
|
||||
|
||||
for (let cookie of cookies) {
|
||||
cookieSvc.remove(cookie.host, cookie.name, "/", false, {});
|
||||
}
|
||||
// Make sure we don't silently poison subsequent tests if something goes wrong.
|
||||
is(getCookies(options.domain).length, 0, "cookies cleared");
|
||||
}
|
||||
|
|
@ -0,0 +1,331 @@
|
|||
"use strict";
|
||||
|
||||
let commonEvents = {
|
||||
"onBeforeRequest": [{urls: ["<all_urls>"]}, ["blocking"]],
|
||||
"onBeforeSendHeaders": [{urls: ["<all_urls>"]}, ["blocking", "requestHeaders"]],
|
||||
"onSendHeaders": [{urls: ["<all_urls>"]}, ["requestHeaders"]],
|
||||
"onBeforeRedirect": [{urls: ["<all_urls>"]}],
|
||||
"onHeadersReceived": [{urls: ["<all_urls>"]}, ["blocking", "responseHeaders"]],
|
||||
"onResponseStarted": [{urls: ["<all_urls>"]}],
|
||||
"onCompleted": [{urls: ["<all_urls>"]}, ["responseHeaders"]],
|
||||
"onErrorOccurred": [{urls: ["<all_urls>"]}],
|
||||
};
|
||||
|
||||
function background(events) {
|
||||
let expect;
|
||||
let ignore;
|
||||
let defaultOrigin;
|
||||
|
||||
browser.test.onMessage.addListener((msg, expected) => {
|
||||
if (msg !== "set-expected") {
|
||||
return;
|
||||
}
|
||||
expect = expected.expect;
|
||||
defaultOrigin = expected.origin;
|
||||
ignore = expected.ignore;
|
||||
let promises = [];
|
||||
// Initialize some stuff we'll need in the tests.
|
||||
for (let entry of Object.values(expect)) {
|
||||
// a place for the test infrastructure to store some state.
|
||||
entry.test = {};
|
||||
// Each entry in expected gets a Promise that will be resolved in the
|
||||
// last event for that entry. This will either be onCompleted, or the
|
||||
// last entry if an events list was provided.
|
||||
promises.push(new Promise(resolve => { entry.test.resolve = resolve; }));
|
||||
// If events was left undefined, we're expecting all normal events we're
|
||||
// listening for, exclude onBeforeRedirect and onErrorOccurred
|
||||
if (entry.events === undefined) {
|
||||
entry.events = Object.keys(events).filter(name => name != "onErrorOccurred" && name != "onBeforeRedirect");
|
||||
}
|
||||
if (entry.optional_events === undefined) {
|
||||
entry.optional_events = [];
|
||||
}
|
||||
}
|
||||
// When every expected entry has finished our test is done.
|
||||
Promise.all(promises).then(() => {
|
||||
browser.test.sendMessage("done");
|
||||
});
|
||||
browser.test.sendMessage("continue");
|
||||
});
|
||||
|
||||
// Retrieve the per-file/test expected values.
|
||||
function getExpected(details) {
|
||||
let url = new URL(details.url);
|
||||
let filename;
|
||||
if (url.protocol == "data:") {
|
||||
// pathname is everything after protocol.
|
||||
filename = url.pathname;
|
||||
} else {
|
||||
filename = url.pathname.split("/").pop();
|
||||
}
|
||||
if (ignore && ignore.includes(filename)) {
|
||||
return;
|
||||
}
|
||||
let expected = expect[filename];
|
||||
if (!expected) {
|
||||
browser.test.fail(`unexpected request ${filename}`);
|
||||
return;
|
||||
}
|
||||
// Save filename for redirect verification.
|
||||
expected.test.filename = filename;
|
||||
return expected;
|
||||
}
|
||||
|
||||
// Process any test header modifications that can happen in request or response phases.
|
||||
// If a test includes headers, it needs a complete header object, no undefined
|
||||
// objects even if empty:
|
||||
// request: {
|
||||
// add: {"HeaderName": "value",},
|
||||
// modify: {"HeaderName": "value",},
|
||||
// remove: ["HeaderName",],
|
||||
// },
|
||||
// response: {
|
||||
// add: {"HeaderName": "value",},
|
||||
// modify: {"HeaderName": "value",},
|
||||
// remove: ["HeaderName",],
|
||||
// },
|
||||
function processHeaders(phase, expected, details) {
|
||||
// This should only happen once per phase [request|response].
|
||||
browser.test.assertFalse(!!expected.test[phase], `First processing of headers for ${phase}`);
|
||||
expected.test[phase] = true;
|
||||
|
||||
let headers = details[`${phase}Headers`];
|
||||
browser.test.assertTrue(Array.isArray(headers), `${phase}Headers array present`);
|
||||
|
||||
let {add, modify, remove} = expected.headers[phase];
|
||||
|
||||
for (let name in add) {
|
||||
browser.test.assertTrue(!headers.find(h => h.name === name), `header ${name} to be added not present yet in ${phase}Headers`);
|
||||
let header = {name: name};
|
||||
if (name.endsWith("-binary")) {
|
||||
header.binaryValue = Array.from(add[name], c => c.charCodeAt(0));
|
||||
} else {
|
||||
header.value = add[name];
|
||||
}
|
||||
headers.push(header);
|
||||
}
|
||||
|
||||
let modifiedAny = false;
|
||||
for (let header of headers) {
|
||||
if (header.name.toLowerCase() in modify) {
|
||||
header.value = modify[header.name.toLowerCase()];
|
||||
modifiedAny = true;
|
||||
}
|
||||
}
|
||||
browser.test.assertTrue(modifiedAny, `at least one ${phase}Headers element to modify`);
|
||||
|
||||
let deletedAny = false;
|
||||
for (let j = headers.length; j-- > 0;) {
|
||||
if (remove.includes(headers[j].name.toLowerCase())) {
|
||||
headers.splice(j, 1);
|
||||
deletedAny = true;
|
||||
}
|
||||
}
|
||||
browser.test.assertTrue(deletedAny, `at least one ${phase}Headers element to delete`);
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
// phase is request or response.
|
||||
function checkHeaders(phase, expected, details) {
|
||||
if (!/^https?:/.test(details.url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let headers = details[`${phase}Headers`];
|
||||
browser.test.assertTrue(Array.isArray(headers), `valid ${phase}Headers array`);
|
||||
|
||||
let {add, modify, remove} = expected.headers[phase];
|
||||
for (let name in add) {
|
||||
let value = headers.find(h => h.name.toLowerCase() === name.toLowerCase()).value;
|
||||
browser.test.assertEq(value, add[name], `header ${name} correctly injected in ${phase}Headers`);
|
||||
}
|
||||
|
||||
for (let name in modify) {
|
||||
let value = headers.find(h => h.name.toLowerCase() === name.toLowerCase()).value;
|
||||
browser.test.assertEq(value, modify[name], `header ${name} matches modified value`);
|
||||
}
|
||||
|
||||
for (let name of remove) {
|
||||
let found = headers.find(h => h.name.toLowerCase() === name.toLowerCase());
|
||||
browser.test.assertFalse(!!found, `deleted header ${name} still found in ${phase}Headers`);
|
||||
}
|
||||
}
|
||||
|
||||
function getListener(name) {
|
||||
return details => {
|
||||
let result = {};
|
||||
browser.test.log(`${name} ${details.requestId} ${details.url}`);
|
||||
let expected = getExpected(details);
|
||||
if (!expected) {
|
||||
return result;
|
||||
}
|
||||
let expectedEvent = expected.events[0] == name;
|
||||
if (expectedEvent) {
|
||||
expected.events.shift();
|
||||
} else {
|
||||
expectedEvent = expected.optional_events[0] == name;
|
||||
if (expectedEvent) {
|
||||
expected.optional_events.shift();
|
||||
}
|
||||
}
|
||||
browser.test.assertTrue(expectedEvent, `received ${name}`);
|
||||
browser.test.assertEq(expected.type, details.type, "resource type is correct");
|
||||
browser.test.assertEq(expected.origin || defaultOrigin, details.originUrl, "origin is correct");
|
||||
|
||||
if (name == "onBeforeRequest") {
|
||||
// Save some values to test request consistency in later events.
|
||||
browser.test.assertTrue(details.tabId !== undefined, `tabId ${details.tabId}`);
|
||||
browser.test.assertTrue(details.requestId !== undefined, `requestId ${details.requestId}`);
|
||||
// Validate requestId if it's already set, this happens with redirects.
|
||||
if (expected.test.requestId !== undefined) {
|
||||
browser.test.assertEq("string", typeof expected.test.requestId, `requestid ${expected.test.requestId} is string`);
|
||||
browser.test.assertEq("string", typeof details.requestId, `requestid ${details.requestId} is string`);
|
||||
browser.test.assertEq("number", typeof parseInt(details.requestId, 10), "parsed requestid is number");
|
||||
browser.test.assertNotEq(expected.test.requestId, details.requestId,
|
||||
`last requestId ${expected.test.requestId} different from this one ${details.requestId}`);
|
||||
} else {
|
||||
// Save any values we want to validate in later events.
|
||||
expected.test.requestId = details.requestId;
|
||||
expected.test.tabId = details.tabId;
|
||||
}
|
||||
// Tests we don't need to do every event.
|
||||
browser.test.assertTrue(details.type.toUpperCase() in browser.webRequest.ResourceType, `valid resource type ${details.type}`);
|
||||
if (details.type == "main_frame") {
|
||||
browser.test.assertEq(0, details.frameId, "frameId is zero when type is main_frame bug 1329299");
|
||||
}
|
||||
} else {
|
||||
// On events after onBeforeRequest, check the previous values.
|
||||
browser.test.assertEq(expected.test.requestId, details.requestId, "correct requestId");
|
||||
browser.test.assertEq(expected.test.tabId, details.tabId, "correct tabId");
|
||||
}
|
||||
if (name == "onBeforeSendHeaders") {
|
||||
if (expected.headers && expected.headers.request) {
|
||||
result.requestHeaders = processHeaders("request", expected, details);
|
||||
}
|
||||
if (expected.redirect) {
|
||||
browser.test.log(`${name} redirect request`);
|
||||
result.redirectUrl = details.url.replace(expected.test.filename, expected.redirect);
|
||||
}
|
||||
}
|
||||
if (name == "onSendHeaders") {
|
||||
if (expected.headers && expected.headers.request) {
|
||||
checkHeaders("request", expected, details);
|
||||
}
|
||||
}
|
||||
if (name == "onHeadersReceived") {
|
||||
browser.test.assertEq(expected.status || 200, details.statusCode,
|
||||
`expected HTTP status received for ${details.url}`);
|
||||
if (expected.headers && expected.headers.response) {
|
||||
result.responseHeaders = processHeaders("response", expected, details);
|
||||
}
|
||||
}
|
||||
if (name == "onCompleted") {
|
||||
// If we have already completed a GET request for this url,
|
||||
// and it was found, we expect for the response to come fromCache.
|
||||
// expected.cached may be undefined, force boolean.
|
||||
let expectCached = !!expected.cached && details.method === "GET" && details.statusCode != 404;
|
||||
browser.test.assertEq(expectCached, details.fromCache, "fromCache is correct");
|
||||
// We can only tell IPs for non-cached HTTP requests.
|
||||
if (!details.fromCache && /^https?:/.test(details.url)) {
|
||||
browser.test.assertEq("127.0.0.1", details.ip, `correct ip for ${details.url}`);
|
||||
}
|
||||
if (expected.headers && expected.headers.response) {
|
||||
checkHeaders("response", expected, details);
|
||||
}
|
||||
}
|
||||
|
||||
if (expected.cancel && expected.cancel == name) {
|
||||
browser.test.log(`${name} cancel request`);
|
||||
browser.test.sendMessage("cancelled");
|
||||
result.cancel = true;
|
||||
}
|
||||
// If we've used up all the events for this test, resolve the promise.
|
||||
// If something wrong happens and more events come through, there will be
|
||||
// failures.
|
||||
if (expected.events.length <= 0) {
|
||||
expected.test.resolve();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
for (let [name, args] of Object.entries(events)) {
|
||||
browser.test.log(`adding listener for ${name}`);
|
||||
try {
|
||||
browser.webRequest[name].addListener(getListener(name), ...args);
|
||||
} catch (e) {
|
||||
browser.test.assertTrue(/\brequestBody\b/.test(e.message),
|
||||
"Request body is unsupported");
|
||||
|
||||
// RequestBody is disabled in release builds.
|
||||
if (!/\brequestBody\b/.test(e.message)) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
args.splice(args.indexOf("requestBody"), 1);
|
||||
browser.webRequest[name].addListener(getListener(name), ...args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* exported makeExtension */
|
||||
|
||||
function makeExtension(events = commonEvents) {
|
||||
return ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: [
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
"<all_urls>",
|
||||
],
|
||||
},
|
||||
background: `(${background})(${JSON.stringify(events)})`,
|
||||
});
|
||||
}
|
||||
|
||||
/* exported addStylesheet */
|
||||
|
||||
function addStylesheet(file) {
|
||||
let link = document.createElement("link");
|
||||
link.setAttribute("rel", "stylesheet");
|
||||
link.setAttribute("href", file);
|
||||
document.body.appendChild(link);
|
||||
}
|
||||
|
||||
/* exported addLink */
|
||||
|
||||
function addLink(file) {
|
||||
let a = document.createElement("a");
|
||||
a.setAttribute("href", file);
|
||||
a.setAttribute("target", "_blank");
|
||||
document.body.appendChild(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
/* exported addImage */
|
||||
|
||||
function addImage(file) {
|
||||
let img = document.createElement("img");
|
||||
img.setAttribute("src", file);
|
||||
document.body.appendChild(img);
|
||||
}
|
||||
|
||||
/* exported addScript */
|
||||
|
||||
function addScript(file) {
|
||||
let script = document.createElement("script");
|
||||
script.setAttribute("type", "text/javascript");
|
||||
script.setAttribute("src", file);
|
||||
document.getElementsByTagName("head").item(0).appendChild(script);
|
||||
}
|
||||
|
||||
/* exported addFrame */
|
||||
|
||||
function addFrame(file) {
|
||||
let frame = document.createElement("iframe");
|
||||
frame.setAttribute("width", "200");
|
||||
frame.setAttribute("height", "200");
|
||||
frame.setAttribute("src", file);
|
||||
document.body.appendChild(frame);
|
||||
}
|
||||
114
toolkit/components/webextensions/test/mochitest/mochitest.ini
Normal file
114
toolkit/components/webextensions/test/mochitest/mochitest.ini
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
file_mixed.html
|
||||
head_webrequest.js
|
||||
file_csp.html
|
||||
file_csp.html^headers^
|
||||
file_WebRequest_page3.html
|
||||
file_webNavigation_clientRedirect.html
|
||||
file_webNavigation_clientRedirect_httpHeaders.html
|
||||
file_webNavigation_clientRedirect_httpHeaders.html^headers^
|
||||
file_webNavigation_frameClientRedirect.html
|
||||
file_webNavigation_frameRedirect.html
|
||||
file_webNavigation_manualSubframe.html
|
||||
file_webNavigation_manualSubframe_page1.html
|
||||
file_webNavigation_manualSubframe_page2.html
|
||||
file_WebNavigation_page1.html
|
||||
file_WebNavigation_page2.html
|
||||
file_WebNavigation_page3.html
|
||||
file_with_about_blank.html
|
||||
file_image_good.png
|
||||
file_image_bad.png
|
||||
file_image_redirect.png
|
||||
file_style_good.css
|
||||
file_style_bad.css
|
||||
file_style_redirect.css
|
||||
file_script_good.js
|
||||
file_script_bad.js
|
||||
file_script_redirect.js
|
||||
file_script_xhr.js
|
||||
file_sample.html
|
||||
redirection.sjs
|
||||
file_privilege_escalation.html
|
||||
file_ext_test_api_injection.js
|
||||
file_permission_xhr.html
|
||||
file_teardown_test.js
|
||||
return_headers.sjs
|
||||
webrequest_worker.js
|
||||
tags = webextensions
|
||||
|
||||
[test_clipboard.html]
|
||||
# skip-if = # disabled test case with_permission_allow_copy, see inline comment.
|
||||
[test_ext_inIncognitoContext_window.html]
|
||||
skip-if = os == 'android' # Android does not currently support windows.
|
||||
[test_ext_geturl.html]
|
||||
[test_ext_background_canvas.html]
|
||||
[test_ext_content_security_policy.html]
|
||||
[test_ext_contentscript.html]
|
||||
[test_ext_contentscript_api_injection.html]
|
||||
[test_ext_contentscript_async_loading.html]
|
||||
[test_ext_contentscript_context.html]
|
||||
[test_ext_contentscript_create_iframe.html]
|
||||
[test_ext_contentscript_devtools_metadata.html]
|
||||
[test_ext_contentscript_exporthelpers.html]
|
||||
[test_ext_contentscript_css.html]
|
||||
[test_ext_contentscript_about_blank.html]
|
||||
[test_ext_contentscript_permission.html]
|
||||
skip-if = os == 'android' # Android does not support tabs API. Bug 1260250
|
||||
[test_ext_contentscript_teardown.html]
|
||||
skip-if = (os == 'android') # Android does not support tabs API. Bug 1260250
|
||||
[test_ext_exclude_include_globs.html]
|
||||
[test_ext_i18n_css.html]
|
||||
[test_ext_generate.html]
|
||||
[test_ext_notifications.html]
|
||||
[test_ext_permission_xhr.html]
|
||||
[test_ext_runtime_connect.html]
|
||||
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
|
||||
[test_ext_runtime_connect_twoway.html]
|
||||
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
|
||||
[test_ext_runtime_connect2.html]
|
||||
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
|
||||
[test_ext_runtime_disconnect.html]
|
||||
[test_ext_runtime_id.html]
|
||||
[test_ext_sandbox_var.html]
|
||||
[test_ext_sendmessage_reply.html]
|
||||
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
|
||||
[test_ext_sendmessage_reply2.html]
|
||||
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
|
||||
[test_ext_sendmessage_doublereply.html]
|
||||
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
|
||||
[test_ext_sendmessage_no_receiver.html]
|
||||
[test_ext_storage_content.html]
|
||||
[test_ext_storage_tab.html]
|
||||
skip-if = os == 'android' # Android does not currently support tabs.
|
||||
[test_ext_test.html]
|
||||
[test_ext_cookies.html]
|
||||
skip-if = os == 'android' # Bug 1258975 on android.
|
||||
[test_ext_background_api_injection.html]
|
||||
[test_ext_background_generated_url.html]
|
||||
[test_ext_background_teardown.html]
|
||||
[test_ext_tab_teardown.html]
|
||||
skip-if = (os == 'android') # Android does not support tabs API. Bug 1260250
|
||||
[test_ext_unload_frame.html]
|
||||
[test_ext_i18n.html]
|
||||
skip-if = (os == 'android') # Bug 1258975 on android.
|
||||
[test_ext_listener_proxies.html]
|
||||
[test_ext_web_accessible_resources.html]
|
||||
skip-if = (os == 'android') # Bug 1258975 on android.
|
||||
[test_ext_webrequest_background_events.html]
|
||||
skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
|
||||
[test_ext_webrequest_basic.html]
|
||||
skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
|
||||
[test_ext_webrequest_suspend.html]
|
||||
skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
|
||||
[test_ext_webrequest_upload.html]
|
||||
skip-if = release_or_beta || os == 'android' # webrequest api unsupported (bug 1258975).
|
||||
[test_ext_webnavigation.html]
|
||||
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
|
||||
[test_ext_webnavigation_filters.html]
|
||||
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
|
||||
[test_ext_window_postMessage.html]
|
||||
[test_ext_subframes_privileges.html]
|
||||
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
|
||||
[test_ext_xhr_capabilities.html]
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
function handleRequest(aRequest, aResponse) {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 302);
|
||||
aResponse.setHeader("Location", "./dummy_page.html");
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
/* exported handleRequest */
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
|
||||
let headers = {};
|
||||
// Why on earth is this a nsISimpleEnumerator...
|
||||
let enumerator = request.headers;
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let header = enumerator.getNext().data;
|
||||
headers[header.toLowerCase()] = request.getHeader(header);
|
||||
}
|
||||
|
||||
response.write(JSON.stringify(headers));
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm");
|
||||
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
const {
|
||||
XPIProvider,
|
||||
} = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm");
|
||||
|
||||
/**
|
||||
* This test is asserting that ext-backgroundPage.js successfully sets its
|
||||
* debug global in the AddonWrapper provided by XPIProvider.jsm
|
||||
*
|
||||
* It does _not_ test any functionality in devtools and does not guarantee
|
||||
* debugging is actually working correctly end-to-end.
|
||||
*/
|
||||
|
||||
function background() {
|
||||
window.testThing = "test!";
|
||||
browser.test.notifyPass("background script ran");
|
||||
}
|
||||
|
||||
const ID = "debug@tests.mozilla.org";
|
||||
let extensionData = {
|
||||
useAddonManager: "temporary",
|
||||
background,
|
||||
manifest: {
|
||||
applications: {gecko: {id: ID}},
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* () {
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
yield extension.awaitFinish("background script ran");
|
||||
|
||||
yield new Promise(function(resolve) {
|
||||
window.BrowserToolboxProcess.emit("connectionchange", "opened", {
|
||||
setAddonOptions(id, options) {
|
||||
if (id === ID) {
|
||||
let context = Cu.waiveXrays(options.global);
|
||||
ok(context.chrome, "global context has a chrome object");
|
||||
ok(context.browser, "global context has a browser object");
|
||||
is("test!", context.testThing, "global context is the background script context");
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
let addon = yield new Promise((resolve, reject) => {
|
||||
AddonManager.getAddonByID(ID, addon => addon ? resolve(addon) : reject());
|
||||
});
|
||||
|
||||
ok(addon, `Got the addon wrapper for ${addon.id}`);
|
||||
|
||||
function waitForDebugGlobalChanges(times, initialAddonInstanceID) {
|
||||
return new Promise((resolve) => {
|
||||
AddonManager.addAddonListener({
|
||||
count: 0,
|
||||
notNullGlobalsCount: 0,
|
||||
undefinedPrivateWrappersCount: 0,
|
||||
lastAddonInstanceID: initialAddonInstanceID,
|
||||
onPropertyChanged(newAddon, changedPropNames) {
|
||||
if (newAddon.id != addon.id ||
|
||||
!changedPropNames.includes("debugGlobal")) {
|
||||
return;
|
||||
}
|
||||
|
||||
ok(!(newAddon.setDebugGlobal) && !(newAddon.getDebugGlobal),
|
||||
"The addon wrapper should not be a PrivateWrapper");
|
||||
|
||||
let activeAddon = XPIProvider.activeAddons.get(addon.id);
|
||||
|
||||
let addonInstanceID;
|
||||
|
||||
if (!activeAddon) {
|
||||
// The addon has been disable, the preferred global should be null
|
||||
addonInstanceID = this.lastAddonInstanceID;
|
||||
delete this.lastAddonInstanceID;
|
||||
} else {
|
||||
addonInstanceID = activeAddon.instanceID;
|
||||
this.lastAddonInstanceID = addonInstanceID;
|
||||
}
|
||||
|
||||
ok(addonInstanceID, `Got the addon instanceID for ${addon.id}`);
|
||||
|
||||
AddonManager.getAddonByInstanceID(addonInstanceID).then((privateWrapper) => {
|
||||
this.count += 1;
|
||||
|
||||
if (!privateWrapper) {
|
||||
// The addon has been uninstalled
|
||||
this.undefinedPrivateWrappersCount += 1;
|
||||
} else {
|
||||
ok((privateWrapper.getDebugGlobal), "Got the addon PrivateWrapper");
|
||||
|
||||
if (privateWrapper.getDebugGlobal()) {
|
||||
this.notNullGlobalsCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.count == times) {
|
||||
AddonManager.removeAddonListener(this);
|
||||
resolve({
|
||||
counters: {
|
||||
count: this.count,
|
||||
notNullGlobalsCount: this.notNullGlobalsCount,
|
||||
undefinedPrivateWrappersCount: this.undefinedPrivateWrappersCount,
|
||||
},
|
||||
lastAddonInstanceID: this.lastAddonInstanceID,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// two calls expected, one for the shutdown and one for the startup
|
||||
// of the background page.
|
||||
let waitForDebugGlobalChangesOnReload = waitForDebugGlobalChanges(2);
|
||||
|
||||
info("Addon reload...");
|
||||
yield addon.reload();
|
||||
|
||||
info("Addon completed startup after reload");
|
||||
|
||||
let {
|
||||
counters: reloadCounters,
|
||||
lastAddonInstanceID,
|
||||
} = yield waitForDebugGlobalChangesOnReload;
|
||||
|
||||
isDeeply(reloadCounters, {count: 2, notNullGlobalsCount: 1, undefinedPrivateWrappersCount: 0},
|
||||
"Got the expected number of onPropertyChanged calls on reload");
|
||||
|
||||
// one more call expected for the shutdown.
|
||||
let waitForDebugGlobalChangesOnShutdown = waitForDebugGlobalChanges(1, lastAddonInstanceID);
|
||||
|
||||
info("extension unloading...");
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
|
||||
let {counters: unloadCounters} = yield waitForDebugGlobalChangesOnShutdown;
|
||||
|
||||
isDeeply(unloadCounters, {count: 1, notNullGlobalsCount: 0, undefinedPrivateWrappersCount: 1},
|
||||
"Got the expected number of onPropertyChanged calls on shutdown");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/TestUtils.jsm");
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
|
||||
add_task(function* testAlertNotShownInBackgroundWindow() {
|
||||
ok(!Services.wm.getEnumerator("alert:alert").hasMoreElements(),
|
||||
"Alerts should not be present at the start of the test.");
|
||||
|
||||
let consoleOpened = TestUtils.topicObserved("web-console-created");
|
||||
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: function() {
|
||||
browser.test.log("background script executed");
|
||||
|
||||
alert("I am an alert in the background.");
|
||||
|
||||
browser.test.notifyPass("alertCalled");
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
info("startup complete loaded");
|
||||
|
||||
yield extension.awaitFinish("alertCalled");
|
||||
|
||||
|
||||
let alertWindows = Services.wm.getEnumerator("alert:alert");
|
||||
ok(!alertWindows.hasMoreElements(), "Should not show alert");
|
||||
|
||||
|
||||
// Make sure the message we output to the console is seen.
|
||||
// This message is in ext-backgroundPage.js
|
||||
let events = Cc["@mozilla.org/consoleAPI-storage;1"]
|
||||
.getService(Ci.nsIConsoleAPIStorage).getEvents();
|
||||
|
||||
// This is the warning that is output after the first `alert()` call is made.
|
||||
let alertWarningEvent = events[events.length - 2];
|
||||
is(alertWarningEvent.arguments[0], "alert() is not supported in background windows; please use console.log instead.");
|
||||
|
||||
// This is the actual alert text that should be present in the console
|
||||
// instead of as an `alert`.
|
||||
let alertEvent = events[events.length - 1];
|
||||
is(alertEvent.arguments[0], "I am an alert in the background.");
|
||||
|
||||
|
||||
// Wait for the browser console window to open.
|
||||
yield consoleOpened;
|
||||
|
||||
let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
require("devtools/client/framework/devtools-browser");
|
||||
let hudservice = require("devtools/client/webconsole/hudservice");
|
||||
|
||||
// And then double check that we have an actual browser console.
|
||||
let haveConsole = !!hudservice.getBrowserConsole();
|
||||
ok(haveConsole, "Expected browser console to be open");
|
||||
|
||||
if (haveConsole) {
|
||||
yield hudservice.toggleBrowserConsole();
|
||||
}
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script unrecognized property on manifest</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
const BASE = "http://mochi.test:8888/chrome/toolkit/components/extensions/test/mochitest";
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener(async (msg) => {
|
||||
if (msg == "loaded") {
|
||||
// NOTE: we're removing the tab from here because doing a win.close()
|
||||
// from the chrome test code is raising a "TypeError: can't access
|
||||
// dead object" exception.
|
||||
let tabs = await browser.tabs.query({active: true, currentWindow: true});
|
||||
await browser.tabs.remove(tabs[0].id);
|
||||
|
||||
browser.test.notifyPass("content-script-loaded");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
chrome.runtime.sendMessage("loaded");
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
"unrecognized_property": "with-a-random-value",
|
||||
},
|
||||
],
|
||||
},
|
||||
background,
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
let waitForConsole = new Promise(resolve => {
|
||||
SimpleTest.monitorConsole(resolve, [{
|
||||
message: /Reading manifest: Error processing content_scripts.*.unrecognized_property: An unexpected property was found/,
|
||||
}]);
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
window.open(`${BASE}/file_sample.html`);
|
||||
|
||||
yield Promise.all([extension.awaitFinish("content-script-loaded")]);
|
||||
info("test page loaded");
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
SimpleTest.endMonitorConsole();
|
||||
yield waitForConsole;
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test downloads.download() saveAs option</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_downloads_saveAs() {
|
||||
function background() {
|
||||
const url = URL.createObjectURL(new Blob(["file content"]));
|
||||
browser.test.onMessage.addListener(async () => {
|
||||
try {
|
||||
let id = await browser.downloads.download({url, saveAs: true});
|
||||
browser.downloads.onChanged.addListener(delta => {
|
||||
if (delta.state.current === "complete") {
|
||||
browser.test.sendMessage("done", {ok: true, id});
|
||||
}
|
||||
});
|
||||
} catch ({message}) {
|
||||
browser.test.sendMessage("done", {ok: false, message});
|
||||
}
|
||||
});
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
|
||||
const {MockFilePicker} = SpecialPowers;
|
||||
const manifest = {background, manifest: {permissions: ["downloads"]}};
|
||||
const extension = ExtensionTestUtils.loadExtension(manifest);
|
||||
|
||||
MockFilePicker.init(window);
|
||||
MockFilePicker.useAnyFile();
|
||||
const [file] = MockFilePicker.returnFiles;
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
extension.sendMessage("download");
|
||||
let result = yield extension.awaitMessage("done");
|
||||
|
||||
ok(result.ok, "downloads.download() works with saveAs");
|
||||
is(file.fileSize, 12, "downloaded file is the correct size");
|
||||
file.remove(false);
|
||||
|
||||
// Test the user canceling the save dialog.
|
||||
MockFilePicker.returnValue = MockFilePicker.returnCancel;
|
||||
|
||||
extension.sendMessage("download");
|
||||
result = yield extension.awaitMessage("done");
|
||||
|
||||
ok(!result.ok, "download rejected if the user cancels the dialog");
|
||||
is(result.message, "Download canceled by the user", "with the correct message");
|
||||
ok(!file.exists(), "file was not downloaded");
|
||||
|
||||
yield extension.unload();
|
||||
MockFilePicker.cleanup();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for WebExtension EventPage Warning</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function createEventPageExtension(eventPage) {
|
||||
function eventPageScript() {
|
||||
browser.test.log("running event page as background script");
|
||||
browser.test.sendMessage("running", 1);
|
||||
}
|
||||
|
||||
return ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"background": eventPage,
|
||||
},
|
||||
files: {
|
||||
"event-page-script.js": eventPageScript,
|
||||
"event-page.html": `<html><head>
|
||||
<meta charset="utf-8">
|
||||
<script src="event-page-script.js"><\/script>
|
||||
</head></html>`,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* test_eventpages() {
|
||||
// Used in other tests to prevent the monitorConsole to grip.
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let testCases = [
|
||||
{
|
||||
message: "testing event page running as a background page",
|
||||
eventPage: {
|
||||
"page": "event-page.html",
|
||||
"persistent": false,
|
||||
},
|
||||
},
|
||||
{
|
||||
message: "testing event page scripts running as a background page",
|
||||
eventPage: {
|
||||
"scripts": ["event-page-script.js"],
|
||||
"persistent": false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (let {message, eventPage} of testCases) {
|
||||
info(message);
|
||||
|
||||
// Wait for the expected logged warnings from the manifest validation.
|
||||
let waitForConsole = new Promise(resolve => {
|
||||
SimpleTest.monitorConsole(resolve, [{message: /Event pages are not currently supported./}]);
|
||||
});
|
||||
|
||||
let extension = createEventPageExtension(eventPage);
|
||||
|
||||
info("load complete");
|
||||
let [, x] = yield Promise.all([extension.startup(), extension.awaitMessage("running")]);
|
||||
is(x, 1, "got correct value from extension");
|
||||
info("test complete");
|
||||
yield extension.unload();
|
||||
info("extension unloaded successfully");
|
||||
|
||||
SimpleTest.endMonitorConsole();
|
||||
yield waitForConsole;
|
||||
|
||||
waitForConsole = new Promise(resolve => {
|
||||
SimpleTest.monitorConsole(resolve, [{
|
||||
message: /Reading manifest: Error processing background.nonExistentProp: An unexpected property was found/,
|
||||
}]);
|
||||
});
|
||||
|
||||
info("testing additional unrecognized properties on background page");
|
||||
|
||||
extension = createEventPageExtension({
|
||||
"scripts": ["event-page-script.js"],
|
||||
"nonExistentProp": true,
|
||||
});
|
||||
|
||||
info("load complete");
|
||||
[, x] = yield Promise.all([extension.startup(), extension.awaitMessage("running")]);
|
||||
is(x, 1, "got correct value from extension");
|
||||
info("test complete");
|
||||
yield extension.unload();
|
||||
info("extension unloaded successfully");
|
||||
|
||||
SimpleTest.endMonitorConsole();
|
||||
yield waitForConsole;
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for hybrid addons: SDK or bootstrap.js + embedded WebExtension</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This test contains additional tests that ensure that an SDK hybrid addon
|
||||
* which is using the new module loader can embed a webextension correctly:
|
||||
*
|
||||
* while the other tests related to the "Embedded WebExtension" are focused
|
||||
* on unit testing a specific component, these tests are testing that a complete
|
||||
* hybrid SDK addon works as expected.
|
||||
*
|
||||
* NOTE: this tests are also the only ones which tests an SDK hybrid addon that
|
||||
* uses the new module loader (the one actually used in production by real world
|
||||
* addons these days), while the Addon SDK "embedded-webextension" test addon
|
||||
* uses the old deprecated module loader (as all the other Addon SDK test addons).
|
||||
*/
|
||||
|
||||
function generateClassicExtensionFiles({id, files}) {
|
||||
// The addon install.rdf file, as it would be generated by jpm from the addon
|
||||
// package.json metadata.
|
||||
files["install.rdf"] = `<?xml version="1.0" encoding="utf-8"?>
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>${id}</em:id>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:hasEmbeddedWebExtension>true</em:hasEmbeddedWebExtension>
|
||||
<em:unpack>false</em:unpack>
|
||||
<em:version>0.1.0</em:version>
|
||||
<em:name>Fake Hybrid Addon</em:name>
|
||||
<em:description>A fake hybrid addon</em:description>
|
||||
|
||||
<!-- Firefox -->
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>51.0a1</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<!-- Fennec -->
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{aa3c5121-dab2-40e2-81ca-7ea25febc110}</em:id>
|
||||
<em:minVersion>51.0a1</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</RDF>`;
|
||||
|
||||
// The addon package.json file.
|
||||
files["package.json"] = `{
|
||||
"id": "${id}",
|
||||
"name": "hybrid-addon",
|
||||
"version": "0.1.0",
|
||||
"description": "A fake hybrid addon",
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
"firefox": ">= 51.0a1",
|
||||
"fennec": ">= 51.0a1"
|
||||
},
|
||||
"license": "MPL-2.0",
|
||||
"hasEmbeddedWebExtension": true
|
||||
}`;
|
||||
|
||||
// The bootstrap file that jpm bundle in any SDK addon built with it.
|
||||
files["bootstrap.js"] = `
|
||||
const { utils: Cu } = Components;
|
||||
const rootURI = __SCRIPT_URI_SPEC__.replace("bootstrap.js", "");
|
||||
const COMMONJS_URI = "resource://gre/modules/commonjs";
|
||||
const { require } = Cu.import(COMMONJS_URI + "/toolkit/require.js", {});
|
||||
const { Bootstrap } = require(COMMONJS_URI + "/sdk/addon/bootstrap.js");
|
||||
var { startup, shutdown, install, uninstall } = new Bootstrap(rootURI);
|
||||
`;
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
add_task(function* test_sdk_hybrid_addon_with_jpm_module_loader() {
|
||||
function backgroundScript() {
|
||||
browser.runtime.sendMessage("background message", (reply) => {
|
||||
browser.test.assertEq("sdk received message: background message", reply,
|
||||
"Got the expected reply from the SDK context");
|
||||
browser.test.notifyPass("sdk.webext-api.onmessage");
|
||||
});
|
||||
}
|
||||
|
||||
async function sdkMainScript() {
|
||||
/* globals require */
|
||||
const webext = require("sdk/webextension");
|
||||
let {browser} = await webext.startup();
|
||||
browser.runtime.onMessage.addListener((msg, sender, sendReply) => {
|
||||
sendReply(`sdk received message: ${msg}`);
|
||||
});
|
||||
}
|
||||
|
||||
let id = "fake@sdk.hybrid.addon";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
files: generateClassicExtensionFiles({
|
||||
id,
|
||||
files: {
|
||||
"index.js": sdkMainScript,
|
||||
"webextension/manifest.json": {
|
||||
name: "embedded webextension name",
|
||||
manifest_version: 2,
|
||||
version: "0.1.0",
|
||||
background: {
|
||||
scripts: ["bg.js"],
|
||||
},
|
||||
},
|
||||
"webextension/bg.js": backgroundScript,
|
||||
},
|
||||
}),
|
||||
}, id);
|
||||
|
||||
extension.startup();
|
||||
|
||||
yield extension.awaitFinish("sdk.webext-api.onmessage");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
const idleService = Cc["@mozilla.org/widget/idleservice;1"].getService(Ci.nsIIdleService);
|
||||
|
||||
add_task(function* testWithRealIdleService() {
|
||||
function background() {
|
||||
browser.test.onMessage.addListener((msg, ...args) => {
|
||||
let detectionInterval = args[0];
|
||||
if (msg == "addListener") {
|
||||
browser.idle.queryState(detectionInterval).then(status => {
|
||||
browser.test.assertEq("active", status, "Idle status is active");
|
||||
});
|
||||
browser.idle.setDetectionInterval(detectionInterval);
|
||||
browser.idle.onStateChanged.addListener(newState => {
|
||||
browser.test.assertEq("idle", newState, "listener fired with the expected state");
|
||||
browser.test.sendMessage("listenerFired");
|
||||
});
|
||||
} else if (msg == "checkState") {
|
||||
browser.idle.queryState(detectionInterval).then(status => {
|
||||
browser.test.assertEq("idle", status, "Idle status is idle");
|
||||
browser.test.notifyPass("idle");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
manifest: {
|
||||
permissions: ["idle"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
let idleTime = idleService.idleTime;
|
||||
let detectionInterval = Math.max(Math.ceil(idleTime / 1000) + 2, 15);
|
||||
info(`idleTime: ${idleTime}, detectionInterval: ${detectionInterval}`);
|
||||
extension.sendMessage("addListener", detectionInterval);
|
||||
info("Listener added");
|
||||
yield extension.awaitMessage("listenerFired");
|
||||
info("Listener fired");
|
||||
extension.sendMessage("checkState", detectionInterval);
|
||||
yield extension.awaitFinish("idle");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://testing-common/TestUtils.jsm");
|
||||
|
||||
const {GlobalManager} = Cu.import("resource://gre/modules/Extension.jsm");
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
|
||||
add_task(function* testShutdownCleanup() {
|
||||
is(GlobalManager.initialized, false,
|
||||
"GlobalManager start as not initialized");
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: function() {
|
||||
browser.test.notifyPass("background page loaded");
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
yield extension.awaitFinish("background page loaded");
|
||||
|
||||
is(GlobalManager.initialized, true,
|
||||
"GlobalManager has been initialized once an extension is started");
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
is(GlobalManager.initialized, false,
|
||||
"GlobalManager has been uninitialized once all the webextensions have been stopped");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
// Test that storage used by a webextension (through localStorage,
|
||||
// indexedDB, and browser.storage.local) gets cleaned up when the
|
||||
// extension is uninstalled.
|
||||
add_task(function* test_uninstall() {
|
||||
function writeData() {
|
||||
localStorage.setItem("hello", "world");
|
||||
|
||||
let idbPromise = new Promise((resolve, reject) => {
|
||||
let req = indexedDB.open("test");
|
||||
req.onerror = e => {
|
||||
reject(new Error(`indexedDB open failed with ${e.errorCode}`));
|
||||
};
|
||||
|
||||
req.onupgradeneeded = e => {
|
||||
let db = e.target.result;
|
||||
db.createObjectStore("store", {keyPath: "name"});
|
||||
};
|
||||
|
||||
req.onsuccess = e => {
|
||||
let db = e.target.result;
|
||||
let transaction = db.transaction("store", "readwrite");
|
||||
let addreq = transaction.objectStore("store")
|
||||
.add({name: "hello", value: "world"});
|
||||
addreq.onerror = addreqError => {
|
||||
reject(new Error(`add to indexedDB failed with ${addreqError.errorCode}`));
|
||||
};
|
||||
addreq.onsuccess = () => {
|
||||
resolve();
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
let browserStoragePromise = browser.storage.local.set({hello: "world"});
|
||||
|
||||
Promise.all([idbPromise, browserStoragePromise]).then(() => {
|
||||
browser.test.sendMessage("finished");
|
||||
});
|
||||
}
|
||||
|
||||
function readData() {
|
||||
let matchLocalStorage = (localStorage.getItem("hello") == "world");
|
||||
|
||||
let idbPromise = new Promise((resolve, reject) => {
|
||||
let req = indexedDB.open("test");
|
||||
req.onerror = e => {
|
||||
reject(new Error(`indexedDB open failed with ${e.errorCode}`));
|
||||
};
|
||||
|
||||
req.onupgradeneeded = e => {
|
||||
// no database, data is not present
|
||||
resolve(false);
|
||||
};
|
||||
|
||||
req.onsuccess = e => {
|
||||
let db = e.target.result;
|
||||
let transaction = db.transaction("store", "readwrite");
|
||||
let addreq = transaction.objectStore("store").get("hello");
|
||||
addreq.onerror = addreqError => {
|
||||
reject(new Error(`read from indexedDB failed with ${addreqError.errorCode}`));
|
||||
};
|
||||
addreq.onsuccess = () => {
|
||||
let match = (addreq.result.value == "world");
|
||||
resolve(match);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
let browserStoragePromise = browser.storage.local.get("hello").then(result => {
|
||||
return (Object.keys(result).length == 1 && result.hello == "world");
|
||||
});
|
||||
|
||||
Promise.all([idbPromise, browserStoragePromise])
|
||||
.then(([matchIDB, matchBrowserStorage]) => {
|
||||
let result = {matchLocalStorage, matchIDB, matchBrowserStorage};
|
||||
browser.test.sendMessage("results", result);
|
||||
});
|
||||
}
|
||||
|
||||
const ID = "storage.cleanup@tests.mozilla.org";
|
||||
|
||||
// Use a test-only pref to leave the addonid->uuid mapping around after
|
||||
// uninstall so that we can re-attach to the same storage. Also set
|
||||
// the pref to prevent cleaning up storage on uninstall so we can test
|
||||
// that the "keep uuid" logic works correctly. Do the storage flag in
|
||||
// a separate prefEnv so we can pop it below, leaving the uuid flag set.
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.webextensions.keepUuidOnUninstall", true]],
|
||||
});
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.webextensions.keepStorageOnUninstall", true]],
|
||||
});
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: writeData,
|
||||
manifest: {
|
||||
applications: {gecko: {id: ID}},
|
||||
permissions: ["storage"],
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("finished");
|
||||
yield extension.unload();
|
||||
|
||||
// Check that we can still see data we wrote to storage but clear the
|
||||
// "leave storage" flag so our storaged gets cleared on uninstall.
|
||||
// This effectively tests the keepUuidOnUninstall logic, which ensures
|
||||
// that when we read storage again and check that it is cleared, that
|
||||
// it is actually a meaningful test!
|
||||
yield SpecialPowers.popPrefEnv();
|
||||
extension = ExtensionTestUtils.loadExtension({
|
||||
background: readData,
|
||||
manifest: {
|
||||
applications: {gecko: {id: ID}},
|
||||
permissions: ["storage"],
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
let results = yield extension.awaitMessage("results");
|
||||
is(results.matchLocalStorage, true, "localStorage data is still present");
|
||||
is(results.matchIDB, true, "indexedDB data is still present");
|
||||
is(results.matchBrowserStorage, true, "browser.storage.local data is still present");
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
// Read again. This time, our data should be gone.
|
||||
extension = ExtensionTestUtils.loadExtension({
|
||||
background: readData,
|
||||
manifest: {
|
||||
applications: {gecko: {id: ID}},
|
||||
permissions: ["storage"],
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
results = yield extension.awaitMessage("results");
|
||||
is(results.matchLocalStorage, false, "localStorage data was cleared");
|
||||
is(results.matchIDB, false, "indexedDB data was cleared");
|
||||
is(results.matchBrowserStorage, false, "browser.storage.local data was cleared");
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This test is asserting that moz-extension: URLs are recognized as trustworthy local origins
|
||||
*/
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gContentSecurityManager",
|
||||
"@mozilla.org/contentsecuritymanager;1",
|
||||
"nsIContentSecurityManager");
|
||||
|
||||
add_task(function* () {
|
||||
function background() {
|
||||
browser.test.sendMessage("ready", browser.runtime.getURL("/test.html"));
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
files: {
|
||||
"test.html": `<html><head></head><body></body></html>`,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let url = yield extension.awaitMessage("ready");
|
||||
|
||||
let uri = NetUtil.newURI(url);
|
||||
let principal = Services.scriptSecurityManager.getCodebasePrincipal(uri);
|
||||
is(gContentSecurityManager.isOriginPotentiallyTrustworthy(principal), true);
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for simple WebExtension</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* webnav_unresolved_uri_on_expected_URI_scheme() {
|
||||
function background() {
|
||||
let checkURLs;
|
||||
|
||||
browser.webNavigation.onCompleted.addListener(async msg => {
|
||||
if (checkURLs.length > 0) {
|
||||
let expectedURL = checkURLs.shift();
|
||||
browser.test.assertEq(expectedURL, msg.url, "Got the expected URL");
|
||||
await browser.tabs.remove(msg.tabId);
|
||||
browser.test.sendMessage("next");
|
||||
}
|
||||
});
|
||||
|
||||
browser.test.onMessage.addListener((name, urls) => {
|
||||
if (name == "checkURLs") {
|
||||
checkURLs = urls;
|
||||
}
|
||||
});
|
||||
|
||||
browser.test.sendMessage("ready", browser.runtime.getURL("/tab.html"));
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
permissions: [
|
||||
"webNavigation",
|
||||
],
|
||||
},
|
||||
background,
|
||||
files: {
|
||||
"tab.html": `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
let checkURLs = [
|
||||
"resource://gre/modules/Services.jsm",
|
||||
"chrome://mochikit/content/tests/SimpleTest/SimpleTest.js",
|
||||
"about:mozilla",
|
||||
];
|
||||
|
||||
let tabURL = yield extension.awaitMessage("ready");
|
||||
checkURLs.push(tabURL);
|
||||
|
||||
extension.sendMessage("checkURLs", checkURLs);
|
||||
|
||||
for (let url of checkURLs) {
|
||||
window.open(url);
|
||||
yield extension.awaitMessage("next");
|
||||
}
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for simple WebExtension</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
Cu.import(SimpleTest.getTestFileURL("webrequest_test.jsm"));
|
||||
let {testFetch, testXHR} = webrequest_test;
|
||||
|
||||
// Here we test that any requests originating from a system principal are not
|
||||
// accessible through WebRequest. text_ext_webrequest_background_events tests
|
||||
// non-system principal requests.
|
||||
|
||||
let testExtension = {
|
||||
manifest: {
|
||||
permissions: [
|
||||
"webRequest",
|
||||
"<all_urls>",
|
||||
],
|
||||
},
|
||||
background() {
|
||||
let eventNames = [
|
||||
"onBeforeRequest",
|
||||
"onBeforeSendHeaders",
|
||||
"onSendHeaders",
|
||||
"onHeadersReceived",
|
||||
"onResponseStarted",
|
||||
"onCompleted",
|
||||
];
|
||||
|
||||
function listener(name, details) {
|
||||
// If we get anything, we failed. Removing the system principal check
|
||||
// in ext-webrequest triggers this failure.
|
||||
browser.test.fail(`recieved ${name}`);
|
||||
}
|
||||
|
||||
for (let name of eventNames) {
|
||||
browser.webRequest[name].addListener(
|
||||
listener.bind(null, name),
|
||||
{urls: ["https://example.com/*"]}
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* test_webRequest_chromeworker_events() {
|
||||
let extension = ExtensionTestUtils.loadExtension(testExtension);
|
||||
yield extension.startup();
|
||||
yield new Promise(resolve => {
|
||||
let worker = new ChromeWorker("webrequest_chromeworker.js");
|
||||
worker.onmessage = event => {
|
||||
ok("chrome worker fetch finished");
|
||||
resolve();
|
||||
};
|
||||
worker.postMessage("go");
|
||||
});
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_webRequest_chromepage_events() {
|
||||
let extension = ExtensionTestUtils.loadExtension(testExtension);
|
||||
yield extension.startup();
|
||||
yield new Promise(resolve => {
|
||||
fetch("https://example.com/example.txt").then(() => {
|
||||
ok("test page loaded");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_webRequest_jsm_events() {
|
||||
let extension = ExtensionTestUtils.loadExtension(testExtension);
|
||||
yield extension.startup();
|
||||
yield testFetch("https://example.com/example.txt").then(() => {
|
||||
ok("fetch page loaded");
|
||||
});
|
||||
yield testXHR("https://example.com/example.txt").then(() => {
|
||||
ok("xhr page loaded");
|
||||
});
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
/* global OS */
|
||||
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
// Test that the default paths searched for native host manifests
|
||||
// are the ones we expect.
|
||||
add_task(function* test_default_paths() {
|
||||
let expectUser, expectGlobal;
|
||||
switch (AppConstants.platform) {
|
||||
case "macosx": {
|
||||
expectUser = OS.Path.join(OS.Constants.Path.homeDir,
|
||||
"Library/Application Support/Mozilla/NativeMessagingHosts");
|
||||
expectGlobal = "/Library/Application Support/Mozilla/NativeMessagingHosts";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "linux": {
|
||||
expectUser = OS.Path.join(OS.Constants.Path.homeDir, ".mozilla/native-messaging-hosts");
|
||||
|
||||
const libdir = AppConstants.HAVE_USR_LIB64_DIR ? "lib64" : "lib";
|
||||
expectGlobal = OS.Path.join("/usr", libdir, "mozilla/native-messaging-hosts");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// Fixed filesystem paths are only defined for MacOS and Linux,
|
||||
// there's nothing to test on other platforms.
|
||||
ok(false, `This test does not apply on ${AppConstants.platform}`);
|
||||
break;
|
||||
}
|
||||
|
||||
let userDir = Services.dirsvc.get("XREUserNativeMessaging", Ci.nsIFile).path;
|
||||
is(userDir, expectUser, "user-specific native messaging directory is correct");
|
||||
|
||||
let globalDir = Services.dirsvc.get("XRESysNativeMessaging", Ci.nsIFile).path;
|
||||
is(globalDir, expectGlobal, "system-wide native messaing directory is correct");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>clipboard permission test</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script src="head.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
function doCopy(txt) {
|
||||
let field = document.createElement("textarea");
|
||||
document.body.appendChild(field);
|
||||
field.value = txt;
|
||||
field.select();
|
||||
return document.execCommand("copy");
|
||||
}
|
||||
|
||||
add_task(function* no_permission_deny_copy() {
|
||||
function backgroundScript() {
|
||||
browser.test.assertEq(false, doCopy("whatever"),
|
||||
"copy should be denied without permission");
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
let extensionData = {
|
||||
background: `${doCopy};(${backgroundScript})();`,
|
||||
};
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
/** Selecting text in a bg page is not possible, skip test until it's fixed.
|
||||
add_task(function* with_permission_allow_copy() {
|
||||
function backgroundScript() {
|
||||
browser.test.onMessage.addListener(txt => {
|
||||
browser.test.assertEq(true, doCopy(txt),
|
||||
"copy should be allowed with permission");
|
||||
});
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
let extensionData = {
|
||||
background: `${doCopy};(${backgroundScript})();`,
|
||||
manifest: {
|
||||
permissions: [
|
||||
"clipboardWrite",
|
||||
],
|
||||
},
|
||||
};
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
const DUMMY_STR = "dummy string to copy";
|
||||
yield new Promise(resolve => {
|
||||
SimpleTest.waitForClipboard(DUMMY_STR, () => {
|
||||
extension.sendMessage(DUMMY_STR);
|
||||
}, resolve, resolve);
|
||||
});
|
||||
|
||||
yield extension.unload();
|
||||
}); */
|
||||
|
||||
add_task(function* content_script_no_permission_deny_copy() {
|
||||
function contentScript() {
|
||||
browser.test.assertEq(false, doCopy("whatever"),
|
||||
"copy should be denied without permission");
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [{
|
||||
js: ["contentscript.js"],
|
||||
matches: ["http://mochi.test/*/file_sample.html"],
|
||||
}],
|
||||
},
|
||||
files: {
|
||||
"contentscript.js": `${doCopy};(${contentScript})();`,
|
||||
},
|
||||
};
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
yield extension.awaitMessage("ready");
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* content_script_with_permission_allow_copy() {
|
||||
function contentScript() {
|
||||
browser.test.onMessage.addListener(txt => {
|
||||
browser.test.assertEq(true, doCopy(txt),
|
||||
"copy should be allowed with permission");
|
||||
});
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [{
|
||||
js: ["contentscript.js"],
|
||||
matches: ["http://mochi.test/*/file_sample.html"],
|
||||
}],
|
||||
permissions: [
|
||||
"clipboardWrite",
|
||||
],
|
||||
},
|
||||
files: {
|
||||
"contentscript.js": `${doCopy};(${contentScript})();`,
|
||||
},
|
||||
};
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
const DUMMY_STR = "dummy string to copy in content script";
|
||||
yield new Promise(resolve => {
|
||||
SimpleTest.waitForClipboard(DUMMY_STR, () => {
|
||||
extension.sendMessage(DUMMY_STR);
|
||||
}, resolve, resolve);
|
||||
});
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
// Tests whether not too many APIs are visible by default.
|
||||
// This file is used by test_ext_all_apis.html in browser/ and mobile/android/,
|
||||
// which may modify the following variables to add or remove expected APIs.
|
||||
/* globals expectedContentApisTargetSpecific */
|
||||
/* globals expectedBackgroundApisTargetSpecific */
|
||||
|
||||
// Generates a list of expectations.
|
||||
function generateExpectations(list) {
|
||||
return list.reduce((allApis, path) => {
|
||||
return allApis.concat(`browser.${path}`, `chrome.${path}`);
|
||||
}, []).sort();
|
||||
}
|
||||
|
||||
let expectedCommonApis = [
|
||||
"extension.getURL",
|
||||
"extension.inIncognitoContext",
|
||||
"extension.lastError",
|
||||
"i18n.detectLanguage",
|
||||
"i18n.getAcceptLanguages",
|
||||
"i18n.getMessage",
|
||||
"i18n.getUILanguage",
|
||||
"runtime.OnInstalledReason",
|
||||
"runtime.OnRestartRequiredReason",
|
||||
"runtime.PlatformArch",
|
||||
"runtime.PlatformOs",
|
||||
"runtime.RequestUpdateCheckStatus",
|
||||
"runtime.getManifest",
|
||||
"runtime.connect",
|
||||
"runtime.getURL",
|
||||
"runtime.id",
|
||||
"runtime.lastError",
|
||||
"runtime.onConnect",
|
||||
"runtime.onMessage",
|
||||
"runtime.sendMessage",
|
||||
// If you want to add a new powerful test API, please see bug 1287233.
|
||||
"test.assertEq",
|
||||
"test.assertFalse",
|
||||
"test.assertRejects",
|
||||
"test.assertThrows",
|
||||
"test.assertTrue",
|
||||
"test.fail",
|
||||
"test.log",
|
||||
"test.notifyFail",
|
||||
"test.notifyPass",
|
||||
"test.onMessage",
|
||||
"test.sendMessage",
|
||||
"test.succeed",
|
||||
];
|
||||
|
||||
let expectedContentApis = [
|
||||
...expectedCommonApis,
|
||||
...expectedContentApisTargetSpecific,
|
||||
];
|
||||
|
||||
let expectedBackgroundApis = [
|
||||
...expectedCommonApis,
|
||||
...expectedBackgroundApisTargetSpecific,
|
||||
"extension.ViewType",
|
||||
"extension.getBackgroundPage",
|
||||
"extension.getViews",
|
||||
"extension.isAllowedFileSchemeAccess",
|
||||
"extension.isAllowedIncognitoAccess",
|
||||
// Note: extensionTypes is not visible in Chrome.
|
||||
"extensionTypes.ImageFormat",
|
||||
"extensionTypes.RunAt",
|
||||
"management.ExtensionDisabledReason",
|
||||
"management.ExtensionInstallType",
|
||||
"management.ExtensionType",
|
||||
"management.getSelf",
|
||||
"management.uninstallSelf",
|
||||
"runtime.getBackgroundPage",
|
||||
"runtime.getBrowserInfo",
|
||||
"runtime.getPlatformInfo",
|
||||
"runtime.onInstalled",
|
||||
"runtime.onStartup",
|
||||
"runtime.onUpdateAvailable",
|
||||
"runtime.openOptionsPage",
|
||||
"runtime.reload",
|
||||
"runtime.setUninstallURL",
|
||||
];
|
||||
|
||||
function sendAllApis() {
|
||||
function isEvent(key, val) {
|
||||
if (!/^on[A-Z]/.test(key)) {
|
||||
return false;
|
||||
}
|
||||
let eventKeys = [];
|
||||
for (let prop in val) {
|
||||
eventKeys.push(prop);
|
||||
}
|
||||
eventKeys = eventKeys.sort().join();
|
||||
return eventKeys === "addListener,hasListener,removeListener";
|
||||
}
|
||||
function mayRecurse(key, val) {
|
||||
if (Object.keys(val).filter(k => !/^[A-Z\-0-9_]+$/.test(k)).length === 0) {
|
||||
// Don't recurse on constants and empty objects.
|
||||
return false;
|
||||
}
|
||||
return !isEvent(key, val);
|
||||
}
|
||||
|
||||
let results = [];
|
||||
function diveDeeper(path, obj) {
|
||||
for (let key in obj) {
|
||||
let val = obj[key];
|
||||
if (typeof val == "object" && val !== null && mayRecurse(key, val)) {
|
||||
diveDeeper(`${path}.${key}`, val);
|
||||
} else if (val !== undefined) {
|
||||
results.push(`${path}.${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
diveDeeper("browser", browser);
|
||||
diveDeeper("chrome", chrome);
|
||||
browser.test.sendMessage("allApis", results.sort());
|
||||
}
|
||||
|
||||
add_task(function* test_enumerate_content_script_apis() {
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [{
|
||||
matches: ["http://mochi.test/*/file_sample.html"],
|
||||
js: ["contentscript.js"],
|
||||
run_at: "document_start",
|
||||
}],
|
||||
},
|
||||
files: {
|
||||
"contentscript.js": sendAllApis,
|
||||
},
|
||||
};
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
let actualApis = yield extension.awaitMessage("allApis");
|
||||
win.close();
|
||||
let expectedApis = generateExpectations(expectedContentApis);
|
||||
isDeeply(actualApis, expectedApis, "content script APIs");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_enumerate_background_script_apis() {
|
||||
let extensionData = {
|
||||
background: sendAllApis,
|
||||
};
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
let actualApis = yield extension.awaitMessage("allApis");
|
||||
let expectedApis = generateExpectations(expectedBackgroundApis);
|
||||
isDeeply(actualApis, expectedApis, "background script APIs");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for privilege escalation into content pages</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* testBackgroundWindow() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: function() {
|
||||
const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest";
|
||||
|
||||
browser.test.log("background script executed");
|
||||
window.location = `${BASE}/file_privilege_escalation.html`;
|
||||
},
|
||||
});
|
||||
|
||||
let awaitConsole = new Promise(resolve => {
|
||||
let chromeScript = SpecialPowers.loadChromeScript(
|
||||
SimpleTest.getTestFileURL("file_ext_test_api_injection.js"));
|
||||
|
||||
chromeScript.addMessageListener("console-message", resolve);
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
let message = yield awaitConsole;
|
||||
|
||||
ok(message.message.includes("WebExt Privilege Escalation: typeof(browser) = undefined"),
|
||||
"Document does not have `browser` APIs.");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for background page canvas rendering</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_background_canvas() {
|
||||
function background() {
|
||||
try {
|
||||
let canvas = document.createElement("canvas");
|
||||
|
||||
let context = canvas.getContext("2d");
|
||||
|
||||
// This ensures that we have a working PresShell, and can successfully
|
||||
// calculate font metrics.
|
||||
context.font = "8pt fixed";
|
||||
|
||||
browser.test.notifyPass("background-canvas");
|
||||
} catch (e) {
|
||||
browser.test.fail(`Error: ${e} :: ${e.stack}`);
|
||||
browser.test.notifyFail("background-canvas");
|
||||
}
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("background-canvas");
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test _generated_background_page.html</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_url_of_generated_background_page() {
|
||||
function backgroundScript() {
|
||||
const EXPECTED_URL = browser.runtime.getURL("/_generated_background_page.html");
|
||||
browser.test.assertEq(EXPECTED_URL, location.href);
|
||||
browser.test.sendMessage("script done", EXPECTED_URL);
|
||||
}
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
background: {
|
||||
scripts: ["bg.js"],
|
||||
},
|
||||
web_accessible_resources: ["_generated_background_page.html"],
|
||||
},
|
||||
files: {
|
||||
"bg.js": backgroundScript,
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
const EXPECTED_URL = yield extension.awaitMessage("script done");
|
||||
|
||||
let win = window.open(EXPECTED_URL);
|
||||
ok(win, "Should open new tab at URL: " + EXPECTED_URL);
|
||||
yield extension.awaitMessage("script done");
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for background script teardown</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_background_reload_and_unload() {
|
||||
function background() {
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
browser.test.assertEq("reload-background", msg);
|
||||
location.reload();
|
||||
});
|
||||
browser.test.sendMessage("background-url", location.href);
|
||||
}
|
||||
|
||||
let chromeScript = SpecialPowers.loadChromeScript(
|
||||
SimpleTest.getTestFileURL("file_teardown_test.js"));
|
||||
yield chromeScript.promiseOneMessage("chromescript-startup");
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
function* getContextEvents() {
|
||||
chromeScript.sendAsyncMessage("get-context-events");
|
||||
let contextEvents = yield chromeScript.promiseOneMessage("context-events");
|
||||
return contextEvents.filter(event => event.extensionId == extension.id);
|
||||
}
|
||||
yield extension.startup();
|
||||
let backgroundUrl = yield extension.awaitMessage("background-url");
|
||||
|
||||
let contextEvents = yield* getContextEvents();
|
||||
is(contextEvents.length, 1,
|
||||
"ExtensionContext state change after loading an extension");
|
||||
is(contextEvents[0].eventType, "load");
|
||||
is(contextEvents[0].url, backgroundUrl,
|
||||
"The ExtensionContext should be the background page");
|
||||
|
||||
extension.sendMessage("reload-background");
|
||||
yield extension.awaitMessage("background-url");
|
||||
|
||||
contextEvents = yield* getContextEvents();
|
||||
is(contextEvents.length, 2,
|
||||
"ExtensionContext state changes after reloading the background page");
|
||||
is(contextEvents[0].eventType, "unload",
|
||||
"Unload ExtensionContext of background page");
|
||||
is(contextEvents[0].url, backgroundUrl, "ExtensionContext URL = background");
|
||||
is(contextEvents[1].eventType, "load",
|
||||
"Create new ExtensionContext for background page");
|
||||
is(contextEvents[1].url, backgroundUrl, "ExtensionContext URL = background");
|
||||
yield extension.unload();
|
||||
|
||||
contextEvents = yield* getContextEvents();
|
||||
is(contextEvents.length, 1,
|
||||
"ExtensionContext state change after unloading the extension");
|
||||
is(contextEvents[0].eventType, "unload",
|
||||
"Unload ExtensionContext for background page after extension unloads");
|
||||
is(contextEvents[0].url, backgroundUrl, "ExtensionContext URL = background");
|
||||
|
||||
chromeScript.sendAsyncMessage("cleanup");
|
||||
chromeScript.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension CSP test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests that content security policies for an add-on are actually applied to *
|
||||
* documents that belong to it. This tests both the base policies and add-on
|
||||
* specific policies, and ensures that the parsed policies applied to the
|
||||
* document's principal match what was specified in the policy string.
|
||||
*
|
||||
* @param {object} [customCSP]
|
||||
*/
|
||||
function* testPolicy(customCSP = null) {
|
||||
let baseURL;
|
||||
|
||||
let baseCSP = {
|
||||
"object-src": ["blob:", "filesystem:", "https://*", "moz-extension:", "'self'"],
|
||||
"script-src": ["'unsafe-eval'", "'unsafe-inline'", "blob:", "filesystem:", "https://*", "moz-extension:", "'self'"],
|
||||
};
|
||||
|
||||
let addonCSP = {
|
||||
"object-src": ["'self'"],
|
||||
"script-src": ["'self'"],
|
||||
};
|
||||
|
||||
let content_security_policy = null;
|
||||
|
||||
if (customCSP) {
|
||||
for (let key of Object.keys(customCSP)) {
|
||||
addonCSP[key] = customCSP[key].split(/\s+/);
|
||||
}
|
||||
|
||||
content_security_policy = Object.keys(customCSP)
|
||||
.map(key => `${key} ${customCSP[key]}`)
|
||||
.join("; ");
|
||||
}
|
||||
|
||||
|
||||
function filterSelf(sources) {
|
||||
return sources.map(src => src == "'self'" ? baseURL : src);
|
||||
}
|
||||
|
||||
function checkSource(name, policy, expected) {
|
||||
is(JSON.stringify(policy[name].sort()),
|
||||
JSON.stringify(filterSelf(expected[name]).sort()),
|
||||
`Expected value for ${name}`);
|
||||
}
|
||||
|
||||
function checkCSP(csp, location) {
|
||||
let policies = csp["csp-policies"];
|
||||
|
||||
info(`Base policy for ${location}`);
|
||||
|
||||
is(policies[0]["report-only"], false, "Policy is not report-only");
|
||||
checkSource("object-src", policies[0], baseCSP);
|
||||
checkSource("script-src", policies[0], baseCSP);
|
||||
|
||||
info(`Add-on policy for ${location}`);
|
||||
|
||||
is(policies[1]["report-only"], false, "Policy is not report-only");
|
||||
checkSource("object-src", policies[1], addonCSP);
|
||||
checkSource("script-src", policies[1], addonCSP);
|
||||
}
|
||||
|
||||
|
||||
function getCSP(window) {
|
||||
let {cspJSON} = SpecialPowers.Cu.getObjectPrincipal(window);
|
||||
return JSON.parse(cspJSON);
|
||||
}
|
||||
|
||||
function background(getCSPFn) {
|
||||
browser.test.sendMessage("base-url", browser.extension.getURL("").replace(/\/$/, ""));
|
||||
|
||||
browser.test.sendMessage("background-csp", getCSPFn(window));
|
||||
}
|
||||
|
||||
function tabScript(getCSPFn) {
|
||||
browser.test.sendMessage("tab-csp", getCSPFn(window));
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: `(${background})(${getCSP})`,
|
||||
|
||||
files: {
|
||||
"tab.html": `<html><head><meta charset="utf-8">
|
||||
<script src="tab.js"></${"script"}></head></html>`,
|
||||
|
||||
"tab.js": `(${tabScript})(${getCSP})`,
|
||||
|
||||
"content.html": `<html><head><meta charset="utf-8"></head></html>`,
|
||||
},
|
||||
|
||||
manifest: {
|
||||
content_security_policy,
|
||||
|
||||
web_accessible_resources: ["content.html", "tab.html"],
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
info(`Testing CSP for policy: ${content_security_policy}`);
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
baseURL = yield extension.awaitMessage("base-url");
|
||||
|
||||
|
||||
let win1 = window.open(`${baseURL}/tab.html`);
|
||||
|
||||
let frame = document.createElement("iframe");
|
||||
frame.src = `${baseURL}/content.html`;
|
||||
document.body.appendChild(frame);
|
||||
|
||||
yield new Promise(resolve => {
|
||||
frame.onload = resolve;
|
||||
});
|
||||
|
||||
|
||||
let backgroundCSP = yield extension.awaitMessage("background-csp");
|
||||
checkCSP(backgroundCSP, "background page");
|
||||
|
||||
let tabCSP = yield extension.awaitMessage("tab-csp");
|
||||
checkCSP(tabCSP, "tab page");
|
||||
|
||||
let contentCSP = getCSP(frame.contentWindow);
|
||||
checkCSP(contentCSP, "content frame");
|
||||
|
||||
|
||||
win1.close();
|
||||
frame.remove();
|
||||
|
||||
yield extension.unload();
|
||||
}
|
||||
|
||||
add_task(function* testCSP() {
|
||||
yield testPolicy(null);
|
||||
|
||||
let hash = "'sha256-NjZhMDQ1YjQ1MjEwMmM1OWQ4NDBlYzA5N2Q1OWQ5NDY3ZTEzYTNmMzRmNjQ5NGU1MzlmZmQzMmMxYmIzNWYxOCAgLQo='";
|
||||
|
||||
yield testPolicy({
|
||||
"object-src": "'self' https://*.example.com",
|
||||
"script-src": `'self' https://*.example.com 'unsafe-eval' ${hash}`,
|
||||
});
|
||||
|
||||
yield testPolicy({
|
||||
"object-src": "'none'",
|
||||
"script-src": `'self'`,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener(([msg, expectedStates, readyState], sender) => {
|
||||
if (msg == "chrome-namespace-ok") {
|
||||
browser.test.sendMessage(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
browser.test.assertEq("script-run", msg, "message type is correct");
|
||||
browser.test.assertTrue(expectedStates.includes(readyState),
|
||||
`readyState "${readyState}" is one of [${expectedStates}]`);
|
||||
browser.test.sendMessage("script-run-" + expectedStates[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function contentScriptStart() {
|
||||
browser.runtime.sendMessage(["script-run", ["loading"], document.readyState]);
|
||||
}
|
||||
function contentScriptEnd() {
|
||||
browser.runtime.sendMessage(["script-run", ["interactive", "complete"], document.readyState]);
|
||||
}
|
||||
function contentScriptIdle() {
|
||||
browser.runtime.sendMessage(["script-run", ["complete"], document.readyState]);
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
let manifest = browser.runtime.getManifest();
|
||||
void manifest.applications.gecko.id;
|
||||
chrome.runtime.sendMessage(["chrome-namespace-ok"]);
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
applications: {gecko: {id: "contentscript@tests.mozilla.org"}},
|
||||
content_scripts: [
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script_start.js"],
|
||||
"run_at": "document_start",
|
||||
},
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script_end.js"],
|
||||
"run_at": "document_end",
|
||||
},
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script_idle.js"],
|
||||
"run_at": "document_idle",
|
||||
},
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
},
|
||||
],
|
||||
},
|
||||
background,
|
||||
|
||||
files: {
|
||||
"content_script_start.js": contentScriptStart,
|
||||
"content_script_end.js": contentScriptEnd,
|
||||
"content_script_idle.js": contentScriptIdle,
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
let loadingCount = 0;
|
||||
let interactiveCount = 0;
|
||||
let completeCount = 0;
|
||||
extension.onMessage("script-run-loading", () => { loadingCount++; });
|
||||
extension.onMessage("script-run-interactive", () => { interactiveCount++; });
|
||||
|
||||
let completePromise = new Promise(resolve => {
|
||||
extension.onMessage("script-run-complete", () => { completeCount++; resolve(); });
|
||||
});
|
||||
|
||||
let chromeNamespacePromise = extension.awaitMessage("chrome-namespace-ok");
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield Promise.all([waitForLoad(win), completePromise, chromeNamespacePromise]);
|
||||
info("test page loaded");
|
||||
|
||||
win.close();
|
||||
|
||||
is(loadingCount, 1, "document_start script ran exactly once");
|
||||
is(interactiveCount, 1, "document_end script ran exactly once");
|
||||
is(completeCount, 1, "document_idle script ran exactly once");
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test content script match_about_blank option</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript_about_blank() {
|
||||
const manifest = {
|
||||
content_scripts: [
|
||||
{
|
||||
match_about_blank: true,
|
||||
matches: ["http://mochi.test/*/file_with_about_blank.html", "http://example.com/*"],
|
||||
all_frames: true,
|
||||
css: ["all.css"],
|
||||
js: ["all.js"],
|
||||
}, {
|
||||
matches: ["http://mochi.test/*/file_with_about_blank.html"],
|
||||
css: ["mochi_without.css"],
|
||||
js: ["mochi_without.js"],
|
||||
all_frames: true,
|
||||
}, {
|
||||
match_about_blank: true,
|
||||
matches: ["http://mochi.test/*/file_with_about_blank.html"],
|
||||
css: ["mochi_with.css"],
|
||||
js: ["mochi_with.js"],
|
||||
all_frames: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const files = {
|
||||
"all.js": function() {
|
||||
browser.runtime.sendMessage("all");
|
||||
},
|
||||
"all.css": `
|
||||
body { color: red; }
|
||||
`,
|
||||
"mochi_without.js": function() {
|
||||
browser.runtime.sendMessage("mochi_without");
|
||||
},
|
||||
"mochi_without.css": `
|
||||
body { background: yellow; }
|
||||
`,
|
||||
"mochi_with.js": function() {
|
||||
browser.runtime.sendMessage("mochi_with");
|
||||
},
|
||||
"mochi_with.css": `
|
||||
body { text-align: right; }
|
||||
`,
|
||||
};
|
||||
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener((script, {url}) => {
|
||||
const kind = url.startsWith("about:") ? url : "top";
|
||||
browser.test.sendMessage("script", [script, kind, url]);
|
||||
browser.test.sendMessage(`${script}:${kind}`);
|
||||
});
|
||||
}
|
||||
|
||||
const PATH = "tests/toolkit/components/extensions/test/mochitest/file_with_about_blank.html";
|
||||
const extension = ExtensionTestUtils.loadExtension({manifest, files, background});
|
||||
yield extension.startup();
|
||||
|
||||
let count = 0;
|
||||
extension.onMessage("script", script => {
|
||||
info(`script ran: ${script}`);
|
||||
count++;
|
||||
});
|
||||
|
||||
let win = window.open("http://example.com/" + PATH);
|
||||
yield Promise.all([
|
||||
extension.awaitMessage("all:top"),
|
||||
extension.awaitMessage("all:about:blank"),
|
||||
extension.awaitMessage("all:about:srcdoc"),
|
||||
]);
|
||||
is(count, 3, "exactly 3 scripts ran");
|
||||
win.close();
|
||||
|
||||
win = window.open("http://mochi.test:8888/" + PATH);
|
||||
yield Promise.all([
|
||||
extension.awaitMessage("all:top"),
|
||||
extension.awaitMessage("all:about:blank"),
|
||||
extension.awaitMessage("all:about:srcdoc"),
|
||||
extension.awaitMessage("mochi_without:top"),
|
||||
extension.awaitMessage("mochi_with:top"),
|
||||
extension.awaitMessage("mochi_with:about:blank"),
|
||||
extension.awaitMessage("mochi_with:about:srcdoc"),
|
||||
]);
|
||||
|
||||
let style = win.getComputedStyle(win.document.body);
|
||||
is(style.color, "rgb(255, 0, 0)", "top window text color is red");
|
||||
is(style.backgroundColor, "rgb(255, 255, 0)", "top window background is yellow");
|
||||
is(style.textAlign, "right", "top window text is right-aligned");
|
||||
|
||||
let a_b = win.document.getElementById("a_b");
|
||||
style = a_b.contentWindow.getComputedStyle(a_b.contentDocument.body);
|
||||
is(style.color, "rgb(255, 0, 0)", "about:blank iframe text color is red");
|
||||
is(style.backgroundColor, "transparent", "about:blank iframe background is transparent");
|
||||
is(style.textAlign, "right", "about:blank text is right-aligned");
|
||||
|
||||
is(count, 10, "exactly 7 more scripts ran");
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for privilege escalation into iframe with content script APIs</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- WORKAROUND: this textarea hack is used to contain the html page source without escaping it -->
|
||||
<textarea id="test-asset">
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="./content_script_iframe.js">
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
</textarea>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript_api_injection() {
|
||||
function contentScript() {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("src", browser.runtime.getURL("content_script_iframe.html"));
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
function contentScriptIframe() {
|
||||
const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest";
|
||||
window.location = `${BASE}/file_privilege_escalation.html`;
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
},
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
"content_script_iframe.html",
|
||||
],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
"content_script_iframe.js": contentScriptIframe,
|
||||
"content_script_iframe.html": document.querySelector("#test-asset").textContent,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
let awaitConsole = new Promise(resolve => {
|
||||
let chromeScript = SpecialPowers.loadChromeScript(
|
||||
SimpleTest.getTestFileURL("file_ext_test_api_injection.js"));
|
||||
|
||||
chromeScript.addMessageListener("console-message", resolve);
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
info("extension loaded");
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
let message = yield awaitConsole;
|
||||
|
||||
ok(message.message.includes("WebExt Privilege Escalation: typeof(browser) = undefined"),
|
||||
"Document does not have `browser` APIs.");
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test content script async loading</title>
|
||||
<script src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_async_loading() {
|
||||
const adder = `(function add(a = 1) { this.count += a; })();\n`;
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
content_scripts: [{
|
||||
matches: ["https://example.org/"],
|
||||
js: ["first.js", "second.js"],
|
||||
}],
|
||||
},
|
||||
files: {
|
||||
"first.js": `
|
||||
this.count = 0;
|
||||
${adder.repeat(50000)}; // 2Mb
|
||||
browser.test.assertEq(this.count, 50000, "A 50k line script");
|
||||
|
||||
this.order = (this.order || 0) + 1;
|
||||
browser.test.sendMessage("first", this.order);
|
||||
`,
|
||||
"second.js": `
|
||||
this.order = (this.order || 0) + 1;
|
||||
browser.test.sendMessage("second", this.order);
|
||||
`,
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
const win = window.open("https://example.org/");
|
||||
|
||||
const [first, second] = yield Promise.all([
|
||||
extension.awaitMessage("first"),
|
||||
extension.awaitMessage("second"),
|
||||
]);
|
||||
|
||||
is(first, 1, "first.js finished execution first.");
|
||||
is(second, 2, "second.js finished execution second.");
|
||||
|
||||
yield extension.unload();
|
||||
win.close();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script contexts</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
|
||||
add_task(function* test_contentscript_context() {
|
||||
function contentScript() {
|
||||
browser.test.sendMessage("content-script-ready");
|
||||
|
||||
window.addEventListener("pagehide", () => {
|
||||
browser.test.sendMessage("content-script-hide");
|
||||
}, true);
|
||||
window.addEventListener("pageshow", () => {
|
||||
browser.test.sendMessage("content-script-show");
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
content_scripts: [{
|
||||
"matches": ["http://example.com/"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_start",
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("http://example.com/");
|
||||
yield extension.awaitMessage("content-script-ready");
|
||||
yield extension.awaitMessage("content-script-show");
|
||||
|
||||
// Get the content script context and check that it points to the correct window.
|
||||
|
||||
let {DocumentManager} = SpecialPowers.Cu.import("resource://gre/modules/ExtensionContent.jsm", {});
|
||||
let context = DocumentManager.getContentScriptContext(extension, win);
|
||||
ok(context != null, "Got content script context");
|
||||
|
||||
is(SpecialPowers.unwrap(context.contentWindow), win, "Context's contentWindow property is correct");
|
||||
|
||||
// Navigate so that the content page is hidden in the bfcache.
|
||||
|
||||
win.location = "http://example.org/";
|
||||
yield extension.awaitMessage("content-script-hide");
|
||||
|
||||
is(context.contentWindow, null, "Context's contentWindow property is null");
|
||||
|
||||
// Navigate back so the content page is resurrected from the bfcache.
|
||||
|
||||
SpecialPowers.wrap(win).history.back();
|
||||
yield extension.awaitMessage("content-script-show");
|
||||
|
||||
is(SpecialPowers.unwrap(context.contentWindow), win, "Context's contentWindow property is correct");
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.awaitMessage("content-script-hide");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- WORKAROUND: this textarea hack is used to contain the html page source without escaping it -->
|
||||
<textarea id="test-asset">
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="content_script_iframe.js"></script>
|
||||
</head>
|
||||
</html>
|
||||
</textarea>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript_create_iframe() {
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener((msg, sender) => {
|
||||
let {name, availableAPIs, manifest, testGetManifest} = msg;
|
||||
let hasExtTabsAPI = availableAPIs.indexOf("tabs") > 0;
|
||||
let hasExtWindowsAPI = availableAPIs.indexOf("windows") > 0;
|
||||
|
||||
browser.test.assertFalse(hasExtTabsAPI, "the created iframe should not be able to use privileged APIs (tabs)");
|
||||
browser.test.assertFalse(hasExtWindowsAPI, "the created iframe should not be able to use privileged APIs (windows)");
|
||||
|
||||
let {applications: {gecko: {id: expectedManifestGeckoId}}} = chrome.runtime.getManifest();
|
||||
let {applications: {gecko: {id: actualManifestGeckoId}}} = manifest;
|
||||
|
||||
browser.test.assertEq(actualManifestGeckoId, expectedManifestGeckoId,
|
||||
"the add-on manifest should be accessible from the created iframe"
|
||||
);
|
||||
|
||||
let {applications: {gecko: {id: testGetManifestGeckoId}}} = testGetManifest;
|
||||
|
||||
browser.test.assertEq(testGetManifestGeckoId, expectedManifestGeckoId,
|
||||
"GET_MANIFEST() returns manifest data before extension unload"
|
||||
);
|
||||
|
||||
browser.test.sendMessage(name);
|
||||
});
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("src", browser.runtime.getURL("content_script_iframe.html"));
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
function contentScriptIframe() {
|
||||
window.GET_MANIFEST = browser.runtime.getManifest.bind(null);
|
||||
|
||||
window.testGetManifestException = () => {
|
||||
try {
|
||||
window.GET_MANIFEST();
|
||||
} catch (exception) {
|
||||
return String(exception);
|
||||
}
|
||||
};
|
||||
|
||||
let testGetManifest = window.GET_MANIFEST();
|
||||
|
||||
let manifest = browser.runtime.getManifest();
|
||||
let availableAPIs = Object.keys(browser);
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
name: "content-script-iframe-loaded",
|
||||
availableAPIs,
|
||||
manifest,
|
||||
testGetManifest,
|
||||
});
|
||||
}
|
||||
|
||||
const ID = "contentscript@tests.mozilla.org";
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
applications: {gecko: {id: ID}},
|
||||
content_scripts: [
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
},
|
||||
],
|
||||
web_accessible_resources: [
|
||||
"content_script_iframe.html",
|
||||
],
|
||||
},
|
||||
|
||||
background,
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
"content_script_iframe.html": document.querySelector("#test-asset").textContent,
|
||||
"content_script_iframe.js": contentScriptIframe,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
let contentScriptIframeCreatedPromise = new Promise(resolve => {
|
||||
extension.onMessage("content-script-iframe-loaded", () => { resolve(); });
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
info("extension loaded");
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield Promise.all([waitForLoad(win), contentScriptIframeCreatedPromise]);
|
||||
info("content script privileged iframe loaded and executed");
|
||||
|
||||
info("testing APIs availability once the extension is unloaded...");
|
||||
|
||||
let iframeWindow = SpecialPowers.wrap(win)[0];
|
||||
|
||||
ok(iframeWindow, "content script enabled iframe found");
|
||||
ok(/content_script_iframe\.html$/.test(iframeWindow.location), "the found iframe has the expected URL");
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
|
||||
info("test content script APIs not accessible from the frame once the extension is unloaded");
|
||||
|
||||
let ww = SpecialPowers.Cu.waiveXrays(iframeWindow);
|
||||
let isDeadWrapper = SpecialPowers.Cu.isDeadWrapper(ww.browser);
|
||||
ok(!isDeadWrapper, "the API object should not be a dead object");
|
||||
|
||||
let manifest;
|
||||
let manifestException;
|
||||
|
||||
try {
|
||||
manifest = ww.browser.runtime.getManifest();
|
||||
} catch (e) {
|
||||
manifestException = e;
|
||||
}
|
||||
|
||||
ok(!manifest, "manifest should be undefined");
|
||||
|
||||
is(String(manifestException), "TypeError: ww.browser.runtime is undefined",
|
||||
"expected exception received");
|
||||
|
||||
let getManifestException = ww.testGetManifestException();
|
||||
|
||||
is(getManifestException, "TypeError: can't access dead object",
|
||||
"expected exception received");
|
||||
|
||||
win.close();
|
||||
|
||||
info("done");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_content_script_css() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"css": ["content.css"],
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content.css": "body { max-width: 42px; }",
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
yield waitForLoad(win);
|
||||
|
||||
let style = win.getComputedStyle(win.document.body);
|
||||
is(style.maxWidth, "42px", "Stylesheet correctly applied");
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
style = win.getComputedStyle(win.document.body);
|
||||
is(style.maxWidth, "none", "Stylesheet correctly removed");
|
||||
|
||||
win.close();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Sandbox metadata on WebExtensions ContentScripts</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript_devtools_sandbox_metadata() {
|
||||
function contentScript() {
|
||||
browser.runtime.sendMessage("contentScript.executed");
|
||||
}
|
||||
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener((msg) => {
|
||||
if (msg == "contentScript.executed") {
|
||||
browser.test.notifyPass("contentScript.executed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
background,
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
let innerWindowID = SpecialPowers.wrap(win)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
|
||||
.getInterface(SpecialPowers.Ci.nsIDOMWindowUtils)
|
||||
.currentInnerWindowID;
|
||||
|
||||
yield extension.awaitFinish("contentScript.executed");
|
||||
|
||||
const {ExtensionContent} = SpecialPowers.Cu.import(
|
||||
"resource://gre/modules/ExtensionContent.jsm", {}
|
||||
);
|
||||
|
||||
let res = ExtensionContent.getContentScriptGlobalsForWindow(win);
|
||||
is(res.length, 1, "Got the expected array of globals");
|
||||
let metadata = SpecialPowers.Cu.getSandboxMetadata(res[0]) || {};
|
||||
|
||||
is(metadata.addonId, extension.id, "Got the expected addonId");
|
||||
is(metadata["inner-window-id"], innerWindowID, "Got the expected inner-window-id");
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
|
||||
res = ExtensionContent.getContentScriptGlobalsForWindow(win);
|
||||
is(res.length, 0, "No content scripts globals found once the extension is unloaded");
|
||||
|
||||
win.close();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript_exportHelpers() {
|
||||
function contentScript() {
|
||||
browser.test.assertTrue(typeof cloneInto === "function");
|
||||
browser.test.assertTrue(typeof createObjectIn === "function");
|
||||
browser.test.assertTrue(typeof exportFunction === "function");
|
||||
|
||||
/* globals exportFunction, precisePi, reportPi */
|
||||
let value = 3.14;
|
||||
exportFunction(() => value, window, {defineAs: "precisePi"});
|
||||
|
||||
browser.test.assertEq("undefined", typeof precisePi,
|
||||
"exportFunction should export to the page's scope only");
|
||||
|
||||
browser.test.assertEq("undefined", typeof window.precisePi,
|
||||
"exportFunction should export to the page's scope only");
|
||||
|
||||
let results = [];
|
||||
exportFunction(pi => results.push(pi), window, {defineAs: "reportPi"});
|
||||
|
||||
let s = document.createElement("script");
|
||||
s.textContent = `(${function() {
|
||||
let result1 = "unknown 1";
|
||||
let result2 = "unknown 2";
|
||||
try {
|
||||
result1 = precisePi();
|
||||
} catch (e) {
|
||||
result1 = "err:" + e;
|
||||
}
|
||||
try {
|
||||
result2 = window.precisePi();
|
||||
} catch (e) {
|
||||
result2 = "err:" + e;
|
||||
}
|
||||
reportPi(result1);
|
||||
reportPi(result2);
|
||||
}})();`;
|
||||
|
||||
document.documentElement.appendChild(s);
|
||||
// Inline script ought to run synchronously.
|
||||
|
||||
browser.test.assertEq(3.14, results[0],
|
||||
"exportFunction on window should define a global function");
|
||||
browser.test.assertEq(3.14, results[1],
|
||||
"exportFunction on window should export a property to window.");
|
||||
|
||||
browser.test.assertEq(2, results.length,
|
||||
"Expecting the number of results to match the number of method calls");
|
||||
|
||||
browser.test.notifyPass("export helper test completed");
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [{
|
||||
js: ["contentscript.js"],
|
||||
matches: ["http://mochi.test/*/file_sample.html"],
|
||||
run_at: "document_start",
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"contentscript.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield extension.awaitFinish("export helper test completed");
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script private browsing ID</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript_incognito() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
content_scripts: [
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
background() {
|
||||
let windowId;
|
||||
|
||||
browser.test.onMessage.addListener(([msg, url]) => {
|
||||
if (msg === "open-window") {
|
||||
browser.windows.create({url, incognito: true}).then(window => {
|
||||
windowId = window.id;
|
||||
});
|
||||
} else if (msg === "close-window") {
|
||||
browser.windows.remove(windowId).then(() => {
|
||||
browser.test.sendMessage("done");
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": async () => {
|
||||
const COOKIE = "foo=florgheralzps";
|
||||
document.cookie = COOKIE;
|
||||
|
||||
let url = new URL("return_headers.sjs", location.href);
|
||||
|
||||
let responses = [
|
||||
new Promise(resolve => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url);
|
||||
xhr.onload = () => resolve(JSON.parse(xhr.responseText));
|
||||
xhr.send();
|
||||
}),
|
||||
|
||||
fetch(url, {credentials: "include"}).then(body => body.json()),
|
||||
];
|
||||
|
||||
try {
|
||||
for (let response of await Promise.all(responses)) {
|
||||
browser.test.assertEq(COOKIE, response.cookie, "Got expected cookie header");
|
||||
}
|
||||
browser.test.notifyPass("cookies");
|
||||
} catch (e) {
|
||||
browser.test.fail(`Error: ${e}`);
|
||||
browser.test.notifyFail("cookies");
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
extension.sendMessage(["open-window", SimpleTest.getTestFileURL("file_sample.html")]);
|
||||
|
||||
yield extension.awaitFinish("cookies");
|
||||
|
||||
extension.sendMessage(["close-window"]);
|
||||
yield extension.awaitMessage("done");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
function background() {
|
||||
browser.test.onMessage.addListener(url => {
|
||||
browser.tabs.create({url}).then(tab => {
|
||||
return browser.tabs.executeScript(tab.id, {code: "true;"})
|
||||
.then(() => {
|
||||
browser.test.sendMessage("executed", true);
|
||||
browser.tabs.remove([tab.id]);
|
||||
}, err => {
|
||||
browser.test.sendMessage("executed", false);
|
||||
browser.tabs.remove([tab.id]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
permissions: ["<all_urls>"],
|
||||
},
|
||||
background,
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
extension.sendMessage("https://example.com");
|
||||
let result = yield extension.awaitMessage("executed");
|
||||
is(result, true, "Content script can be run in a page without mozAddonManager");
|
||||
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.webapi.testing", true]],
|
||||
});
|
||||
|
||||
extension.sendMessage("https://example.com");
|
||||
result = yield extension.awaitMessage("executed");
|
||||
is(result, false, "Content script cannot be run in a page with mozAddonManager");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script teardown</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript_reload_and_unload() {
|
||||
function contentScript() {
|
||||
browser.test.sendMessage("contentscript-run");
|
||||
}
|
||||
function background() {
|
||||
let removedTabs = 0;
|
||||
browser.tabs.onRemoved.addListener(() => {
|
||||
browser.test.assertEq(1, ++removedTabs,
|
||||
"Expected only one tab to be removed during the test");
|
||||
browser.test.sendMessage("tab-closed");
|
||||
});
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
manifest: {
|
||||
content_scripts: [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["contentscript.js"],
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"contentscript.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let chromeScript = SpecialPowers.loadChromeScript(
|
||||
SimpleTest.getTestFileURL("file_teardown_test.js"));
|
||||
yield chromeScript.promiseOneMessage("chromescript-startup");
|
||||
function* getContextEvents() {
|
||||
chromeScript.sendAsyncMessage("get-context-events");
|
||||
let contextEvents = yield chromeScript.promiseOneMessage("context-events");
|
||||
return contextEvents.filter(event => event.extensionId == extension.id);
|
||||
}
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
yield extension.awaitMessage("contentscript-run");
|
||||
let tabUrl = win.location.href;
|
||||
|
||||
let contextEvents = yield* getContextEvents();
|
||||
is(contextEvents.length, 1,
|
||||
"ExtensionContext state change after loading a content script");
|
||||
is(contextEvents[0].eventType, "load",
|
||||
"Create ExtensionContext for content script");
|
||||
is(contextEvents[0].url, tabUrl, "ExtensionContext URL = page");
|
||||
|
||||
let promiseReload = extension.awaitMessage("contentscript-run");
|
||||
win.location.reload();
|
||||
yield promiseReload;
|
||||
contextEvents = yield* getContextEvents();
|
||||
is(contextEvents.length, 2,
|
||||
"ExtensionContext state changes after reloading a content script");
|
||||
is(contextEvents[0].eventType, "unload", "Unload old ExtensionContext");
|
||||
is(contextEvents[0].url, tabUrl, "ExtensionContext URL = page");
|
||||
is(contextEvents[1].eventType, "load",
|
||||
"Create new ExtensionContext for content script");
|
||||
is(contextEvents[1].url, tabUrl, "ExtensionContext URL = page");
|
||||
|
||||
let tabClosePromise = extension.awaitMessage("tab-closed");
|
||||
win.close();
|
||||
yield tabClosePromise;
|
||||
|
||||
contextEvents = yield* getContextEvents();
|
||||
is(contextEvents.length, 1,
|
||||
"ExtensionContext state change after unloading a content script");
|
||||
is(contextEvents[0].eventType, "unload",
|
||||
"Unload ExtensionContext after closing the tab with the content script");
|
||||
is(contextEvents[0].url, tabUrl, "ExtensionContext URL = page");
|
||||
|
||||
chromeScript.sendAsyncMessage("cleanup");
|
||||
chromeScript.destroy();
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_cookies() {
|
||||
async function background() {
|
||||
function assertExpected(expected, cookie) {
|
||||
for (let key of Object.keys(cookie)) {
|
||||
browser.test.assertTrue(key in expected, `found property ${key}`);
|
||||
browser.test.assertEq(expected[key], cookie[key], `property value for ${key} is correct`);
|
||||
}
|
||||
browser.test.assertEq(Object.keys(expected).length, Object.keys(cookie).length, "all expected properties found");
|
||||
}
|
||||
|
||||
const TEST_URL = "http://example.org/";
|
||||
const TEST_SECURE_URL = "https://example.org/";
|
||||
const THE_FUTURE = Date.now() + 5 * 60;
|
||||
const TEST_PATH = "set_path";
|
||||
const TEST_URL_WITH_PATH = TEST_URL + TEST_PATH;
|
||||
const TEST_COOKIE_PATH = `/${TEST_PATH}`;
|
||||
const STORE_ID = "firefox-default";
|
||||
const PRIVATE_STORE_ID = "firefox-private";
|
||||
|
||||
let expected = {
|
||||
name: "name1",
|
||||
value: "value1",
|
||||
domain: "example.org",
|
||||
hostOnly: true,
|
||||
path: "/",
|
||||
secure: false,
|
||||
httpOnly: false,
|
||||
session: false,
|
||||
expirationDate: THE_FUTURE,
|
||||
storeId: STORE_ID,
|
||||
};
|
||||
|
||||
let cookie = await browser.cookies.set({url: TEST_URL, name: "name1", value: "value1", expirationDate: THE_FUTURE});
|
||||
assertExpected(expected, cookie);
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "name1"});
|
||||
assertExpected(expected, cookie);
|
||||
|
||||
let cookies = await browser.cookies.getAll({name: "name1"});
|
||||
browser.test.assertEq(cookies.length, 1, "one cookie found for matching name");
|
||||
assertExpected(expected, cookies[0]);
|
||||
|
||||
cookies = await browser.cookies.getAll({domain: "example.org"});
|
||||
browser.test.assertEq(cookies.length, 1, "one cookie found for matching domain");
|
||||
assertExpected(expected, cookies[0]);
|
||||
|
||||
cookies = await browser.cookies.getAll({domain: "example.net"});
|
||||
browser.test.assertEq(cookies.length, 0, "no cookies found for non-matching domain");
|
||||
|
||||
cookies = await browser.cookies.getAll({secure: false});
|
||||
browser.test.assertEq(cookies.length, 1, "one non-secure cookie found");
|
||||
assertExpected(expected, cookies[0]);
|
||||
|
||||
cookies = await browser.cookies.getAll({secure: true});
|
||||
browser.test.assertEq(cookies.length, 0, "no secure cookies found");
|
||||
|
||||
cookies = await browser.cookies.getAll({storeId: STORE_ID});
|
||||
browser.test.assertEq(cookies.length, 1, "one cookie found for valid storeId");
|
||||
assertExpected(expected, cookies[0]);
|
||||
|
||||
cookies = await browser.cookies.getAll({storeId: "invalid_id"});
|
||||
browser.test.assertEq(cookies.length, 0, "no cookies found for invalid storeId");
|
||||
|
||||
let details = await browser.cookies.remove({url: TEST_URL, name: "name1"});
|
||||
assertExpected({url: TEST_URL, name: "name1", storeId: STORE_ID}, details);
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "name1"});
|
||||
browser.test.assertEq(null, cookie, "removed cookie not found");
|
||||
|
||||
let stores = await browser.cookies.getAllCookieStores();
|
||||
browser.test.assertEq(1, stores.length, "expected number of stores returned");
|
||||
browser.test.assertEq(STORE_ID, stores[0].id, "expected store id returned");
|
||||
browser.test.assertEq(1, stores[0].tabIds.length, "one tab returned for store");
|
||||
|
||||
{
|
||||
let privateWindow = await browser.windows.create({incognito: true});
|
||||
let stores = await browser.cookies.getAllCookieStores();
|
||||
|
||||
browser.test.assertEq(2, stores.length, "expected number of stores returned");
|
||||
browser.test.assertEq(STORE_ID, stores[0].id, "expected store id returned");
|
||||
browser.test.assertEq(1, stores[0].tabIds.length, "one tab returned for store");
|
||||
browser.test.assertEq(PRIVATE_STORE_ID, stores[1].id, "expected private store id returned");
|
||||
browser.test.assertEq(1, stores[0].tabIds.length, "one tab returned for private store");
|
||||
|
||||
await browser.windows.remove(privateWindow.id);
|
||||
}
|
||||
|
||||
cookie = await browser.cookies.set({url: TEST_URL, name: "name2", domain: ".example.org", expirationDate: THE_FUTURE});
|
||||
browser.test.assertEq(false, cookie.hostOnly, "cookie is not a hostOnly cookie");
|
||||
|
||||
details = await browser.cookies.remove({url: TEST_URL, name: "name2"});
|
||||
assertExpected({url: TEST_URL, name: "name2", storeId: STORE_ID}, details);
|
||||
|
||||
// Create a session cookie.
|
||||
cookie = await browser.cookies.set({url: TEST_URL, name: "name1", value: "value1"});
|
||||
browser.test.assertEq(true, cookie.session, "session cookie set");
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "name1"});
|
||||
browser.test.assertEq(true, cookie.session, "got session cookie");
|
||||
|
||||
cookies = await browser.cookies.getAll({session: true});
|
||||
browser.test.assertEq(cookies.length, 1, "one session cookie found");
|
||||
browser.test.assertEq(true, cookies[0].session, "found session cookie");
|
||||
|
||||
cookies = await browser.cookies.getAll({session: false});
|
||||
browser.test.assertEq(cookies.length, 0, "no non-session cookies found");
|
||||
|
||||
details = await browser.cookies.remove({url: TEST_URL, name: "name1"});
|
||||
assertExpected({url: TEST_URL, name: "name1", storeId: STORE_ID}, details);
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "name1"});
|
||||
browser.test.assertEq(null, cookie, "removed cookie not found");
|
||||
|
||||
cookie = await browser.cookies.set({url: TEST_SECURE_URL, name: "name1", value: "value1", secure: true});
|
||||
browser.test.assertEq(true, cookie.secure, "secure cookie set");
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_SECURE_URL, name: "name1"});
|
||||
browser.test.assertEq(true, cookie.session, "got secure cookie");
|
||||
|
||||
cookies = await browser.cookies.getAll({secure: true});
|
||||
browser.test.assertEq(cookies.length, 1, "one secure cookie found");
|
||||
browser.test.assertEq(true, cookies[0].secure, "found secure cookie");
|
||||
|
||||
cookies = await browser.cookies.getAll({secure: false});
|
||||
browser.test.assertEq(cookies.length, 0, "no non-secure cookies found");
|
||||
|
||||
details = await browser.cookies.remove({url: TEST_SECURE_URL, name: "name1"});
|
||||
assertExpected({url: TEST_SECURE_URL, name: "name1", storeId: STORE_ID}, details);
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_SECURE_URL, name: "name1"});
|
||||
browser.test.assertEq(null, cookie, "removed cookie not found");
|
||||
|
||||
cookie = await browser.cookies.set({url: TEST_URL_WITH_PATH, path: TEST_COOKIE_PATH, name: "name1", value: "value1", expirationDate: THE_FUTURE});
|
||||
browser.test.assertEq(TEST_COOKIE_PATH, cookie.path, "created cookie with path");
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL_WITH_PATH, name: "name1"});
|
||||
browser.test.assertEq(TEST_COOKIE_PATH, cookie.path, "got cookie with path");
|
||||
|
||||
cookies = await browser.cookies.getAll({path: TEST_COOKIE_PATH});
|
||||
browser.test.assertEq(cookies.length, 1, "one cookie with path found");
|
||||
browser.test.assertEq(TEST_COOKIE_PATH, cookies[0].path, "found cookie with path");
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL + "invalid_path", name: "name1"});
|
||||
browser.test.assertEq(null, cookie, "get with invalid path returns null");
|
||||
|
||||
cookies = await browser.cookies.getAll({path: "/invalid_path"});
|
||||
browser.test.assertEq(cookies.length, 0, "getAll with invalid path returns 0 cookies");
|
||||
|
||||
details = await browser.cookies.remove({url: TEST_URL_WITH_PATH, name: "name1"});
|
||||
assertExpected({url: TEST_URL_WITH_PATH, name: "name1", storeId: STORE_ID}, details);
|
||||
|
||||
cookie = await browser.cookies.set({url: TEST_URL, name: "name1", value: "value1", httpOnly: true});
|
||||
browser.test.assertEq(true, cookie.httpOnly, "httpOnly cookie set");
|
||||
|
||||
cookie = await browser.cookies.set({url: TEST_URL, name: "name1", value: "value1", httpOnly: false});
|
||||
browser.test.assertEq(false, cookie.httpOnly, "non-httpOnly cookie set");
|
||||
|
||||
details = await browser.cookies.remove({url: TEST_URL, name: "name1"});
|
||||
assertExpected({url: TEST_URL, name: "name1", storeId: STORE_ID}, details);
|
||||
|
||||
cookie = await browser.cookies.set({url: TEST_URL});
|
||||
browser.test.assertEq("", cookie.name, "default name set");
|
||||
browser.test.assertEq("", cookie.value, "default value set");
|
||||
browser.test.assertEq(true, cookie.session, "no expiry date created session cookie");
|
||||
|
||||
{
|
||||
let privateWindow = await browser.windows.create({incognito: true});
|
||||
|
||||
// Hacky work-around for bugzil.la/1309637
|
||||
await new Promise(resolve => setTimeout(resolve, 700));
|
||||
|
||||
let cookie = await browser.cookies.set({url: TEST_URL, name: "store", value: "private", expirationDate: THE_FUTURE, storeId: PRIVATE_STORE_ID});
|
||||
browser.test.assertEq("private", cookie.value, "set the private cookie");
|
||||
|
||||
cookie = await browser.cookies.set({url: TEST_URL, name: "store", value: "default", expirationDate: THE_FUTURE, storeId: STORE_ID});
|
||||
browser.test.assertEq("default", cookie.value, "set the default cookie");
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "store", storeId: PRIVATE_STORE_ID});
|
||||
browser.test.assertEq("private", cookie.value, "get the private cookie");
|
||||
browser.test.assertEq(PRIVATE_STORE_ID, cookie.storeId, "get the private cookie storeId");
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "store", storeId: STORE_ID});
|
||||
browser.test.assertEq("default", cookie.value, "get the default cookie");
|
||||
browser.test.assertEq(STORE_ID, cookie.storeId, "get the default cookie storeId");
|
||||
|
||||
let details = await browser.cookies.remove({url: TEST_URL, name: "store", storeId: STORE_ID});
|
||||
assertExpected({url: TEST_URL, name: "store", storeId: STORE_ID}, details);
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "store", storeId: STORE_ID});
|
||||
browser.test.assertEq(null, cookie, "deleted the default cookie");
|
||||
|
||||
details = await browser.cookies.remove({url: TEST_URL, name: "store", storeId: PRIVATE_STORE_ID});
|
||||
assertExpected({url: TEST_URL, name: "store", storeId: PRIVATE_STORE_ID}, details);
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "store", storeId: PRIVATE_STORE_ID});
|
||||
browser.test.assertEq(null, cookie, "deleted the private cookie");
|
||||
|
||||
await browser.windows.remove(privateWindow.id);
|
||||
}
|
||||
|
||||
browser.test.notifyPass("cookies");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
manifest: {
|
||||
permissions: ["cookies", "*://example.org/"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("cookies");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* setup() {
|
||||
// make sure userContext is enabled.
|
||||
return SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true],
|
||||
]});
|
||||
});
|
||||
|
||||
add_task(function* test_cookie_containers() {
|
||||
async function background() {
|
||||
function assertExpected(expected, cookie) {
|
||||
for (let key of Object.keys(cookie)) {
|
||||
browser.test.assertTrue(key in expected, `found property ${key}`);
|
||||
browser.test.assertEq(expected[key], cookie[key], `property value for ${key} is correct`);
|
||||
}
|
||||
browser.test.assertEq(Object.keys(expected).length, Object.keys(cookie).length, "all expected properties found");
|
||||
}
|
||||
|
||||
const TEST_URL = "http://example.org/";
|
||||
const THE_FUTURE = Date.now() + 5 * 60;
|
||||
|
||||
let expected = {
|
||||
name: "name1",
|
||||
value: "value1",
|
||||
domain: "example.org",
|
||||
hostOnly: true,
|
||||
path: "/",
|
||||
secure: false,
|
||||
httpOnly: false,
|
||||
session: false,
|
||||
expirationDate: THE_FUTURE,
|
||||
storeId: "firefox-container-1",
|
||||
};
|
||||
|
||||
let cookie = await browser.cookies.set({
|
||||
url: TEST_URL, name: "name1", value: "value1",
|
||||
expirationDate: THE_FUTURE, storeId: "firefox-container-1",
|
||||
});
|
||||
browser.test.assertEq("firefox-container-1", cookie.storeId, "the cookie has the correct storeId");
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "name1"});
|
||||
browser.test.assertEq(null, cookie, "get() without storeId returns null");
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "name1", storeId: "firefox-container-1"});
|
||||
assertExpected(expected, cookie);
|
||||
|
||||
let cookies = await browser.cookies.getAll({storeId: "firefox-default"});
|
||||
browser.test.assertEq(0, cookies.length, "getAll() with default storeId returns an empty array");
|
||||
|
||||
cookies = await browser.cookies.getAll({storeId: "firefox-container-1"});
|
||||
browser.test.assertEq(1, cookies.length, "one cookie found for matching domain");
|
||||
assertExpected(expected, cookies[0]);
|
||||
|
||||
let details = await browser.cookies.remove({url: TEST_URL, name: "name1", storeId: "firefox-container-1"});
|
||||
assertExpected({url: TEST_URL, name: "name1", storeId: "firefox-container-1"}, details);
|
||||
|
||||
cookie = await browser.cookies.get({url: TEST_URL, name: "name1", storeId: "firefox-container-1"});
|
||||
browser.test.assertEq(null, cookie, "removed cookie not found");
|
||||
|
||||
browser.test.notifyPass("cookies");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
manifest: {
|
||||
permissions: ["cookies", "*://example.org/"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("cookies");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_cookies_expiry() {
|
||||
function background() {
|
||||
let expectedEvents = [];
|
||||
|
||||
browser.cookies.onChanged.addListener(event => {
|
||||
expectedEvents.push(`${event.removed}:${event.cause}`);
|
||||
if (expectedEvents.length === 1) {
|
||||
browser.test.assertEq("true:expired", expectedEvents[0], "expired cookie removed");
|
||||
browser.test.assertEq("first", event.cookie.name, "expired cookie has the expected name");
|
||||
browser.test.assertEq("one", event.cookie.value, "expired cookie has the expected value");
|
||||
} else {
|
||||
browser.test.assertEq("false:explicit", expectedEvents[1], "new cookie added");
|
||||
browser.test.assertEq("first", event.cookie.name, "new cookie has the expected name");
|
||||
browser.test.assertEq("one-again", event.cookie.value, "new cookie has the expected value");
|
||||
browser.test.notifyPass("cookie-expiry");
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
browser.test.sendMessage("change-cookies");
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
let domain = ".example.com";
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"permissions": ["http://example.com/", "cookies"],
|
||||
},
|
||||
background,
|
||||
});
|
||||
|
||||
let cookieSvc = SpecialPowers.Services.cookies;
|
||||
|
||||
let cookie = {
|
||||
host: domain,
|
||||
name: "first",
|
||||
path: "/",
|
||||
};
|
||||
|
||||
do {
|
||||
cookieSvc.add(cookie.host, cookie.path, cookie.name, "one", false, false, false, Date.now() / 1000 + 1);
|
||||
} while (!cookieSvc.cookieExists(cookie));
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("change-cookies");
|
||||
|
||||
cookieSvc.add(cookie.host, cookie.path, cookie.name, "one-again", false, false, false, Date.now() / 1000 + 10);
|
||||
|
||||
yield extension.awaitFinish("cookie-expiry");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<script type="text/javascript" src="head_cookies.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* init() {
|
||||
// We need to trigger a cookie eviction in order to test our batch delete
|
||||
// observer.
|
||||
SpecialPowers.setIntPref("network.cookie.maxPerHost", 3);
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
SpecialPowers.clearUserPref("network.cookie.maxPerHost");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_bad_cookie_permissions() {
|
||||
info("Test non-matching, non-secure domain with non-secure cookie");
|
||||
yield testCookies({
|
||||
permissions: ["http://example.com/", "cookies"],
|
||||
url: "http://example.net/",
|
||||
domain: "example.net",
|
||||
secure: false,
|
||||
shouldPass: false,
|
||||
shouldWrite: false,
|
||||
});
|
||||
|
||||
info("Test non-matching, secure domain with non-secure cookie");
|
||||
yield testCookies({
|
||||
permissions: ["https://example.com/", "cookies"],
|
||||
url: "https://example.net/",
|
||||
domain: "example.net",
|
||||
secure: false,
|
||||
shouldPass: false,
|
||||
shouldWrite: false,
|
||||
});
|
||||
|
||||
info("Test non-matching, secure domain with secure cookie");
|
||||
yield testCookies({
|
||||
permissions: ["https://example.com/", "cookies"],
|
||||
url: "https://example.net/",
|
||||
domain: "example.net",
|
||||
secure: false,
|
||||
shouldPass: false,
|
||||
shouldWrite: false,
|
||||
});
|
||||
|
||||
info("Test matching subdomain with superdomain privileges, secure cookie (http)");
|
||||
yield testCookies({
|
||||
permissions: ["http://foo.bar.example.com/", "cookies"],
|
||||
url: "http://foo.bar.example.com/",
|
||||
domain: ".example.com",
|
||||
secure: true,
|
||||
shouldPass: false,
|
||||
shouldWrite: true,
|
||||
});
|
||||
|
||||
info("Test matching, non-secure domain with secure cookie");
|
||||
yield testCookies({
|
||||
permissions: ["http://example.com/", "cookies"],
|
||||
url: "http://example.com/",
|
||||
domain: "example.com",
|
||||
secure: true,
|
||||
shouldPass: false,
|
||||
shouldWrite: true,
|
||||
});
|
||||
|
||||
info("Test matching, non-secure host, secure URL");
|
||||
yield testCookies({
|
||||
permissions: ["http://example.com/", "cookies"],
|
||||
url: "https://example.com/",
|
||||
domain: "example.com",
|
||||
secure: true,
|
||||
shouldPass: false,
|
||||
shouldWrite: false,
|
||||
});
|
||||
|
||||
info("Test non-matching domain");
|
||||
yield testCookies({
|
||||
permissions: ["http://example.com/", "cookies"],
|
||||
url: "http://example.com/",
|
||||
domain: "example.net",
|
||||
secure: false,
|
||||
shouldPass: false,
|
||||
shouldWrite: false,
|
||||
});
|
||||
|
||||
info("Test invalid scheme");
|
||||
yield testCookies({
|
||||
permissions: ["ftp://example.com/", "cookies"],
|
||||
url: "ftp://example.com/",
|
||||
domain: "example.com",
|
||||
secure: false,
|
||||
shouldPass: false,
|
||||
shouldWrite: false,
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<script type="text/javascript" src="head_cookies.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* init() {
|
||||
// We need to trigger a cookie eviction in order to test our batch delete
|
||||
// observer.
|
||||
SpecialPowers.setIntPref("network.cookie.maxPerHost", 3);
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
SpecialPowers.clearUserPref("network.cookie.maxPerHost");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_good_cookie_permissions() {
|
||||
info("Test matching, non-secure domain with non-secure cookie");
|
||||
yield testCookies({
|
||||
permissions: ["http://example.com/", "cookies"],
|
||||
url: "http://example.com/",
|
||||
domain: "example.com",
|
||||
secure: false,
|
||||
shouldPass: true,
|
||||
});
|
||||
|
||||
info("Test matching, secure domain with non-secure cookie");
|
||||
yield testCookies({
|
||||
permissions: ["https://example.com/", "cookies"],
|
||||
url: "https://example.com/",
|
||||
domain: "example.com",
|
||||
secure: false,
|
||||
shouldPass: true,
|
||||
});
|
||||
|
||||
info("Test matching, secure domain with secure cookie");
|
||||
yield testCookies({
|
||||
permissions: ["https://example.com/", "cookies"],
|
||||
url: "https://example.com/",
|
||||
domain: "example.com",
|
||||
secure: true,
|
||||
shouldPass: true,
|
||||
});
|
||||
|
||||
info("Test matching subdomain with superdomain privileges, secure cookie (https)");
|
||||
yield testCookies({
|
||||
permissions: ["https://foo.bar.example.com/", "cookies"],
|
||||
url: "https://foo.bar.example.com/",
|
||||
domain: ".example.com",
|
||||
secure: true,
|
||||
shouldPass: true,
|
||||
});
|
||||
|
||||
info("Test matching subdomain with superdomain privileges, non-secure cookie (https)");
|
||||
yield testCookies({
|
||||
permissions: ["https://foo.bar.example.com/", "cookies"],
|
||||
url: "https://foo.bar.example.com/",
|
||||
domain: ".example.com",
|
||||
secure: false,
|
||||
shouldPass: true,
|
||||
});
|
||||
|
||||
info("Test matching subdomain with superdomain privileges, non-secure cookie (http)");
|
||||
yield testCookies({
|
||||
permissions: ["http://foo.bar.example.com/", "cookies"],
|
||||
url: "http://foo.bar.example.com/",
|
||||
domain: ".example.com",
|
||||
secure: false,
|
||||
shouldPass: true,
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener(([script], sender) => {
|
||||
browser.test.sendMessage("run", {script});
|
||||
browser.test.sendMessage("run-" + script);
|
||||
});
|
||||
browser.test.sendMessage("running");
|
||||
}
|
||||
|
||||
function contentScriptAll() {
|
||||
browser.runtime.sendMessage(["all"]);
|
||||
}
|
||||
function contentScriptIncludesTest1() {
|
||||
browser.runtime.sendMessage(["includes-test1"]);
|
||||
}
|
||||
function contentScriptExcludesTest1() {
|
||||
browser.runtime.sendMessage(["excludes-test1"]);
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [
|
||||
{
|
||||
"matches": ["http://example.org/", "http://*.example.org/"],
|
||||
"exclude_globs": [],
|
||||
"include_globs": ["*"],
|
||||
"js": ["content_script_all.js"],
|
||||
},
|
||||
{
|
||||
"matches": ["http://example.org/", "http://*.example.org/"],
|
||||
"include_globs": ["*test1*"],
|
||||
"js": ["content_script_includes_test1.js"],
|
||||
},
|
||||
{
|
||||
"matches": ["http://example.org/", "http://*.example.org/"],
|
||||
"exclude_globs": ["*test1*"],
|
||||
"js": ["content_script_excludes_test1.js"],
|
||||
},
|
||||
],
|
||||
},
|
||||
background,
|
||||
|
||||
files: {
|
||||
"content_script_all.js": contentScriptAll,
|
||||
"content_script_includes_test1.js": contentScriptIncludesTest1,
|
||||
"content_script_excludes_test1.js": contentScriptExcludesTest1,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
let ran = 0;
|
||||
extension.onMessage("run", ({script}) => {
|
||||
ran++;
|
||||
});
|
||||
|
||||
yield Promise.all([extension.startup(), extension.awaitMessage("running")]);
|
||||
info("extension loaded");
|
||||
|
||||
let win = window.open("http://example.org/");
|
||||
yield Promise.all([extension.awaitMessage("run-all"), extension.awaitMessage("run-excludes-test1")]);
|
||||
win.close();
|
||||
is(ran, 2);
|
||||
|
||||
win = window.open("http://test1.example.org/");
|
||||
yield Promise.all([extension.awaitMessage("run-all"), extension.awaitMessage("run-includes-test1")]);
|
||||
win.close();
|
||||
is(ran, 4);
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for generating WebExtensions</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function background() {
|
||||
browser.test.log("running background script");
|
||||
|
||||
browser.test.onMessage.addListener((x, y) => {
|
||||
browser.test.assertEq(x, 10, "x is 10");
|
||||
browser.test.assertEq(y, 20, "y is 20");
|
||||
|
||||
browser.test.notifyPass("background test passed");
|
||||
});
|
||||
|
||||
browser.test.sendMessage("running", 1);
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
};
|
||||
|
||||
add_task(function* test_background() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
info("load complete");
|
||||
let [, x] = yield Promise.all([extension.startup(), extension.awaitMessage("running")]);
|
||||
is(x, 1, "got correct value from extension");
|
||||
info("startup complete");
|
||||
extension.sendMessage(10, 20);
|
||||
yield extension.awaitFinish();
|
||||
info("test complete");
|
||||
yield extension.unload();
|
||||
info("extension unloaded successfully");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener(([url1, url2]) => {
|
||||
let url3 = browser.runtime.getURL("test_file.html");
|
||||
let url4 = browser.extension.getURL("test_file.html");
|
||||
|
||||
browser.test.assertTrue(url1 !== undefined, "url1 defined");
|
||||
|
||||
browser.test.assertTrue(url1.startsWith("moz-extension://"), "url1 has correct scheme");
|
||||
browser.test.assertTrue(url1.endsWith("test_file.html"), "url1 has correct leaf name");
|
||||
|
||||
browser.test.assertEq(url1, url2, "url2 matches");
|
||||
browser.test.assertEq(url1, url3, "url3 matches");
|
||||
browser.test.assertEq(url1, url4, "url4 matches");
|
||||
|
||||
browser.test.notifyPass("geturl");
|
||||
});
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
let url1 = browser.runtime.getURL("test_file.html");
|
||||
let url2 = browser.extension.getURL("test_file.html");
|
||||
browser.runtime.sendMessage([url1, url2]);
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
manifest: {
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield Promise.all([waitForLoad(win), extension.awaitFinish("geturl")]);
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for WebExtension localization APIs</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
SimpleTest.registerCleanupFunction(() => { SpecialPowers.clearUserPref("intl.accept_languages"); });
|
||||
SimpleTest.registerCleanupFunction(() => { SpecialPowers.clearUserPref("general.useragent.locale"); });
|
||||
|
||||
add_task(function* test_i18n() {
|
||||
function runTests(assertEq) {
|
||||
let _ = browser.i18n.getMessage.bind(browser.i18n);
|
||||
|
||||
let url = browser.runtime.getURL("/");
|
||||
assertEq(url, `moz-extension://${_("@@extension_id")}/`, "@@extension_id builtin message");
|
||||
|
||||
assertEq("Foo.", _("Foo"), "Simple message in selected locale.");
|
||||
|
||||
assertEq("(bar)", _("bar"), "Simple message fallback in default locale.");
|
||||
|
||||
assertEq("", _("some-unknown-locale-string"), "Unknown locale string.");
|
||||
|
||||
assertEq("", _("@@unknown_builtin_string"), "Unknown built-in string.");
|
||||
assertEq("", _("@@bidi_unknown_builtin_string"), "Unknown built-in bidi string.");
|
||||
|
||||
assertEq("Føo.", _("Föo"), "Multi-byte message in selected locale.");
|
||||
|
||||
let substitutions = [];
|
||||
substitutions[4] = "5";
|
||||
substitutions[13] = "14";
|
||||
|
||||
assertEq("'$0' '14' '' '5' '$$$$' '$'.", _("basic_substitutions", substitutions),
|
||||
"Basic numeric substitutions");
|
||||
|
||||
assertEq("'$0' '' 'just a string' '' '$$$$' '$'.", _("basic_substitutions", "just a string"),
|
||||
"Basic numeric substitutions, with non-array value");
|
||||
|
||||
let values = _("named_placeholder_substitutions", ["(subst $1 $2)", "(2 $1 $2)"]).split("\n");
|
||||
|
||||
assertEq("_foo_ (subst $1 $2) _bar_", values[0], "Named and numeric substitution");
|
||||
|
||||
assertEq("(2 $1 $2)", values[1], "Numeric substitution amid named placeholders");
|
||||
|
||||
assertEq("$bad name$", values[2], "Named placeholder with invalid key");
|
||||
|
||||
assertEq("", values[3], "Named placeholder with an invalid value");
|
||||
|
||||
assertEq("Accepted, but shouldn't break.", values[4], "Named placeholder with a strange content value");
|
||||
|
||||
assertEq("$foo", values[5], "Non-placeholder token that should be ignored");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"default_locale": "jp",
|
||||
|
||||
content_scripts: [
|
||||
{"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content.js"]},
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
files: {
|
||||
"_locales/en_US/messages.json": {
|
||||
"foo": {
|
||||
"message": "Foo.",
|
||||
"description": "foo",
|
||||
},
|
||||
|
||||
"föo": {
|
||||
"message": "Føo.",
|
||||
"description": "foo",
|
||||
},
|
||||
|
||||
"basic_substitutions": {
|
||||
"message": "'$0' '$14' '$1' '$5' '$$$$$' '$$'.",
|
||||
"description": "foo",
|
||||
},
|
||||
|
||||
"Named_placeholder_substitutions": {
|
||||
"message": "$Foo$\n$2\n$bad name$\n$bad_value$\n$bad_content_value$\n$foo",
|
||||
"description": "foo",
|
||||
"placeholders": {
|
||||
"foO": {
|
||||
"content": "_foo_ $1 _bar_",
|
||||
"description": "foo",
|
||||
},
|
||||
|
||||
"bad name": {
|
||||
"content": "Nope.",
|
||||
"description": "bad name",
|
||||
},
|
||||
|
||||
"bad_value": "Nope.",
|
||||
|
||||
"bad_content_value": {
|
||||
"content": ["Accepted, but shouldn't break."],
|
||||
"description": "bad value",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"broken_placeholders": {
|
||||
"message": "$broken$",
|
||||
"description": "broken placeholders",
|
||||
"placeholders": "foo.",
|
||||
},
|
||||
},
|
||||
|
||||
"_locales/jp/messages.json": {
|
||||
"foo": {
|
||||
"message": "(foo)",
|
||||
"description": "foo",
|
||||
},
|
||||
|
||||
"bar": {
|
||||
"message": "(bar)",
|
||||
"description": "bar",
|
||||
},
|
||||
},
|
||||
|
||||
"content.js": "new " + function(runTestsFn) {
|
||||
runTestsFn((...args) => {
|
||||
browser.runtime.sendMessage(["assertEq", ...args]);
|
||||
});
|
||||
|
||||
browser.runtime.sendMessage(["content-script-finished"]);
|
||||
} + `(${runTests})`,
|
||||
},
|
||||
|
||||
background: "new " + function(runTestsFn) {
|
||||
browser.runtime.onMessage.addListener(([msg, ...args]) => {
|
||||
if (msg == "assertEq") {
|
||||
browser.test.assertEq(...args);
|
||||
} else {
|
||||
browser.test.sendMessage(msg, ...args);
|
||||
}
|
||||
});
|
||||
|
||||
runTestsFn(browser.test.assertEq.bind(browser.test));
|
||||
} + `(${runTests})`,
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
yield extension.awaitMessage("content-script-finished");
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_get_accept_languages() {
|
||||
function background() {
|
||||
function checkResults(source, results, expected) {
|
||||
browser.test.assertEq(
|
||||
expected.length,
|
||||
results.length,
|
||||
`got expected number of languages in ${source}`);
|
||||
results.forEach((lang, index) => {
|
||||
browser.test.assertEq(
|
||||
expected[index],
|
||||
lang,
|
||||
`got expected language in ${source}`);
|
||||
});
|
||||
}
|
||||
|
||||
let tabId;
|
||||
|
||||
browser.tabs.query({currentWindow: true, active: true}, tabs => {
|
||||
tabId = tabs[0].id;
|
||||
browser.test.sendMessage("ready");
|
||||
});
|
||||
|
||||
browser.test.onMessage.addListener(async ([msg, expected]) => {
|
||||
let contentResults = await browser.tabs.sendMessage(tabId, "get-results");
|
||||
let backgroundResults = await browser.i18n.getAcceptLanguages();
|
||||
|
||||
checkResults("contentScript", contentResults, expected);
|
||||
checkResults("background", backgroundResults, expected);
|
||||
|
||||
browser.test.sendMessage("done");
|
||||
});
|
||||
}
|
||||
|
||||
function content() {
|
||||
browser.runtime.onMessage.addListener((msg, sender, respond) => {
|
||||
browser.i18n.getAcceptLanguages(respond);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"run_at": "document_start",
|
||||
"js": ["content_script.js"],
|
||||
}],
|
||||
},
|
||||
|
||||
background,
|
||||
|
||||
files: {
|
||||
"content_script.js": content,
|
||||
},
|
||||
});
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
let expectedLangs = ["en-US", "en"];
|
||||
extension.sendMessage(["expect-results", expectedLangs]);
|
||||
yield extension.awaitMessage("done");
|
||||
|
||||
expectedLangs = ["en-US", "en", "fr-CA", "fr"];
|
||||
SpecialPowers.setCharPref("intl.accept_languages", expectedLangs.toString());
|
||||
extension.sendMessage(["expect-results", expectedLangs]);
|
||||
yield extension.awaitMessage("done");
|
||||
SpecialPowers.clearUserPref("intl.accept_languages");
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_get_ui_language() {
|
||||
function getResults() {
|
||||
return {
|
||||
getUILanguage: browser.i18n.getUILanguage(),
|
||||
getMessage: browser.i18n.getMessage("@@ui_locale"),
|
||||
};
|
||||
}
|
||||
|
||||
function background(getResultsFn) {
|
||||
function checkResults(source, results, expected) {
|
||||
browser.test.assertEq(
|
||||
expected,
|
||||
results.getUILanguage,
|
||||
`Got expected getUILanguage result in ${source}`
|
||||
);
|
||||
browser.test.assertEq(
|
||||
expected,
|
||||
results.getMessage,
|
||||
`Got expected getMessage result in ${source}`
|
||||
);
|
||||
}
|
||||
|
||||
let tabId;
|
||||
|
||||
browser.test.onMessage.addListener(([msg, expected]) => {
|
||||
browser.tabs.sendMessage(tabId, "get-results", result => {
|
||||
checkResults("contentScript", result, expected);
|
||||
checkResults("background", getResultsFn(), expected);
|
||||
|
||||
browser.test.sendMessage("done");
|
||||
});
|
||||
});
|
||||
|
||||
browser.tabs.query({currentWindow: true, active: true}, tabs => {
|
||||
tabId = tabs[0].id;
|
||||
browser.test.sendMessage("ready");
|
||||
});
|
||||
}
|
||||
|
||||
function content(getResultsFn) {
|
||||
browser.runtime.onMessage.addListener((msg, sender, respond) => {
|
||||
respond(getResultsFn());
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"run_at": "document_start",
|
||||
"js": ["content_script.js"],
|
||||
}],
|
||||
},
|
||||
|
||||
background: `(${background})(${getResults})`,
|
||||
|
||||
files: {
|
||||
"content_script.js": `(${content})(${getResults})`,
|
||||
},
|
||||
});
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
extension.sendMessage(["expect-results", "en_US"]);
|
||||
yield extension.awaitMessage("done");
|
||||
|
||||
SpecialPowers.setCharPref("general.useragent.locale", "he");
|
||||
|
||||
extension.sendMessage(["expect-results", "he"]);
|
||||
yield extension.awaitMessage("done");
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_detect_language() {
|
||||
const af_string = " aam skukuza die naam beteken hy wat skoonvee of hy wat alles onderstebo keer wysig " +
|
||||
"bosveldkampe boskampe is kleiner afgeleë ruskampe wat oor min fasiliteite beskik daar is geen restaurante " +
|
||||
"of winkels nie en slegs oornagbesoekers word toegelaat bateleur";
|
||||
// String with intermixed French/English text
|
||||
const fr_en_string = "France is the largest country in Western Europe and the third-largest in Europe as a whole. " +
|
||||
"A accès aux chiens et aux frontaux qui lui ont été il peut consulter et modifier ses collections et exporter " +
|
||||
"Cet article concerne le pays européen aujourd’hui appelé République française. Pour d’autres usages du nom France, " +
|
||||
"Pour une aide rapide et effective, veuiller trouver votre aide dans le menu ci-dessus." +
|
||||
"Motoring events began soon after the construction of the first successful gasoline-fueled automobiles. The quick brown fox jumped over the lazy dog";
|
||||
|
||||
function background() {
|
||||
function checkResult(source, result, expected) {
|
||||
browser.test.assertEq(expected.isReliable, result.isReliable, "result.confident is true");
|
||||
browser.test.assertEq(
|
||||
expected.languages.length,
|
||||
result.languages.length,
|
||||
`result.languages contains the expected number of languages in ${source}`);
|
||||
expected.languages.forEach((lang, index) => {
|
||||
browser.test.assertEq(
|
||||
lang.percentage,
|
||||
result.languages[index].percentage,
|
||||
`element ${index} of result.languages array has the expected percentage in ${source}`);
|
||||
browser.test.assertEq(
|
||||
lang.language,
|
||||
result.languages[index].language,
|
||||
`element ${index} of result.languages array has the expected language in ${source}`);
|
||||
});
|
||||
}
|
||||
|
||||
let tabId;
|
||||
|
||||
browser.tabs.query({currentWindow: true, active: true}, tabs => {
|
||||
tabId = tabs[0].id;
|
||||
browser.test.sendMessage("ready");
|
||||
});
|
||||
|
||||
browser.test.onMessage.addListener(async ([msg, expected]) => {
|
||||
let backgroundResults = await browser.i18n.detectLanguage(msg);
|
||||
let contentResults = await browser.tabs.sendMessage(tabId, msg);
|
||||
|
||||
checkResult("background", backgroundResults, expected);
|
||||
checkResult("contentScript", contentResults, expected);
|
||||
|
||||
browser.test.sendMessage("done");
|
||||
});
|
||||
}
|
||||
|
||||
function content() {
|
||||
browser.runtime.onMessage.addListener((msg, sender, respond) => {
|
||||
browser.i18n.detectLanguage(msg, respond);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"run_at": "document_start",
|
||||
"js": ["content_script.js"],
|
||||
}],
|
||||
},
|
||||
|
||||
background,
|
||||
|
||||
files: {
|
||||
"content_script.js": content,
|
||||
},
|
||||
});
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
let expected = {
|
||||
isReliable: true,
|
||||
languages: [
|
||||
{
|
||||
language: "fr",
|
||||
percentage: 67,
|
||||
},
|
||||
{
|
||||
language: "en",
|
||||
percentage: 32,
|
||||
},
|
||||
],
|
||||
};
|
||||
extension.sendMessage([fr_en_string, expected]);
|
||||
yield extension.awaitMessage("done");
|
||||
|
||||
expected = {
|
||||
isReliable: true,
|
||||
languages: [
|
||||
{
|
||||
language: "af",
|
||||
percentage: 99,
|
||||
},
|
||||
],
|
||||
};
|
||||
extension.sendMessage([af_string, expected]);
|
||||
yield extension.awaitMessage("done");
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_i18n_css() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: function() {
|
||||
function backgroundFetch(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url);
|
||||
xhr.onload = () => { resolve(xhr.responseText); };
|
||||
xhr.onerror = reject;
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
Promise.all([backgroundFetch("foo.css"), backgroundFetch("bar.CsS?x#y"), backgroundFetch("foo.txt")]).then(results => {
|
||||
browser.test.assertEq("body { max-width: 42px; }", results[0], "CSS file localized");
|
||||
browser.test.assertEq("body { max-width: 42px; }", results[1], "CSS file localized");
|
||||
|
||||
browser.test.assertEq("body { __MSG_foo__; }", results[2], "Text file not localized");
|
||||
|
||||
browser.test.notifyPass("i18n-css");
|
||||
});
|
||||
|
||||
browser.test.sendMessage("ready", browser.runtime.getURL("foo.css"));
|
||||
},
|
||||
|
||||
manifest: {
|
||||
"web_accessible_resources": ["foo.css", "foo.txt", "locale.css"],
|
||||
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"css": ["foo.css"],
|
||||
}],
|
||||
|
||||
"default_locale": "en",
|
||||
},
|
||||
|
||||
files: {
|
||||
"_locales/en/messages.json": JSON.stringify({
|
||||
"foo": {
|
||||
"message": "max-width: 42px",
|
||||
"description": "foo",
|
||||
},
|
||||
}),
|
||||
|
||||
"foo.css": "body { __MSG_foo__; }",
|
||||
"bar.CsS": "body { __MSG_foo__; }",
|
||||
"foo.txt": "body { __MSG_foo__; }",
|
||||
"locale.css": '* { content: "__MSG_@@ui_locale__ __MSG_@@bidi_dir__ __MSG_@@bidi_reversed_dir__ __MSG_@@bidi_start_edge__ __MSG_@@bidi_end_edge__" }',
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
let cssURL = yield extension.awaitMessage("ready");
|
||||
|
||||
function fetch(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url);
|
||||
xhr.onload = () => { resolve(xhr.responseText); };
|
||||
xhr.onerror = reject;
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
let css = yield fetch(cssURL);
|
||||
|
||||
is(css, "body { max-width: 42px; }", "CSS file localized in mochitest scope");
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
yield waitForLoad(win);
|
||||
|
||||
let style = win.getComputedStyle(win.document.body);
|
||||
is(style.maxWidth, "42px", "stylesheet correctly applied");
|
||||
win.close();
|
||||
|
||||
cssURL = cssURL.replace(/foo.css$/, "locale.css");
|
||||
|
||||
css = yield fetch(cssURL);
|
||||
is(css, '* { content: "en_US ltr rtl left right" }', "CSS file localized in mochitest scope");
|
||||
|
||||
const LOCALE = "general.useragent.locale";
|
||||
const DIR = "intl.uidirection.en";
|
||||
|
||||
// We don't wind up actually switching the chrome registry locale, since we
|
||||
// don't have a chrome package for Hebrew. So just override it.
|
||||
SpecialPowers.setCharPref(LOCALE, "he");
|
||||
SpecialPowers.setCharPref(DIR, "rtl");
|
||||
|
||||
css = yield fetch(cssURL);
|
||||
is(css, '* { content: "he rtl ltr right left" }', "CSS file localized in mochitest scope");
|
||||
|
||||
SpecialPowers.clearUserPref(LOCALE);
|
||||
SpecialPowers.clearUserPref(DIR);
|
||||
|
||||
yield extension.awaitFinish("i18n-css");
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_in_incognito_context_true() {
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener(msg => {
|
||||
browser.test.assertEq(true, msg, "inIncognitoContext is true");
|
||||
browser.test.notifyPass("inIncognitoContext");
|
||||
});
|
||||
|
||||
browser.windows.create({url: browser.runtime.getURL("/tab.html"), incognito: true});
|
||||
}
|
||||
|
||||
function tabScript() {
|
||||
browser.runtime.sendMessage(browser.extension.inIncognitoContext);
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
files: {
|
||||
"tab.js": tabScript,
|
||||
"tab.html": `<!DOCTYPE html><html><head>
|
||||
<meta charset="utf-8">
|
||||
<script src="tab.js"><\/script>
|
||||
</head></html>`,
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("inIncognitoContext");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for simple WebExtension</title>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_versioned_js() {
|
||||
// We need to deal with escaping the close script tags.
|
||||
// May as well consolidate it into one place.
|
||||
let script = attrs => `<script ${attrs}><\/script>`;
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"background": {"page": "background.html"},
|
||||
},
|
||||
|
||||
files: {
|
||||
"background.html": `
|
||||
<meta charset="utf-8">
|
||||
${script('src="background.js" type="application/javascript"')}
|
||||
${script('src="background-1.js" type="application/javascript;version=1.8"')}
|
||||
${script('src="background-2.js" type="application/javascript;version=latest"')}
|
||||
${script('src="background-3.js" type="application/javascript"')}
|
||||
`,
|
||||
|
||||
"background.js": function() {
|
||||
window.reportResult = msg => {
|
||||
browser.test.assertEq(
|
||||
msg, "background-script-3",
|
||||
"Expected a message only from the unversioned background script.");
|
||||
|
||||
browser.test.sendMessage("finished");
|
||||
};
|
||||
},
|
||||
|
||||
"background-1.js": function() {
|
||||
window.reportResult("background-script-1");
|
||||
},
|
||||
"background-2.js": function() {
|
||||
window.reportResult("background-script-2");
|
||||
},
|
||||
"background-3.js": function() {
|
||||
window.reportResult("background-script-3");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
let messages = [/Versioned JavaScript.*not supported in WebExtension.*developer\.mozilla\.org/,
|
||||
/Versioned JavaScript.*not supported in WebExtension.*developer\.mozilla\.org/];
|
||||
|
||||
let waitForConsole = new Promise(resolve => {
|
||||
SimpleTest.monitorConsole(resolve, messages);
|
||||
});
|
||||
|
||||
info("loading extension");
|
||||
|
||||
yield Promise.all([extension.startup(),
|
||||
extension.awaitMessage("finished")]);
|
||||
|
||||
info("waiting for console");
|
||||
|
||||
SimpleTest.endMonitorConsole();
|
||||
yield waitForConsole;
|
||||
|
||||
info("unloading extension");
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
info("test complete");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_listener_proxies() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
|
||||
manifest: {
|
||||
"permissions": ["storage"],
|
||||
},
|
||||
|
||||
async background() {
|
||||
// Test that adding multiple listeners for the same event works as
|
||||
// expected.
|
||||
|
||||
let awaitChanged = () => new Promise(resolve => {
|
||||
browser.storage.onChanged.addListener(function listener() {
|
||||
browser.storage.onChanged.removeListener(listener);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
let promises = [
|
||||
awaitChanged(),
|
||||
awaitChanged(),
|
||||
];
|
||||
|
||||
function removedListener() {}
|
||||
browser.storage.onChanged.addListener(removedListener);
|
||||
browser.storage.onChanged.removeListener(removedListener);
|
||||
|
||||
promises.push(awaitChanged(), awaitChanged());
|
||||
|
||||
browser.storage.local.set({foo: "bar"});
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
browser.test.notifyPass("onchanged-listeners");
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
yield extension.awaitFinish("onchanged-listeners");
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for notifications</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
// A 1x1 PNG image.
|
||||
// Source: https://commons.wikimedia.org/wiki/File:1x1.png (Public Domain)
|
||||
let image = atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" +
|
||||
"ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=");
|
||||
const IMAGE_ARRAYBUFFER = Uint8Array.from(image, byte => byte.charCodeAt(0)).buffer;
|
||||
|
||||
add_task(function* test_notification() {
|
||||
async function background() {
|
||||
let opts = {
|
||||
type: "basic",
|
||||
title: "Testing Notification",
|
||||
message: "Carry on",
|
||||
};
|
||||
|
||||
let id = await browser.notifications.create(opts);
|
||||
|
||||
browser.test.sendMessage("running", id);
|
||||
browser.test.notifyPass("background test passed");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["notifications"],
|
||||
},
|
||||
background,
|
||||
});
|
||||
yield extension.startup();
|
||||
let x = yield extension.awaitMessage("running");
|
||||
is(x, "0", "got correct id from notifications.create");
|
||||
yield extension.awaitFinish();
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_notification_events() {
|
||||
async function background() {
|
||||
let opts = {
|
||||
type: "basic",
|
||||
title: "Testing Notification",
|
||||
message: "Carry on",
|
||||
};
|
||||
|
||||
// Test an ignored listener.
|
||||
browser.notifications.onButtonClicked.addListener(function() {});
|
||||
|
||||
// We cannot test onClicked listener without a mock
|
||||
// but we can attempt to add a listener.
|
||||
browser.notifications.onClicked.addListener(function() {});
|
||||
|
||||
// Test onClosed listener.
|
||||
browser.notifications.onClosed.addListener(id => {
|
||||
browser.test.sendMessage("closed", id);
|
||||
browser.test.notifyPass("background test passed");
|
||||
});
|
||||
|
||||
await browser.notifications.create("5", opts);
|
||||
let id = await browser.notifications.create("5", opts);
|
||||
browser.test.sendMessage("running", id);
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["notifications"],
|
||||
},
|
||||
background,
|
||||
});
|
||||
yield extension.startup();
|
||||
let x = yield extension.awaitMessage("closed");
|
||||
is(x, "5", "got correct id from onClosed listener");
|
||||
x = yield extension.awaitMessage("running");
|
||||
is(x, "5", "got correct id from notifications.create");
|
||||
yield extension.awaitFinish();
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_notification_clear() {
|
||||
async function background() {
|
||||
let opts = {
|
||||
type: "basic",
|
||||
title: "Testing Notification",
|
||||
message: "Carry on",
|
||||
};
|
||||
|
||||
browser.notifications.onClosed.addListener(id => {
|
||||
browser.test.sendMessage("closed", id);
|
||||
});
|
||||
|
||||
let id = await browser.notifications.create("99", opts);
|
||||
|
||||
let wasCleared = await browser.notifications.clear(id);
|
||||
browser.test.sendMessage("cleared", wasCleared);
|
||||
|
||||
browser.test.notifyPass("background test passed");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["notifications"],
|
||||
},
|
||||
background,
|
||||
});
|
||||
yield extension.startup();
|
||||
let x = yield extension.awaitMessage("closed");
|
||||
is(x, "99", "got correct id from onClosed listener");
|
||||
x = yield extension.awaitMessage("cleared");
|
||||
is(x, true, "got correct boolean from notifications.clear");
|
||||
yield extension.awaitFinish();
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_notifications_empty_getAll() {
|
||||
async function background() {
|
||||
let notifications = await browser.notifications.getAll();
|
||||
|
||||
browser.test.assertEq("object", typeof notifications, "getAll() returned an object");
|
||||
browser.test.assertEq(0, Object.keys(notifications).length, "the object has no properties");
|
||||
browser.test.notifyPass("getAll empty");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["notifications"],
|
||||
},
|
||||
background,
|
||||
});
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("getAll empty");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_notifications_populated_getAll() {
|
||||
async function background() {
|
||||
let opts = {
|
||||
type: "basic",
|
||||
iconUrl: "a.png",
|
||||
title: "Testing Notification",
|
||||
message: "Carry on",
|
||||
};
|
||||
|
||||
await browser.notifications.create("p1", opts);
|
||||
await browser.notifications.create("p2", opts);
|
||||
let notifications = await browser.notifications.getAll();
|
||||
|
||||
browser.test.assertEq("object", typeof notifications, "getAll() returned an object");
|
||||
browser.test.assertEq(2, Object.keys(notifications).length, "the object has 2 properties");
|
||||
|
||||
for (let notificationId of ["p1", "p2"]) {
|
||||
for (let key of Object.keys(opts)) {
|
||||
browser.test.assertEq(
|
||||
opts[key],
|
||||
notifications[notificationId][key],
|
||||
`the notification has the expected value for option: ${key}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
browser.test.notifyPass("getAll populated");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["notifications"],
|
||||
},
|
||||
background,
|
||||
files: {
|
||||
"a.png": IMAGE_ARRAYBUFFER,
|
||||
},
|
||||
});
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("getAll populated");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_buttons_unsupported() {
|
||||
function background() {
|
||||
let opts = {
|
||||
type: "basic",
|
||||
title: "Testing Notification",
|
||||
message: "Carry on",
|
||||
buttons: [{title: "Button title"}],
|
||||
};
|
||||
|
||||
let exception = {};
|
||||
try {
|
||||
browser.notifications.create(opts);
|
||||
} catch (e) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
browser.test.assertTrue(
|
||||
String(exception).includes('Property "buttons" is unsupported by Firefox'),
|
||||
"notifications.create with buttons option threw an expected exception"
|
||||
);
|
||||
browser.test.notifyPass("buttons-unsupported");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["notifications"],
|
||||
},
|
||||
background,
|
||||
});
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("buttons-unsupported");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension Test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
|
||||
add_task(function* test_simple() {
|
||||
async function runTests(cx) {
|
||||
function xhr(XMLHttpRequest) {
|
||||
return (url) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let req = new XMLHttpRequest();
|
||||
req.open("GET", url);
|
||||
req.addEventListener("load", resolve);
|
||||
req.addEventListener("error", reject);
|
||||
req.send();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function run(shouldFail, fetch) {
|
||||
function passListener() {
|
||||
browser.test.succeed(`${cx}.${fetch.name} pass listener`);
|
||||
}
|
||||
|
||||
function failListener() {
|
||||
browser.test.fail(`${cx}.${fetch.name} fail listener`);
|
||||
}
|
||||
|
||||
/* eslint-disable no-else-return */
|
||||
if (shouldFail) {
|
||||
return fetch("http://example.org/example.txt").then(failListener, passListener);
|
||||
} else {
|
||||
return fetch("http://example.com/example.txt").then(passListener, failListener);
|
||||
}
|
||||
/* eslint-enable no-else-return */
|
||||
}
|
||||
|
||||
try {
|
||||
await run(true, xhr(XMLHttpRequest));
|
||||
await run(false, xhr(XMLHttpRequest));
|
||||
await run(true, xhr(window.XMLHttpRequest));
|
||||
await run(false, xhr(window.XMLHttpRequest));
|
||||
await run(true, fetch);
|
||||
await run(false, fetch);
|
||||
await run(true, window.fetch);
|
||||
await run(false, window.fetch);
|
||||
} catch (err) {
|
||||
browser.test.fail(`Error: ${err} :: ${err.stack}`);
|
||||
browser.test.notifyFail("permission_xhr");
|
||||
}
|
||||
}
|
||||
|
||||
async function background(runTestsFn) {
|
||||
await runTestsFn("bg");
|
||||
browser.test.notifyPass("permission_xhr");
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background: `(${background})(${runTests})`,
|
||||
manifest: {
|
||||
permissions: ["http://example.com/"],
|
||||
content_scripts: [{
|
||||
"matches": ["http://mochi.test/*/file_permission_xhr.html"],
|
||||
"js": ["content.js"],
|
||||
}],
|
||||
},
|
||||
files: {
|
||||
"content.js": `(${async runTestsFn => {
|
||||
await runTestsFn("content");
|
||||
|
||||
window.wrappedJSObject.privilegedFetch = fetch;
|
||||
window.wrappedJSObject.privilegedXHR = XMLHttpRequest;
|
||||
|
||||
window.addEventListener("message", function rcv({data}) {
|
||||
switch (data.msg) {
|
||||
case "test":
|
||||
break;
|
||||
|
||||
case "assertTrue":
|
||||
browser.test.assertTrue(data.condition, data.description);
|
||||
break;
|
||||
|
||||
case "finish":
|
||||
window.removeEventListener("message", rcv, false);
|
||||
browser.test.sendMessage("content-script-finished");
|
||||
break;
|
||||
}
|
||||
}, false);
|
||||
window.postMessage("test", "*");
|
||||
}})(${runTests})`,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_permission_xhr.html");
|
||||
yield extension.awaitMessage("content-script-finished");
|
||||
win.close();
|
||||
|
||||
yield extension.awaitFinish("permission_xhr");
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function background() {
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
browser.test.assertEq(port.name, "ernie", "port name correct");
|
||||
browser.test.assertTrue(port.sender.url.endsWith("file_sample.html"), "URL correct");
|
||||
browser.test.assertTrue(port.sender.tab.url.endsWith("file_sample.html"), "tab URL correct");
|
||||
|
||||
let expected = "message 1";
|
||||
port.onMessage.addListener(msg => {
|
||||
browser.test.assertEq(msg, expected, "message is expected");
|
||||
if (expected == "message 1") {
|
||||
port.postMessage("message 2");
|
||||
expected = "message 3";
|
||||
} else if (expected == "message 3") {
|
||||
expected = "disconnect";
|
||||
browser.test.notifyPass("runtime.connect");
|
||||
}
|
||||
});
|
||||
port.onDisconnect.addListener(() => {
|
||||
browser.test.assertEq(null, port.error, "No error because port is closed by disconnect() at other end");
|
||||
browser.test.assertEq(expected, "disconnect", "got disconnection at right time");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
let port = browser.runtime.connect({name: "ernie"});
|
||||
port.postMessage("message 1");
|
||||
port.onMessage.addListener(msg => {
|
||||
if (msg == "message 2") {
|
||||
port.postMessage("message 3");
|
||||
port.disconnect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
manifest: {
|
||||
"permissions": ["tabs"],
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_start",
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield Promise.all([waitForLoad(win), extension.awaitFinish("runtime.connect")]);
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function backgroundScript(token) {
|
||||
browser.runtime.onMessage.addListener(msg => {
|
||||
browser.test.assertEq(msg, "done");
|
||||
browser.test.notifyPass("sendmessage_reply");
|
||||
});
|
||||
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
browser.test.assertTrue(port.sender.url.endsWith("file_sample.html"), "sender url correct");
|
||||
browser.test.assertTrue(port.sender.tab.url.endsWith("file_sample.html"), "sender url correct");
|
||||
|
||||
let tabId = port.sender.tab.id;
|
||||
browser.tabs.connect(tabId, {name: token});
|
||||
|
||||
browser.test.assertEq(port.name, token, "token matches");
|
||||
port.postMessage(token + "-done");
|
||||
});
|
||||
|
||||
browser.test.sendMessage("background-ready");
|
||||
}
|
||||
|
||||
function contentScript(token) {
|
||||
let gotTabMessage = false;
|
||||
let badTabMessage = false;
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
if (port.name == token) {
|
||||
gotTabMessage = true;
|
||||
} else {
|
||||
badTabMessage = true;
|
||||
}
|
||||
port.disconnect();
|
||||
});
|
||||
|
||||
let port = browser.runtime.connect(null, {name: token});
|
||||
port.onMessage.addListener(function(msg) {
|
||||
if (msg != token + "-done" || !gotTabMessage || badTabMessage) {
|
||||
return; // test failed
|
||||
}
|
||||
|
||||
// FIXME: Removing this line causes the test to fail:
|
||||
// resource://gre/modules/ExtensionUtils.jsm, line 651: NS_ERROR_NOT_INITIALIZED
|
||||
port.disconnect();
|
||||
browser.runtime.sendMessage("done");
|
||||
});
|
||||
}
|
||||
|
||||
function makeExtension() {
|
||||
let token = Math.random();
|
||||
let extensionData = {
|
||||
background: `(${backgroundScript})("${token}")`,
|
||||
manifest: {
|
||||
"permissions": ["tabs"],
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": `(${contentScript})("${token}")`,
|
||||
},
|
||||
};
|
||||
return extensionData;
|
||||
}
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
let extension1 = ExtensionTestUtils.loadExtension(makeExtension());
|
||||
let extension2 = ExtensionTestUtils.loadExtension(makeExtension());
|
||||
yield Promise.all([extension1.startup(), extension2.startup()]);
|
||||
|
||||
yield extension1.awaitMessage("background-ready");
|
||||
yield extension2.awaitMessage("background-ready");
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield Promise.all([waitForLoad(win),
|
||||
extension1.awaitFinish("sendmessage_reply"),
|
||||
extension2.awaitFinish("sendmessage_reply")]);
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension1.unload();
|
||||
yield extension2.unload();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_connect_bidirectionally_and_postMessage() {
|
||||
function background() {
|
||||
let onConnectCount = 0;
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
// 3. onConnect by connect() from CS.
|
||||
browser.test.assertEq("from-cs", port.name);
|
||||
browser.test.assertEq(1, ++onConnectCount,
|
||||
"BG onConnect should be called once");
|
||||
|
||||
let tabId = port.sender.tab.id;
|
||||
browser.test.assertTrue(tabId, "content script must have a tab ID");
|
||||
|
||||
let port2;
|
||||
let postMessageCount1 = 0;
|
||||
port.onMessage.addListener(msg => {
|
||||
// 11. port.onMessage by port.postMessage in CS.
|
||||
browser.test.assertEq("from CS to port", msg);
|
||||
browser.test.assertEq(1, ++postMessageCount1,
|
||||
"BG port.onMessage should be called once");
|
||||
|
||||
// 12. should trigger port2.onMessage in CS.
|
||||
port2.postMessage("from BG to port2");
|
||||
});
|
||||
|
||||
// 4. Should trigger onConnect in CS.
|
||||
port2 = browser.tabs.connect(tabId, {name: "from-bg"});
|
||||
let postMessageCount2 = 0;
|
||||
port2.onMessage.addListener(msg => {
|
||||
// 7. onMessage by port2.postMessage in CS.
|
||||
browser.test.assertEq("from CS to port2", msg);
|
||||
browser.test.assertEq(1, ++postMessageCount2,
|
||||
"BG port2.onMessage should be called once");
|
||||
|
||||
// 8. Should trigger port.onMessage in CS.
|
||||
port.postMessage("from BG to port");
|
||||
});
|
||||
});
|
||||
|
||||
// 1. Notify test runner to create a new tab.
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
let onConnectCount = 0;
|
||||
let port;
|
||||
browser.runtime.onConnect.addListener(port2 => {
|
||||
// 5. onConnect by connect() from BG.
|
||||
browser.test.assertEq("from-bg", port2.name);
|
||||
browser.test.assertEq(1, ++onConnectCount,
|
||||
"CS onConnect should be called once");
|
||||
|
||||
let postMessageCount2 = 0;
|
||||
port2.onMessage.addListener(msg => {
|
||||
// 12. port2.onMessage by port2.postMessage in BG.
|
||||
browser.test.assertEq("from BG to port2", msg);
|
||||
browser.test.assertEq(1, ++postMessageCount2,
|
||||
"CS port2.onMessage should be called once");
|
||||
|
||||
// TODO(robwu): Do not explicitly disconnect, it should not be a problem
|
||||
// if we keep the ports open. However, not closing the ports causes the
|
||||
// test to fail with NS_ERROR_NOT_INITIALIZED in ExtensionUtils.jsm, in
|
||||
// Port.prototype.disconnect (nsIMessageSender.sendAsyncMessage).
|
||||
port.disconnect();
|
||||
port2.disconnect();
|
||||
browser.test.notifyPass("ping pong done");
|
||||
});
|
||||
// 6. should trigger port2.onMessage in BG.
|
||||
port2.postMessage("from CS to port2");
|
||||
});
|
||||
|
||||
// 2. should trigger onConnect in BG.
|
||||
port = browser.runtime.connect({name: "from-cs"});
|
||||
let postMessageCount1 = 0;
|
||||
port.onMessage.addListener(msg => {
|
||||
// 9. onMessage by port.postMessage in BG.
|
||||
browser.test.assertEq("from BG to port", msg);
|
||||
browser.test.assertEq(1, ++postMessageCount1,
|
||||
"CS port.onMessage should be called once");
|
||||
|
||||
// 10. should trigger port.onMessage in BG.
|
||||
port.postMessage("from CS to port");
|
||||
});
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
manifest: {
|
||||
content_scripts: [{
|
||||
js: ["contentscript.js"],
|
||||
matches: ["http://mochi.test/*/file_sample.html"],
|
||||
}],
|
||||
},
|
||||
files: {
|
||||
"contentscript.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
info("extension loaded");
|
||||
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
yield extension.awaitFinish("ping pong done");
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function background() {
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
browser.test.assertEq(port.name, "ernie", "port name correct");
|
||||
port.onDisconnect.addListener(() => {
|
||||
browser.test.assertEq(null, port.error, "The port is implicitly closed without errors when the other context unloads");
|
||||
// Closing an already-disconnected port is a no-op.
|
||||
port.disconnect();
|
||||
port.disconnect();
|
||||
browser.test.sendMessage("disconnected");
|
||||
});
|
||||
browser.test.sendMessage("connected");
|
||||
});
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
browser.runtime.connect({name: "ernie"});
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
manifest: {
|
||||
"permissions": ["tabs"],
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
yield Promise.all([waitForLoad(win), extension.awaitMessage("connected")]);
|
||||
win.close();
|
||||
yield extension.awaitMessage("disconnected");
|
||||
|
||||
info("win.close() succeeded");
|
||||
|
||||
win = window.open("file_sample.html");
|
||||
yield Promise.all([waitForLoad(win), extension.awaitMessage("connected")]);
|
||||
|
||||
// Add an "unload" listener so that we don't put the window in the
|
||||
// bfcache. This way it gets destroyed immediately upon navigation.
|
||||
win.addEventListener("unload", function() {}); // eslint-disable-line mozilla/balanced-listeners
|
||||
|
||||
win.location = "http://example.com";
|
||||
yield extension.awaitMessage("disconnected");
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for browser.runtime.id</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_runtime_id() {
|
||||
function background() {
|
||||
browser.test.sendMessage("background-id", browser.runtime.id);
|
||||
}
|
||||
|
||||
function content() {
|
||||
browser.test.sendMessage("content-id", browser.runtime.id);
|
||||
}
|
||||
|
||||
let uuidGenerator = SpecialPowers.Cc["@mozilla.org/uuid-generator;1"].getService(SpecialPowers.Ci.nsIUUIDGenerator);
|
||||
let id = uuidGenerator.generateUUID().number;
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {gecko: {id}},
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"run_at": "document_start",
|
||||
"js": ["content_script.js"],
|
||||
}],
|
||||
},
|
||||
|
||||
background,
|
||||
|
||||
files: {
|
||||
"content_script.js": content,
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
let backgroundId = yield extension.awaitMessage("background-id");
|
||||
is(backgroundId, id, "runtime.id from background script is correct");
|
||||
let win = window.open("file_sample.html");
|
||||
let contentId = yield extension.awaitMessage("content-id");
|
||||
is(contentId, id, "runtime.id from content script is correct");
|
||||
|
||||
win.close();
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener(result => {
|
||||
browser.test.assertEq(result, 12, "x is 12");
|
||||
browser.test.notifyPass("background test passed");
|
||||
});
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
window.x = 12;
|
||||
browser.runtime.onMessage.addListener(function() {});
|
||||
browser.runtime.sendMessage(window.x);
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
manifest: {
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield Promise.all([waitForLoad(win), extension.awaitFinish()]);
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for schema API creation</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="chrome_head.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* testEmptySchema() {
|
||||
function background() {
|
||||
browser.test.assertEq(undefined, browser.manifest, "browser.manifest is not defined");
|
||||
browser.test.assertTrue("storage" in browser, "browser.storage should be defined");
|
||||
browser.test.assertEq(undefined, browser.contextMenus, "browser.contextMenus should not be defined");
|
||||
browser.test.notifyPass("schema");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
manifest: {
|
||||
permissions: ["storage"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("schema");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* testUnknownProperties() {
|
||||
function background() {
|
||||
browser.test.notifyPass("loaded");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["unknownPermission"],
|
||||
|
||||
unknown_property: {},
|
||||
},
|
||||
|
||||
background,
|
||||
});
|
||||
|
||||
let messages = [
|
||||
{message: /processing permissions\.0: Unknown permission "unknownPermission"/},
|
||||
{message: /processing unknown_property: An unexpected property was found in the WebExtension manifest/},
|
||||
];
|
||||
|
||||
let waitForConsole = new Promise(resolve => {
|
||||
SimpleTest.monitorConsole(resolve, messages);
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
yield extension.awaitFinish("loaded");
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
SimpleTest.endMonitorConsole();
|
||||
yield waitForConsole;
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function background() {
|
||||
// Add two listeners that both send replies. We're supposed to ignore all but one
|
||||
// of them. Which one is chosen is non-deterministic.
|
||||
|
||||
browser.runtime.onMessage.addListener((msg, sender, sendReply) => {
|
||||
browser.test.assertTrue(sender.tab.url.endsWith("file_sample.html"), "sender url correct");
|
||||
|
||||
if (msg == "getreply") {
|
||||
sendReply("reply1");
|
||||
}
|
||||
});
|
||||
|
||||
browser.runtime.onMessage.addListener((msg, sender, sendReply) => {
|
||||
browser.test.assertTrue(sender.tab.url.endsWith("file_sample.html"), "sender url correct");
|
||||
|
||||
if (msg == "getreply") {
|
||||
sendReply("reply2");
|
||||
}
|
||||
});
|
||||
|
||||
function sleep(callback, n = 10) {
|
||||
if (n == 0) {
|
||||
callback();
|
||||
} else {
|
||||
setTimeout(function() { sleep(callback, n - 1); }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
let done_count = 0;
|
||||
browser.runtime.onMessage.addListener((msg, sender, sendReply) => {
|
||||
browser.test.assertTrue(sender.tab.url.endsWith("file_sample.html"), "sender url correct");
|
||||
|
||||
if (msg == "done") {
|
||||
done_count++;
|
||||
browser.test.assertEq(done_count, 1, "got exactly one reply");
|
||||
|
||||
// Go through the event loop a few times to make sure we don't get multiple replies.
|
||||
sleep(function() {
|
||||
browser.test.notifyPass("sendmessage_doublereply");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
browser.runtime.sendMessage("getreply", function(resp) {
|
||||
if (resp != "reply1" && resp != "reply2") {
|
||||
return; // test failed
|
||||
}
|
||||
browser.runtime.sendMessage("done");
|
||||
});
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
manifest: {
|
||||
"permissions": ["tabs"],
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_start",
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield Promise.all([waitForLoad(win), extension.awaitFinish("sendmessage_doublereply")]);
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
function loadContentScriptExtension(contentScript) {
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
"content_scripts": [{
|
||||
"js": ["contentscript.js"],
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
}],
|
||||
},
|
||||
files: {
|
||||
"contentscript.js": contentScript,
|
||||
},
|
||||
};
|
||||
return ExtensionTestUtils.loadExtension(extensionData);
|
||||
}
|
||||
|
||||
add_task(function* test_content_script_sendMessage_without_listener() {
|
||||
async function contentScript() {
|
||||
await browser.test.assertRejects(
|
||||
browser.runtime.sendMessage("msg"),
|
||||
"Could not establish connection. Receiving end does not exist.");
|
||||
|
||||
browser.test.notifyPass("sendMessage callback was invoked");
|
||||
}
|
||||
|
||||
let extension = loadContentScriptExtension(contentScript);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
yield extension.awaitFinish("sendMessage callback was invoked");
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* test_content_script_chrome_sendMessage_without_listener() {
|
||||
function contentScript() {
|
||||
/* globals chrome */
|
||||
browser.test.assertEq(null, chrome.runtime.lastError, "no lastError before call");
|
||||
let retval = chrome.runtime.sendMessage("msg");
|
||||
browser.test.assertEq(null, chrome.runtime.lastError, "no lastError after call");
|
||||
// TODO(robwu): Fix the implementation and uncomment the next expectation.
|
||||
// When content script APIs are schema-based (bugzil.la/1287007) this bug will be fixed for free.
|
||||
// browser.test.assertEq(undefined, retval, "return value of chrome.runtime.sendMessage without callback");
|
||||
browser.test.assertTrue(retval instanceof Promise, "TODO: chrome.runtime.sendMessage should return undefined, not a promise");
|
||||
|
||||
let isAsyncCall = false;
|
||||
retval = chrome.runtime.sendMessage("msg", reply => {
|
||||
browser.test.assertEq(undefined, reply, "no reply");
|
||||
browser.test.assertTrue(isAsyncCall, "chrome.runtime.sendMessage's callback must be called asynchronously");
|
||||
browser.test.assertEq(undefined, retval, "return value of chrome.runtime.sendMessage with callback");
|
||||
browser.test.assertEq("Could not establish connection. Receiving end does not exist.", chrome.runtime.lastError.message);
|
||||
browser.test.notifyPass("finished chrome.runtime.sendMessage");
|
||||
});
|
||||
isAsyncCall = true;
|
||||
}
|
||||
|
||||
let extension = loadContentScriptExtension(contentScript);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
yield extension.awaitFinish("finished chrome.runtime.sendMessage");
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener((msg, sender, sendReply) => {
|
||||
browser.test.assertTrue(sender.tab.url.endsWith("file_sample.html"), "sender url correct");
|
||||
|
||||
if (msg == 0) {
|
||||
sendReply("reply1");
|
||||
} else if (msg == 1) {
|
||||
window.setTimeout(function() {
|
||||
sendReply("reply2");
|
||||
}, 0);
|
||||
return true;
|
||||
} else if (msg == 2) {
|
||||
browser.test.notifyPass("sendmessage_reply");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
browser.runtime.sendMessage(0, function(resp1) {
|
||||
if (resp1 != "reply1") {
|
||||
return; // test failed
|
||||
}
|
||||
browser.runtime.sendMessage(1, function(resp2) {
|
||||
if (resp2 != "reply2") {
|
||||
return; // test failed
|
||||
}
|
||||
browser.runtime.sendMessage(2);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
background,
|
||||
manifest: {
|
||||
"permissions": ["tabs"],
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": contentScript,
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield extension.startup();
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield Promise.all([waitForLoad(win), extension.awaitFinish("sendmessage_reply")]);
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
function backgroundScript(token) {
|
||||
browser.runtime.onMessage.addListener((msg, sender, sendReply) => {
|
||||
browser.test.assertTrue(sender.tab.url.endsWith("file_sample.html"), "sender url correct");
|
||||
|
||||
if (msg == "done") {
|
||||
browser.test.notifyPass("sendmessage_reply");
|
||||
return;
|
||||
}
|
||||
|
||||
let tabId = sender.tab.id;
|
||||
browser.tabs.sendMessage(tabId, `${token}-tabMessage`);
|
||||
|
||||
browser.test.assertEq(msg, token, "token matches");
|
||||
sendReply(`${token}-done`);
|
||||
});
|
||||
}
|
||||
|
||||
function contentScript(token) {
|
||||
let gotTabMessage = false;
|
||||
let badTabMessage = false;
|
||||
browser.runtime.onMessage.addListener((msg, sender, sendReply) => {
|
||||
if (msg == `${token}-tabMessage`) {
|
||||
gotTabMessage = true;
|
||||
} else {
|
||||
badTabMessage = true;
|
||||
}
|
||||
});
|
||||
|
||||
browser.runtime.sendMessage(token, function(resp) {
|
||||
if (resp != `${token}-done` || !gotTabMessage || badTabMessage) {
|
||||
return; // test failed
|
||||
}
|
||||
browser.runtime.sendMessage("done");
|
||||
});
|
||||
}
|
||||
|
||||
function makeExtension() {
|
||||
let token = Math.random();
|
||||
let extensionData = {
|
||||
background: `(${backgroundScript})(${token})`,
|
||||
manifest: {
|
||||
"permissions": ["tabs"],
|
||||
"content_scripts": [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_start",
|
||||
}],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": `(${contentScript})(${token})`,
|
||||
},
|
||||
};
|
||||
return extensionData;
|
||||
}
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
let extension1 = ExtensionTestUtils.loadExtension(makeExtension());
|
||||
let extension2 = ExtensionTestUtils.loadExtension(makeExtension());
|
||||
|
||||
yield Promise.all([extension1.startup(), extension2.startup()]);
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield Promise.all([waitForLoad(win),
|
||||
extension1.awaitFinish("sendmessage_reply"),
|
||||
extension2.awaitFinish("sendmessage_reply")]);
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension1.unload();
|
||||
yield extension2.unload();
|
||||
info("extensions unloaded");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
|
||||
// Copied from toolkit/components/extensions/test/xpcshell/test_ext_storage.js.
|
||||
// The storage API in content scripts should behave identical to the storage API
|
||||
// in background pages.
|
||||
const STORAGE_SYNC_PREF = "webextensions.storage.sync.enabled";
|
||||
/**
|
||||
* Utility function to ensure that all supported APIs for getting are
|
||||
* tested.
|
||||
*
|
||||
* @param {string} areaName
|
||||
* either "local" or "sync" according to what we want to test
|
||||
* @param {string} prop
|
||||
* "key" to look up using the storage API
|
||||
* @param {Object} value
|
||||
* "value" to compare against
|
||||
*/
|
||||
async function checkGetImpl(areaName, prop, value) {
|
||||
let storage = browser.storage[areaName];
|
||||
|
||||
let data = await storage.get(null);
|
||||
browser.test.assertEq(value, data[prop], `null getter worked for ${prop} in ${areaName}`);
|
||||
|
||||
data = await storage.get(prop);
|
||||
browser.test.assertEq(value, data[prop], `string getter worked for ${prop} in ${areaName}`);
|
||||
|
||||
data = await storage.get([prop]);
|
||||
browser.test.assertEq(value, data[prop], `array getter worked for ${prop} in ${areaName}`);
|
||||
|
||||
data = await storage.get({[prop]: undefined});
|
||||
browser.test.assertEq(value, data[prop], `object getter worked for ${prop} in ${areaName}`);
|
||||
}
|
||||
|
||||
async function contentScript(checkGet) {
|
||||
let globalChanges, gResolve;
|
||||
function clearGlobalChanges() {
|
||||
globalChanges = new Promise(resolve => { gResolve = resolve; });
|
||||
}
|
||||
clearGlobalChanges();
|
||||
let expectedAreaName;
|
||||
|
||||
browser.storage.onChanged.addListener((changes, areaName) => {
|
||||
browser.test.assertEq(expectedAreaName, areaName,
|
||||
"Expected area name received by listener");
|
||||
gResolve(changes);
|
||||
});
|
||||
|
||||
async function checkChanges(areaName, changes, message) {
|
||||
function checkSub(obj1, obj2) {
|
||||
for (let prop in obj1) {
|
||||
browser.test.assertTrue(obj1[prop] !== undefined,
|
||||
`checkChanges ${areaName} ${prop} is missing (${message})`);
|
||||
browser.test.assertTrue(obj2[prop] !== undefined,
|
||||
`checkChanges ${areaName} ${prop} is missing (${message})`);
|
||||
browser.test.assertEq(obj1[prop].oldValue, obj2[prop].oldValue,
|
||||
`checkChanges ${areaName} ${prop} old (${message})`);
|
||||
browser.test.assertEq(obj1[prop].newValue, obj2[prop].newValue,
|
||||
`checkChanges ${areaName} ${prop} new (${message})`);
|
||||
}
|
||||
}
|
||||
|
||||
const recentChanges = await globalChanges;
|
||||
checkSub(changes, recentChanges);
|
||||
checkSub(recentChanges, changes);
|
||||
clearGlobalChanges();
|
||||
}
|
||||
|
||||
/* eslint-disable dot-notation */
|
||||
async function runTests(areaName) {
|
||||
expectedAreaName = areaName;
|
||||
let storage = browser.storage[areaName];
|
||||
// Set some data and then test getters.
|
||||
try {
|
||||
await storage.set({"test-prop1": "value1", "test-prop2": "value2"});
|
||||
await checkChanges(areaName,
|
||||
{"test-prop1": {newValue: "value1"}, "test-prop2": {newValue: "value2"}},
|
||||
"set (a)");
|
||||
|
||||
await checkGet(areaName, "test-prop1", "value1");
|
||||
await checkGet(areaName, "test-prop2", "value2");
|
||||
|
||||
let data = await storage.get({"test-prop1": undefined, "test-prop2": undefined, "other": "default"});
|
||||
browser.test.assertEq("value1", data["test-prop1"], "prop1 correct (a)");
|
||||
browser.test.assertEq("value2", data["test-prop2"], "prop2 correct (a)");
|
||||
browser.test.assertEq("default", data["other"], "other correct");
|
||||
|
||||
data = await storage.get(["test-prop1", "test-prop2", "other"]);
|
||||
browser.test.assertEq("value1", data["test-prop1"], "prop1 correct (b)");
|
||||
browser.test.assertEq("value2", data["test-prop2"], "prop2 correct (b)");
|
||||
browser.test.assertFalse("other" in data, "other correct");
|
||||
|
||||
// Remove data in various ways.
|
||||
await storage.remove("test-prop1");
|
||||
await checkChanges(areaName, {"test-prop1": {oldValue: "value1"}}, "remove string");
|
||||
|
||||
data = await storage.get(["test-prop1", "test-prop2"]);
|
||||
browser.test.assertFalse("test-prop1" in data, "prop1 absent (remove string)");
|
||||
browser.test.assertTrue("test-prop2" in data, "prop2 present (remove string)");
|
||||
|
||||
await storage.set({"test-prop1": "value1"});
|
||||
await checkChanges(areaName, {"test-prop1": {newValue: "value1"}}, "set (c)");
|
||||
|
||||
data = await storage.get(["test-prop1", "test-prop2"]);
|
||||
browser.test.assertEq(data["test-prop1"], "value1", "prop1 correct (c)");
|
||||
browser.test.assertEq(data["test-prop2"], "value2", "prop2 correct (c)");
|
||||
|
||||
await storage.remove(["test-prop1", "test-prop2"]);
|
||||
await checkChanges(areaName,
|
||||
{"test-prop1": {oldValue: "value1"}, "test-prop2": {oldValue: "value2"}},
|
||||
"remove array");
|
||||
|
||||
data = await storage.get(["test-prop1", "test-prop2"]);
|
||||
browser.test.assertFalse("test-prop1" in data, "prop1 absent (remove array)");
|
||||
browser.test.assertFalse("test-prop2" in data, "prop2 absent (remove array)");
|
||||
|
||||
// test storage.clear
|
||||
await storage.set({"test-prop1": "value1", "test-prop2": "value2"});
|
||||
// Make sure that set() handler happened before we clear the
|
||||
// promise again.
|
||||
await globalChanges;
|
||||
|
||||
clearGlobalChanges();
|
||||
await storage.clear();
|
||||
|
||||
await checkChanges(areaName,
|
||||
{"test-prop1": {oldValue: "value1"}, "test-prop2": {oldValue: "value2"}},
|
||||
"clear");
|
||||
data = await storage.get(["test-prop1", "test-prop2"]);
|
||||
browser.test.assertFalse("test-prop1" in data, "prop1 absent (clear)");
|
||||
browser.test.assertFalse("test-prop2" in data, "prop2 absent (clear)");
|
||||
|
||||
// Make sure we can store complex JSON data.
|
||||
// known previous values
|
||||
await storage.set({"test-prop1": "value1", "test-prop2": "value2"});
|
||||
|
||||
// Make sure the set() handler landed.
|
||||
await globalChanges;
|
||||
|
||||
clearGlobalChanges();
|
||||
await storage.set({
|
||||
"test-prop1": {
|
||||
str: "hello",
|
||||
bool: true,
|
||||
null: null,
|
||||
undef: undefined,
|
||||
obj: {},
|
||||
arr: [1, 2],
|
||||
date: new Date(0),
|
||||
regexp: /regexp/,
|
||||
func: function func() {},
|
||||
window,
|
||||
},
|
||||
});
|
||||
|
||||
await storage.set({"test-prop2": function func() {}});
|
||||
const recentChanges = await globalChanges;
|
||||
|
||||
browser.test.assertEq("value1", recentChanges["test-prop1"].oldValue, "oldValue correct");
|
||||
browser.test.assertEq("object", typeof(recentChanges["test-prop1"].newValue), "newValue is obj");
|
||||
clearGlobalChanges();
|
||||
|
||||
data = await storage.get({"test-prop1": undefined, "test-prop2": undefined});
|
||||
let obj = data["test-prop1"];
|
||||
|
||||
browser.test.assertEq("hello", obj.str, "string part correct");
|
||||
browser.test.assertEq(true, obj.bool, "bool part correct");
|
||||
browser.test.assertEq(null, obj.null, "null part correct");
|
||||
browser.test.assertEq(undefined, obj.undef, "undefined part correct");
|
||||
browser.test.assertEq(undefined, obj.func, "function part correct");
|
||||
browser.test.assertEq(undefined, obj.window, "window part correct");
|
||||
browser.test.assertEq("1970-01-01T00:00:00.000Z", obj.date, "date part correct");
|
||||
browser.test.assertEq("/regexp/", obj.regexp, "regexp part correct");
|
||||
browser.test.assertEq("object", typeof(obj.obj), "object part correct");
|
||||
browser.test.assertTrue(Array.isArray(obj.arr), "array part present");
|
||||
browser.test.assertEq(1, obj.arr[0], "arr[0] part correct");
|
||||
browser.test.assertEq(2, obj.arr[1], "arr[1] part correct");
|
||||
browser.test.assertEq(2, obj.arr.length, "arr.length part correct");
|
||||
|
||||
obj = data["test-prop2"];
|
||||
|
||||
browser.test.assertEq("[object Object]", {}.toString.call(obj), "function serialized as a plain object");
|
||||
browser.test.assertEq(0, Object.keys(obj).length, "function serialized as an empty object");
|
||||
} catch (e) {
|
||||
browser.test.fail(`Error: ${e} :: ${e.stack}`);
|
||||
browser.test.notifyFail("storage");
|
||||
}
|
||||
}
|
||||
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
let promise;
|
||||
if (msg === "test-local") {
|
||||
promise = runTests("local");
|
||||
} else if (msg === "test-sync") {
|
||||
promise = runTests("sync");
|
||||
}
|
||||
promise.then(() => browser.test.sendMessage("test-finished"));
|
||||
});
|
||||
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_idle",
|
||||
}],
|
||||
|
||||
permissions: ["storage"],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": `(${contentScript})(${checkGetImpl})`,
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* test_contentscript() {
|
||||
let win = window.open("file_sample.html");
|
||||
yield waitForLoad(win);
|
||||
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [[STORAGE_SYNC_PREF, true]],
|
||||
});
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
yield Promise.all([extension.startup(), extension.awaitMessage("ready")]);
|
||||
extension.sendMessage("test-local");
|
||||
yield extension.awaitMessage("test-finished");
|
||||
|
||||
extension.sendMessage("test-sync");
|
||||
yield extension.awaitMessage("test-finished");
|
||||
|
||||
yield SpecialPowers.popPrefEnv();
|
||||
yield extension.unload();
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
||||
add_task(function* test_local_cache_invalidation() {
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
function background(checkGet) {
|
||||
browser.test.onMessage.addListener(async msg => {
|
||||
if (msg === "set-initial") {
|
||||
await browser.storage.local.set({"test-prop1": "value1", "test-prop2": "value2"});
|
||||
browser.test.sendMessage("set-initial-done");
|
||||
} else if (msg === "check") {
|
||||
await checkGet("local", "test-prop1", "value1");
|
||||
await checkGet("local", "test-prop2", "value2");
|
||||
browser.test.sendMessage("check-done");
|
||||
}
|
||||
});
|
||||
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["storage"],
|
||||
},
|
||||
background: `(${background})(${checkGetImpl})`,
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
extension.sendMessage("set-initial");
|
||||
yield extension.awaitMessage("set-initial-done");
|
||||
|
||||
SpecialPowers.invalidateExtensionStorageCache();
|
||||
|
||||
extension.sendMessage("check");
|
||||
yield extension.awaitMessage("check-done");
|
||||
|
||||
yield extension.unload();
|
||||
win.close();
|
||||
});
|
||||
|
||||
add_task(function* test_config_flag_needed() {
|
||||
let win = window.open("file_sample.html");
|
||||
yield waitForLoad(win);
|
||||
|
||||
function background() {
|
||||
let promises = [];
|
||||
let apiTests = [
|
||||
{method: "get", args: ["foo"]},
|
||||
{method: "set", args: [{foo: "bar"}]},
|
||||
{method: "remove", args: ["foo"]},
|
||||
{method: "clear", args: []},
|
||||
];
|
||||
apiTests.forEach(testDef => {
|
||||
promises.push(browser.test.assertRejects(
|
||||
browser.storage.sync[testDef.method](...testDef.args),
|
||||
"Please set webextensions.storage.sync.enabled to true in about:config",
|
||||
`storage.sync.${testDef.method} is behind a flag`));
|
||||
});
|
||||
|
||||
Promise.all(promises).then(() => browser.test.notifyPass("flag needed"));
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["storage"],
|
||||
},
|
||||
background: `(${background})(${checkGetImpl})`,
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("flag needed");
|
||||
yield extension.unload();
|
||||
win.close();
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebExtension test</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_multiple_pages() {
|
||||
async function background() {
|
||||
let tabReady = new Promise(resolve => {
|
||||
browser.runtime.onMessage.addListener(function listener(msg) {
|
||||
browser.test.log("onMessage " + msg);
|
||||
if (msg == "tab-ready") {
|
||||
browser.runtime.onMessage.removeListener(listener);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let tabId;
|
||||
let tabRemoved = new Promise(resolve => {
|
||||
browser.tabs.onRemoved.addListener(function listener(removedId) {
|
||||
if (removedId == tabId) {
|
||||
browser.tabs.onRemoved.removeListener(listener);
|
||||
|
||||
// Delay long enough to be sure the inner window has been nuked.
|
||||
setTimeout(resolve, 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
let storage = browser.storage.local;
|
||||
|
||||
browser.test.log("create");
|
||||
let tab = await browser.tabs.create({url: "tab.html"});
|
||||
tabId = tab.id;
|
||||
|
||||
await tabReady;
|
||||
|
||||
let result = await storage.get("key");
|
||||
browser.test.assertEq(undefined, result.key, "Key should be undefined");
|
||||
|
||||
await browser.runtime.sendMessage("tab-set-key");
|
||||
|
||||
result = await storage.get("key");
|
||||
browser.test.assertEq(JSON.stringify({foo: {bar: "baz"}}),
|
||||
JSON.stringify(result.key),
|
||||
"Key should be set to the value from the tab");
|
||||
|
||||
browser.test.log("Remove tab");
|
||||
|
||||
await Promise.all([
|
||||
browser.tabs.remove(tabId),
|
||||
tabRemoved,
|
||||
]);
|
||||
|
||||
result = await storage.get("key");
|
||||
browser.test.assertEq(JSON.stringify({foo: {bar: "baz"}}),
|
||||
JSON.stringify(result.key),
|
||||
"Key should still be set to the value from the tab");
|
||||
|
||||
browser.test.notifyPass("storage-multiple");
|
||||
} catch (e) {
|
||||
browser.test.fail(`Error: ${e} :: ${e.stack}`);
|
||||
browser.test.notifyFail("storage-multiple");
|
||||
}
|
||||
}
|
||||
|
||||
function tab() {
|
||||
browser.test.log("tab");
|
||||
browser.runtime.onMessage.addListener(msg => {
|
||||
if (msg == "tab-set-key") {
|
||||
return browser.storage.local.set({key: {foo: {bar: "baz"}}});
|
||||
}
|
||||
});
|
||||
|
||||
browser.runtime.sendMessage("tab-ready");
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
|
||||
files: {
|
||||
"tab.html": `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="tab.js"><\/script>
|
||||
</head>
|
||||
</html>`,
|
||||
|
||||
"tab.js": tab,
|
||||
},
|
||||
|
||||
manifest: {
|
||||
permissions: ["storage"],
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
|
||||
yield extension.awaitFinish("storage-multiple");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue