diff options
Diffstat (limited to 'toolkit/components/webextensions/test')
180 files changed, 0 insertions, 19193 deletions
diff --git a/toolkit/components/webextensions/test/mochitest/.eslintrc.js b/toolkit/components/webextensions/test/mochitest/.eslintrc.js deleted file mode 100644 index 53938410b..000000000 --- a/toolkit/components/webextensions/test/mochitest/.eslintrc.js +++ /dev/null @@ -1,35 +0,0 @@ -"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, - }, -}; diff --git a/toolkit/components/webextensions/test/mochitest/chrome.ini b/toolkit/components/webextensions/test/mochitest/chrome.ini deleted file mode 100644 index 26585cad7..000000000 --- a/toolkit/components/webextensions/test/mochitest/chrome.ini +++ /dev/null @@ -1,35 +0,0 @@ -[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). diff --git a/toolkit/components/webextensions/test/mochitest/chrome_head.js b/toolkit/components/webextensions/test/mochitest/chrome_head.js deleted file mode 100644 index da2f53a02..000000000 --- a/toolkit/components/webextensions/test/mochitest/chrome_head.js +++ /dev/null @@ -1,12 +0,0 @@ -"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"); - diff --git a/toolkit/components/webextensions/test/mochitest/file_WebNavigation_page1.html b/toolkit/components/webextensions/test/mochitest/file_WebNavigation_page1.html deleted file mode 100644 index 663ebc611..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_WebNavigation_page1.html +++ /dev/null @@ -1,12 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<body> - -<iframe src="file_WebNavigation_page2.html" width="200" height="200"></iframe> - -<form> -</form> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_WebNavigation_page2.html b/toolkit/components/webextensions/test/mochitest/file_WebNavigation_page2.html deleted file mode 100644 index cc1acc83d..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_WebNavigation_page2.html +++ /dev/null @@ -1,7 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<body> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_WebNavigation_page3.html b/toolkit/components/webextensions/test/mochitest/file_WebNavigation_page3.html deleted file mode 100644 index a0a26a2e9..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_WebNavigation_page3.html +++ /dev/null @@ -1,9 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<body> - -<a id="elt" href="file_WebNavigation_page3.html#ref">click me</a> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_WebRequest_page3.html b/toolkit/components/webextensions/test/mochitest/file_WebRequest_page3.html deleted file mode 100644 index 5807dd439..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_WebRequest_page3.html +++ /dev/null @@ -1,11 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<head> -<meta charset="utf-8"> -<script> -"use strict"; -window.close(); -</script> -</head> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_csp.html b/toolkit/components/webextensions/test/mochitest/file_csp.html deleted file mode 100644 index 206e44390..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_csp.html +++ /dev/null @@ -1,14 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/file_csp.html^headers^ b/toolkit/components/webextensions/test/mochitest/file_csp.html^headers^ deleted file mode 100644 index 4c6fa3c26..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_csp.html^headers^ +++ /dev/null @@ -1 +0,0 @@ -Content-Security-Policy: default-src 'self' diff --git a/toolkit/components/webextensions/test/mochitest/file_ext_test_api_injection.js b/toolkit/components/webextensions/test/mochitest/file_ext_test_api_injection.js deleted file mode 100644 index 06dfae65e..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_ext_test_api_injection.js +++ /dev/null @@ -1,12 +0,0 @@ -"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}); - } -}); diff --git a/toolkit/components/webextensions/test/mochitest/file_image_bad.png b/toolkit/components/webextensions/test/mochitest/file_image_bad.png Binary files differdeleted file mode 100644 index 4c3be5084..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_image_bad.png +++ /dev/null diff --git a/toolkit/components/webextensions/test/mochitest/file_image_good.png b/toolkit/components/webextensions/test/mochitest/file_image_good.png Binary files differdeleted file mode 100644 index 769c63634..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_image_good.png +++ /dev/null diff --git a/toolkit/components/webextensions/test/mochitest/file_image_redirect.png b/toolkit/components/webextensions/test/mochitest/file_image_redirect.png Binary files differdeleted file mode 100644 index 4c3be5084..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_image_redirect.png +++ /dev/null diff --git a/toolkit/components/webextensions/test/mochitest/file_mixed.html b/toolkit/components/webextensions/test/mochitest/file_mixed.html deleted file mode 100644 index f3c7dda58..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_mixed.html +++ /dev/null @@ -1,13 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/file_permission_xhr.html b/toolkit/components/webextensions/test/mochitest/file_permission_xhr.html deleted file mode 100644 index 22a55f90d..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_permission_xhr.html +++ /dev/null @@ -1,55 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/file_privilege_escalation.html b/toolkit/components/webextensions/test/mochitest/file_privilege_escalation.html deleted file mode 100644 index 258f7058d..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_privilege_escalation.html +++ /dev/null @@ -1,13 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/file_sample.html b/toolkit/components/webextensions/test/mochitest/file_sample.html deleted file mode 100644 index a20e49a1f..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_sample.html +++ /dev/null @@ -1,12 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<head> -<meta charset="utf-8"> -</head> -<body> - -<div id="test">Sample text</div> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_script_bad.js b/toolkit/components/webextensions/test/mochitest/file_script_bad.js deleted file mode 100644 index c425122c7..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_script_bad.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict"; - -window.failure = true; diff --git a/toolkit/components/webextensions/test/mochitest/file_script_good.js b/toolkit/components/webextensions/test/mochitest/file_script_good.js deleted file mode 100644 index 1848edf68..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_script_good.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict"; - -window.success = window.success ? window.success + 1 : 1; diff --git a/toolkit/components/webextensions/test/mochitest/file_script_redirect.js b/toolkit/components/webextensions/test/mochitest/file_script_redirect.js deleted file mode 100644 index c89a196c2..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_script_redirect.js +++ /dev/null @@ -1,4 +0,0 @@ -"use strict"; - -window.failure = true; - diff --git a/toolkit/components/webextensions/test/mochitest/file_script_xhr.js b/toolkit/components/webextensions/test/mochitest/file_script_xhr.js deleted file mode 100644 index 07f80eb2e..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_script_xhr.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict"; - -var request = new XMLHttpRequest(); -request.open("get", "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest/xhr_resource", false); -request.send(); diff --git a/toolkit/components/webextensions/test/mochitest/file_style_bad.css b/toolkit/components/webextensions/test/mochitest/file_style_bad.css deleted file mode 100644 index 8dbc8dc7a..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_style_bad.css +++ /dev/null @@ -1,3 +0,0 @@ -#test { - color: green !important; -} diff --git a/toolkit/components/webextensions/test/mochitest/file_style_good.css b/toolkit/components/webextensions/test/mochitest/file_style_good.css deleted file mode 100644 index 46f9774b5..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_style_good.css +++ /dev/null @@ -1,3 +0,0 @@ -#test { - color: red; -} diff --git a/toolkit/components/webextensions/test/mochitest/file_style_redirect.css b/toolkit/components/webextensions/test/mochitest/file_style_redirect.css deleted file mode 100644 index 8dbc8dc7a..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_style_redirect.css +++ /dev/null @@ -1,3 +0,0 @@ -#test { - color: green !important; -} diff --git a/toolkit/components/webextensions/test/mochitest/file_teardown_test.js b/toolkit/components/webextensions/test/mochitest/file_teardown_test.js deleted file mode 100644 index 7246012ad..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_teardown_test.js +++ /dev/null @@ -1,24 +0,0 @@ -"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"); diff --git a/toolkit/components/webextensions/test/mochitest/file_webNavigation_clientRedirect.html b/toolkit/components/webextensions/test/mochitest/file_webNavigation_clientRedirect.html deleted file mode 100644 index cba3043f7..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_webNavigation_clientRedirect.html +++ /dev/null @@ -1,9 +0,0 @@ -<!DOCTYPE HTML> - -<html> - <head> - <meta http-equiv="refresh" content="1;dummy_page.html"> - </head> - <body> - </body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_webNavigation_clientRedirect_httpHeaders.html b/toolkit/components/webextensions/test/mochitest/file_webNavigation_clientRedirect_httpHeaders.html deleted file mode 100644 index c5b436979..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_webNavigation_clientRedirect_httpHeaders.html +++ /dev/null @@ -1,8 +0,0 @@ -<!DOCTYPE HTML> - -<html> - <head> - </head> - <body> - </body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_webNavigation_clientRedirect_httpHeaders.html^headers^ b/toolkit/components/webextensions/test/mochitest/file_webNavigation_clientRedirect_httpHeaders.html^headers^ deleted file mode 100644 index 574a392a1..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_webNavigation_clientRedirect_httpHeaders.html^headers^ +++ /dev/null @@ -1 +0,0 @@ -Refresh: 1;url=dummy_page.html diff --git a/toolkit/components/webextensions/test/mochitest/file_webNavigation_frameClientRedirect.html b/toolkit/components/webextensions/test/mochitest/file_webNavigation_frameClientRedirect.html deleted file mode 100644 index d360bcbb1..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_webNavigation_frameClientRedirect.html +++ /dev/null @@ -1,12 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<body> - -<iframe src="file_webNavigation_clientRedirect.html" width="200" height="200"></iframe> - -<form> -</form> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_webNavigation_frameRedirect.html b/toolkit/components/webextensions/test/mochitest/file_webNavigation_frameRedirect.html deleted file mode 100644 index 06dbd4374..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_webNavigation_frameRedirect.html +++ /dev/null @@ -1,12 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<body> - -<iframe src="redirection.sjs" width="200" height="200"></iframe> - -<form> -</form> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_webNavigation_manualSubframe.html b/toolkit/components/webextensions/test/mochitest/file_webNavigation_manualSubframe.html deleted file mode 100644 index 307990714..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_webNavigation_manualSubframe.html +++ /dev/null @@ -1,12 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<body> - -<iframe src="file_webNavigation_manualSubframe_page1.html" width="200" height="200"></iframe> - -<form> -</form> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_webNavigation_manualSubframe_page1.html b/toolkit/components/webextensions/test/mochitest/file_webNavigation_manualSubframe_page1.html deleted file mode 100644 index 55bb7aa6a..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_webNavigation_manualSubframe_page1.html +++ /dev/null @@ -1,8 +0,0 @@ -<!DOCTYPE html> - -<html> - <body> - <h1>page1</h1> - <a href="file_webNavigation_manualSubframe_page2.html">page2</a> - </body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_webNavigation_manualSubframe_page2.html b/toolkit/components/webextensions/test/mochitest/file_webNavigation_manualSubframe_page2.html deleted file mode 100644 index 8f589f8bb..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_webNavigation_manualSubframe_page2.html +++ /dev/null @@ -1,7 +0,0 @@ -<!DOCTYPE html> - -<html> - <body> - <h1>page2</h1> - </body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/file_with_about_blank.html b/toolkit/components/webextensions/test/mochitest/file_with_about_blank.html deleted file mode 100644 index af51c2e52..000000000 --- a/toolkit/components/webextensions/test/mochitest/file_with_about_blank.html +++ /dev/null @@ -1,10 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/head.js b/toolkit/components/webextensions/test/mochitest/head.js deleted file mode 100644 index 1b1a29472..000000000 --- a/toolkit/components/webextensions/test/mochitest/head.js +++ /dev/null @@ -1,13 +0,0 @@ -"use strict"; - -/* exported waitForLoad */ - -function waitForLoad(win) { - return new Promise(resolve => { - win.addEventListener("load", function listener() { - win.removeEventListener("load", listener, true); - resolve(); - }, true); - }); -} - diff --git a/toolkit/components/webextensions/test/mochitest/head_cookies.js b/toolkit/components/webextensions/test/mochitest/head_cookies.js deleted file mode 100644 index 9f6966551..000000000 --- a/toolkit/components/webextensions/test/mochitest/head_cookies.js +++ /dev/null @@ -1,167 +0,0 @@ -/* -*- 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"); -} diff --git a/toolkit/components/webextensions/test/mochitest/head_webrequest.js b/toolkit/components/webextensions/test/mochitest/head_webrequest.js deleted file mode 100644 index 96924e505..000000000 --- a/toolkit/components/webextensions/test/mochitest/head_webrequest.js +++ /dev/null @@ -1,331 +0,0 @@ -"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); -} diff --git a/toolkit/components/webextensions/test/mochitest/mochitest.ini b/toolkit/components/webextensions/test/mochitest/mochitest.ini deleted file mode 100644 index 1f61060ad..000000000 --- a/toolkit/components/webextensions/test/mochitest/mochitest.ini +++ /dev/null @@ -1,115 +0,0 @@ -[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_external_messaging.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] diff --git a/toolkit/components/webextensions/test/mochitest/redirection.sjs b/toolkit/components/webextensions/test/mochitest/redirection.sjs deleted file mode 100644 index 370ecd213..000000000 --- a/toolkit/components/webextensions/test/mochitest/redirection.sjs +++ /dev/null @@ -1,4 +0,0 @@ -function handleRequest(aRequest, aResponse) { - aResponse.setStatusLine(aRequest.httpVersion, 302); - aResponse.setHeader("Location", "./dummy_page.html"); -} diff --git a/toolkit/components/webextensions/test/mochitest/return_headers.sjs b/toolkit/components/webextensions/test/mochitest/return_headers.sjs deleted file mode 100644 index 54e2e5fb4..000000000 --- a/toolkit/components/webextensions/test/mochitest/return_headers.sjs +++ /dev/null @@ -1,20 +0,0 @@ -/* -*- 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)); -} - diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_background_debug_global.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_background_debug_global.html deleted file mode 100644 index 0edf5ea86..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_background_debug_global.html +++ /dev/null @@ -1,166 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_background_page.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_background_page.html deleted file mode 100644 index 471c5339d..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_background_page.html +++ /dev/null @@ -1,84 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_contentscript_unrecognizedprop_warning.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_contentscript_unrecognizedprop_warning.html deleted file mode 100644 index e08121a8f..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_contentscript_unrecognizedprop_warning.html +++ /dev/null @@ -1,80 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_downloads_saveAs.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_downloads_saveAs.html deleted file mode 100644 index c1aaae035..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_downloads_saveAs.html +++ /dev/null @@ -1,68 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_eventpage_warning.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_eventpage_warning.html deleted file mode 100644 index ecea8237e..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_eventpage_warning.html +++ /dev/null @@ -1,106 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_hybrid_addons.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_hybrid_addons.html deleted file mode 100644 index a74c551f0..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_hybrid_addons.html +++ /dev/null @@ -1,141 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_idle.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_idle.html deleted file mode 100644 index 3c3063e67..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_idle.html +++ /dev/null @@ -1,64 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_shutdown_cleanup.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_shutdown_cleanup.html deleted file mode 100644 index e3098e6b1..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_shutdown_cleanup.html +++ /dev/null @@ -1,50 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_storage_cleanup.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_storage_cleanup.html deleted file mode 100644 index 010769500..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_storage_cleanup.html +++ /dev/null @@ -1,164 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_trustworthy_origin.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_trustworthy_origin.html deleted file mode 100644 index 573c08806..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_trustworthy_origin.html +++ /dev/null @@ -1,53 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_webnavigation_resolved_urls.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_webnavigation_resolved_urls.html deleted file mode 100644 index 768eb31fd..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_webnavigation_resolved_urls.html +++ /dev/null @@ -1,83 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_webrequest_background_events.html b/toolkit/components/webextensions/test/mochitest/test_chrome_ext_webrequest_background_events.html deleted file mode 100644 index a13c4d475..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_ext_webrequest_background_events.html +++ /dev/null @@ -1,96 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_chrome_native_messaging_paths.html b/toolkit/components/webextensions/test/mochitest/test_chrome_native_messaging_paths.html deleted file mode 100644 index 29a148063..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_chrome_native_messaging_paths.html +++ /dev/null @@ -1,61 +0,0 @@ -<!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> - diff --git a/toolkit/components/webextensions/test/mochitest/test_clipboard.html b/toolkit/components/webextensions/test/mochitest/test_clipboard.html deleted file mode 100644 index 900ee5f10..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_clipboard.html +++ /dev/null @@ -1,140 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_all_apis.js b/toolkit/components/webextensions/test/mochitest/test_ext_all_apis.js deleted file mode 100644 index 25d04b36b..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_all_apis.js +++ /dev/null @@ -1,160 +0,0 @@ -/* -*- 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.onConnectExternal", - "runtime.onInstalled", - "runtime.onMessageExternal", - "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(); -}); diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_background_api_injection.html b/toolkit/components/webextensions/test/mochitest/test_ext_background_api_injection.html deleted file mode 100644 index f43a59f81..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_background_api_injection.html +++ /dev/null @@ -1,46 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_background_canvas.html b/toolkit/components/webextensions/test/mochitest/test_ext_background_canvas.html deleted file mode 100644 index bff7190cb..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_background_canvas.html +++ /dev/null @@ -1,47 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_background_generated_url.html b/toolkit/components/webextensions/test/mochitest/test_ext_background_generated_url.html deleted file mode 100644 index f4fcf3d34..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_background_generated_url.html +++ /dev/null @@ -1,47 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_background_teardown.html b/toolkit/components/webextensions/test/mochitest/test_ext_background_teardown.html deleted file mode 100644 index bb6b2e970..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_background_teardown.html +++ /dev/null @@ -1,76 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_content_security_policy.html b/toolkit/components/webextensions/test/mochitest/test_ext_content_security_policy.html deleted file mode 100644 index a36f29563..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_content_security_policy.html +++ /dev/null @@ -1,162 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript.html deleted file mode 100644 index 39f1bfabd..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript.html +++ /dev/null @@ -1,116 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_about_blank.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_about_blank.html deleted file mode 100644 index 3766678e7..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_about_blank.html +++ /dev/null @@ -1,117 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_api_injection.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_api_injection.html deleted file mode 100644 index abf3d349f..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_api_injection.html +++ /dev/null @@ -1,88 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_async_loading.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_async_loading.html deleted file mode 100644 index d78f7ce02..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_async_loading.html +++ /dev/null @@ -1,54 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_context.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_context.html deleted file mode 100644 index 97b1645dd..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_context.html +++ /dev/null @@ -1,81 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_create_iframe.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_create_iframe.html deleted file mode 100644 index 8aac3e213..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_create_iframe.html +++ /dev/null @@ -1,165 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_css.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_css.html deleted file mode 100644 index 5630a1d68..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_css.html +++ /dev/null @@ -1,48 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_devtools_metadata.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_devtools_metadata.html deleted file mode 100644 index 137a3cda4..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_devtools_metadata.html +++ /dev/null @@ -1,81 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_exporthelpers.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_exporthelpers.html deleted file mode 100644 index f3414901d..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_exporthelpers.html +++ /dev/null @@ -1,95 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_incognito.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_incognito.html deleted file mode 100644 index a2f38dce6..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_incognito.html +++ /dev/null @@ -1,89 +0,0 @@ -<!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> - diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_permission.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_permission.html deleted file mode 100644 index eaf815092..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_permission.html +++ /dev/null @@ -1,59 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_teardown.html b/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_teardown.html deleted file mode 100644 index 33a8c4ccc..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_contentscript_teardown.html +++ /dev/null @@ -1,96 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_cookies.html b/toolkit/components/webextensions/test/mochitest/test_ext_cookies.html deleted file mode 100644 index d414a4e46..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_cookies.html +++ /dev/null @@ -1,234 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_cookies_containers.html b/toolkit/components/webextensions/test/mochitest/test_ext_cookies_containers.html deleted file mode 100644 index bc4994eec..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_cookies_containers.html +++ /dev/null @@ -1,93 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_cookies_expiry.html b/toolkit/components/webextensions/test/mochitest/test_ext_cookies_expiry.html deleted file mode 100644 index 3927d9e94..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_cookies_expiry.html +++ /dev/null @@ -1,72 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_cookies_permissions_bad.html b/toolkit/components/webextensions/test/mochitest/test_ext_cookies_permissions_bad.html deleted file mode 100644 index 15a62855a..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_cookies_permissions_bad.html +++ /dev/null @@ -1,112 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_cookies_permissions_good.html b/toolkit/components/webextensions/test/mochitest/test_ext_cookies_permissions_good.html deleted file mode 100644 index 31e83188c..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_cookies_permissions_good.html +++ /dev/null @@ -1,86 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_exclude_include_globs.html b/toolkit/components/webextensions/test/mochitest/test_ext_exclude_include_globs.html deleted file mode 100644 index 640522b40..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_exclude_include_globs.html +++ /dev/null @@ -1,92 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_external_messaging.html b/toolkit/components/webextensions/test/mochitest/test_ext_external_messaging.html deleted file mode 100644 index dfc1f9427..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_external_messaging.html +++ /dev/null @@ -1,111 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>WebExtension external messaging</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(id, otherId) { - browser.runtime.onMessage.addListener((msg, sender) => { - browser.test.fail(`Got unexpected message: ${uneval(msg)} ${uneval(sender)}`); - }); - - browser.runtime.onConnect.addListener(port => { - browser.test.fail(`Got unexpected connection: ${uneval(port.sender)}`); - }); - - browser.runtime.onMessageExternal.addListener((msg, sender) => { - browser.test.assertEq(otherId, sender.id, `${id}: Got expected external sender ID`); - browser.test.assertEq(`helo-${id}`, msg, "Got expected message"); - - browser.test.sendMessage("onMessage-done"); - - return Promise.resolve(`ehlo-${otherId}`); - }); - - browser.runtime.onConnectExternal.addListener(port => { - browser.test.assertEq(otherId, port.sender.id, `${id}: Got expected external connecter ID`); - - port.onMessage.addListener(msg => { - browser.test.assertEq(`helo-${id}`, msg, "Got expected port message"); - - port.postMessage(`ehlo-${otherId}`); - - browser.test.sendMessage("onConnect-done"); - }); - }); - - browser.test.onMessage.addListener(msg => { - if (msg === "go") { - browser.runtime.sendMessage(otherId, `helo-${otherId}`).then(result => { - browser.test.assertEq(`ehlo-${id}`, result, "Got expected reply"); - browser.test.sendMessage("sendMessage-done"); - }); - - let port = browser.runtime.connect(otherId); - port.postMessage(`helo-${otherId}`); - - port.onMessage.addListener(msg => { - port.disconnect(); - - browser.test.assertEq(msg, `ehlo-${id}`, "Got expected port reply"); - browser.test.sendMessage("connect-done"); - }); - } - }); -} - -function makeExtension(id, otherId) { - let args = `${JSON.stringify(id)}, ${JSON.stringify(otherId)}`; - - let extensionData = { - background: `(${backgroundScript})(${args})`, - manifest: { - "applications": {"gecko": {id}}, - }, - }; - - return ExtensionTestUtils.loadExtension(extensionData); -} - -add_task(function* test_contentscript() { - const ID1 = "foo-message@mochitest.mozilla.org"; - const ID2 = "bar-message@mochitest.mozilla.org"; - - let extension1 = makeExtension(ID1, ID2); - let extension2 = makeExtension(ID2, ID1); - - yield Promise.all([extension1.startup(), extension2.startup()]); - - extension1.sendMessage("go"); - extension2.sendMessage("go"); - - yield Promise.all([ - extension1.awaitMessage("sendMessage-done"), - extension2.awaitMessage("sendMessage-done"), - - extension1.awaitMessage("onMessage-done"), - extension2.awaitMessage("onMessage-done"), - - extension1.awaitMessage("connect-done"), - extension2.awaitMessage("connect-done"), - - extension1.awaitMessage("onConnect-done"), - extension2.awaitMessage("onConnect-done"), - ]); - - yield extension1.unload(); - yield extension2.unload(); -}); -</script> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_generate.html b/toolkit/components/webextensions/test/mochitest/test_ext_generate.html deleted file mode 100644 index cfafcbad9..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_generate.html +++ /dev/null @@ -1,49 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_geturl.html b/toolkit/components/webextensions/test/mochitest/test_ext_geturl.html deleted file mode 100644 index 6e39c2f5d..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_geturl.html +++ /dev/null @@ -1,72 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_i18n.html b/toolkit/components/webextensions/test/mochitest/test_ext_i18n.html deleted file mode 100644 index 1f7330bbb..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_i18n.html +++ /dev/null @@ -1,432 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_i18n_css.html b/toolkit/components/webextensions/test/mochitest/test_ext_i18n_css.html deleted file mode 100644 index 7c6a8eeaa..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_i18n_css.html +++ /dev/null @@ -1,116 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_inIncognitoContext_window.html b/toolkit/components/webextensions/test/mochitest/test_ext_inIncognitoContext_window.html deleted file mode 100644 index 675cbb298..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_inIncognitoContext_window.html +++ /dev/null @@ -1,49 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_jsversion.html b/toolkit/components/webextensions/test/mochitest/test_ext_jsversion.html deleted file mode 100644 index da0c355e0..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_jsversion.html +++ /dev/null @@ -1,86 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_listener_proxies.html b/toolkit/components/webextensions/test/mochitest/test_ext_listener_proxies.html deleted file mode 100644 index ca8db873e..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_listener_proxies.html +++ /dev/null @@ -1,63 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_notifications.html b/toolkit/components/webextensions/test/mochitest/test_ext_notifications.html deleted file mode 100644 index d1b798cf9..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_notifications.html +++ /dev/null @@ -1,224 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_permission_xhr.html b/toolkit/components/webextensions/test/mochitest/test_ext_permission_xhr.html deleted file mode 100644 index 07967d5d0..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_permission_xhr.html +++ /dev/null @@ -1,119 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_runtime_connect.html b/toolkit/components/webextensions/test/mochitest/test_ext_runtime_connect.html deleted file mode 100644 index 60351eaee..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_runtime_connect.html +++ /dev/null @@ -1,83 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_runtime_connect2.html b/toolkit/components/webextensions/test/mochitest/test_ext_runtime_connect2.html deleted file mode 100644 index dce12b21b..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_runtime_connect2.html +++ /dev/null @@ -1,103 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_runtime_connect_twoway.html b/toolkit/components/webextensions/test/mochitest/test_ext_runtime_connect_twoway.html deleted file mode 100644 index e84134eff..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_runtime_connect_twoway.html +++ /dev/null @@ -1,127 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_runtime_disconnect.html b/toolkit/components/webextensions/test/mochitest/test_ext_runtime_disconnect.html deleted file mode 100644 index 5764d0a3c..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_runtime_disconnect.html +++ /dev/null @@ -1,78 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_runtime_id.html b/toolkit/components/webextensions/test/mochitest/test_ext_runtime_id.html deleted file mode 100644 index 4cdefda41..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_runtime_id.html +++ /dev/null @@ -1,61 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_sandbox_var.html b/toolkit/components/webextensions/test/mochitest/test_ext_sandbox_var.html deleted file mode 100644 index 426a71ac6..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_sandbox_var.html +++ /dev/null @@ -1,60 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_schema.html b/toolkit/components/webextensions/test/mochitest/test_ext_schema.html deleted file mode 100644 index 8a0e11c56..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_schema.html +++ /dev/null @@ -1,73 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_doublereply.html b/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_doublereply.html deleted file mode 100644 index a3ef37cad..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_doublereply.html +++ /dev/null @@ -1,101 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_no_receiver.html b/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_no_receiver.html deleted file mode 100644 index 96af6558e..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_no_receiver.html +++ /dev/null @@ -1,83 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_reply.html b/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_reply.html deleted file mode 100644 index a4ac708b2..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_reply.html +++ /dev/null @@ -1,79 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_reply2.html b/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_reply2.html deleted file mode 100644 index 5c350be2f..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_sendmessage_reply2.html +++ /dev/null @@ -1,181 +0,0 @@ -<!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, id, otherId) { - browser.tabs.create({url: "tab.html"}); - - browser.runtime.onMessage.addListener((msg, sender, sendReply) => { - browser.test.assertEq(id, sender.id, `${id}: Got expected sender ID`); - - if (msg === `content-${token}`) { - browser.test.assertTrue(sender.tab.url.endsWith("file_sample.html"), - `${id}: sender url correct`); - - let tabId = sender.tab.id; - browser.tabs.sendMessage(tabId, `${token}-contentMessage`); - - sendReply(`${token}-done`); - } else if (msg === `tab-${token}`) { - browser.runtime.sendMessage(otherId, `${otherId}-tabMessage`); - browser.runtime.sendMessage(`${token}-tabMessage`); - - sendReply(`${token}-done`); - } else { - browser.test.fail(`${id}: Unexpected runtime message received: ${msg} ${uneval(sender)}`); - } - }); - - browser.runtime.onMessageExternal.addListener((msg, sender, sendReply) => { - browser.test.assertEq(otherId, sender.id, `${id}: Got expected external sender ID`); - - if (msg === `content-${id}`) { - browser.test.assertTrue(sender.tab.url.endsWith("file_sample.html"), - `${id}: external sender url correct`); - - sendReply(`${otherId}-done`); - } else if (msg === `tab-${id}`) { - sendReply(`${otherId}-done`); - } else if (msg !== `${id}-tabMessage`) { - browser.test.fail(`${id}: Unexpected runtime external message received: ${msg} ${uneval(sender)}`); - } - }); -} - -function contentScript(token, id, otherId) { - let gotContentMessage = false; - browser.runtime.onMessage.addListener((msg, sender, sendReply) => { - browser.test.assertEq(id, sender.id, `${id}: Got expected sender ID`); - - browser.test.assertEq(`${token}-contentMessage`, msg, - `${id}: Correct content script message`); - if (msg === `${token}-contentMessage`) { - gotContentMessage = true; - } - }); - - Promise.all([ - browser.runtime.sendMessage(otherId, `content-${otherId}`).then(resp => { - browser.test.assertEq(`${id}-done`, resp, `${id}: Correct content script external response token`); - }), - - browser.runtime.sendMessage(`content-${token}`).then(resp => { - browser.test.assertEq(`${token}-done`, resp, `${id}: Correct content script response token`); - }), - ]).then(() => { - browser.test.assertTrue(gotContentMessage, `${id}: Got content script message`); - - browser.test.sendMessage("content-script-done"); - }); -} - -function tabScript(token, id, otherId) { - let gotTabMessage = false; - browser.runtime.onMessage.addListener((msg, sender, sendReply) => { - browser.test.assertEq(id, sender.id, `${id}: Got expected sender ID`); - - if (String(msg).startsWith("content-")) { - return; - } - - browser.test.assertEq(`${token}-tabMessage`, msg, - `${id}: Correct tab script message`); - if (msg === `${token}-tabMessage`) { - gotTabMessage = true; - } - }); - - Promise.all([ - browser.runtime.sendMessage(otherId, `tab-${otherId}`).then(resp => { - browser.test.assertEq(`${id}-done`, resp, `${id}: Correct tab script external response token`); - }), - - browser.runtime.sendMessage(`tab-${token}`).then(resp => { - browser.test.assertEq(`${token}-done`, resp, `${id}: Correct tab script response token`); - }), - ]).then(() => { - browser.test.assertTrue(gotTabMessage, `${id}: Got tab script message`); - - window.close(); - - browser.test.sendMessage("tab-script-done"); - }); -} - -function makeExtension(id, otherId) { - let token = Math.random(); - - let args = `${token}, ${JSON.stringify(id)}, ${JSON.stringify(otherId)}`; - - let extensionData = { - background: `(${backgroundScript})(${args})`, - manifest: { - "applications": {"gecko": {id}}, - - "permissions": ["tabs"], - - - "content_scripts": [{ - "matches": ["http://mochi.test/*/file_sample.html"], - "js": ["content_script.js"], - "run_at": "document_start", - }], - }, - - files: { - "tab.html": `<!DOCTYPE html> - <html> - <head> - <meta charset="utf-8"> - <script src="tab.js"><\/script> - </head> - </html>`, - - "tab.js": `(${tabScript})(${args})`, - - "content_script.js": `(${contentScript})(${args})`, - }, - }; - return extensionData; -} - -add_task(function* test_contentscript() { - const ID1 = "sendmessage1@mochitest.mozilla.org"; - const ID2 = "sendmessage2@mochitest.mozilla.org"; - - let extension1 = ExtensionTestUtils.loadExtension(makeExtension(ID1, ID2)); - let extension2 = ExtensionTestUtils.loadExtension(makeExtension(ID2, ID1)); - - yield Promise.all([extension1.startup(), extension2.startup()]); - - let win = window.open("file_sample.html"); - - yield waitForLoad(win); - - yield Promise.all([ - extension1.awaitMessage("content-script-done"), - extension2.awaitMessage("content-script-done"), - extension1.awaitMessage("tab-script-done"), - extension2.awaitMessage("tab-script-done"), - ]); - - win.close(); - - yield extension1.unload(); - yield extension2.unload(); -}); -</script> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_storage_content.html b/toolkit/components/webextensions/test/mochitest/test_ext_storage_content.html deleted file mode 100644 index 09a33814a..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_storage_content.html +++ /dev/null @@ -1,330 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_storage_tab.html b/toolkit/components/webextensions/test/mochitest/test_ext_storage_tab.html deleted file mode 100644 index 32d8e6af0..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_storage_tab.html +++ /dev/null @@ -1,118 +0,0 @@ -<!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> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_subframes_privileges.html b/toolkit/components/webextensions/test/mochitest/test_ext_subframes_privileges.html deleted file mode 100644 index 1f3a9a3c9..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_subframes_privileges.html +++ /dev/null @@ -1,202 +0,0 @@ -<!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_webext_tab_subframe_privileges() { - function background() { - browser.runtime.onMessage.addListener(async ({msg, success, tabId, error}) => { - if (msg == "webext-tab-subframe-privileges") { - if (success) { - await browser.tabs.remove(tabId); - - browser.test.notifyPass(msg); - } else { - browser.test.log(`Got an unexpected error: ${error}`); - - let tabs = await browser.tabs.query({active: true}); - await browser.tabs.remove(tabs[0].id); - - browser.test.notifyFail(msg); - } - } - }); - browser.tabs.create({url: browser.runtime.getURL("/tab.html")}); - } - - async function tabSubframeScript() { - browser.test.assertTrue(browser.tabs != undefined, - "Subframe of a privileged page has access to privileged APIs"); - if (browser.tabs) { - try { - let tab = await browser.tabs.getCurrent(); - browser.runtime.sendMessage({ - msg: "webext-tab-subframe-privileges", - success: true, - tabId: tab.id, - }); - } catch (e) { - browser.runtime.sendMessage({msg: "webext-tab-subframe-privileges", success: false, error: `${e}`}); - } - } else { - browser.runtime.sendMessage({ - msg: "webext-tab-subframe-privileges", - success: false, - error: `Privileged APIs missing in WebExtension tab sub-frame`, - }); - } - } - - let extensionData = { - background, - files: { - "tab.html": `<!DOCTYPE> - <head> - <meta charset="utf-8"> - </head> - <body> - <iframe src="tab-subframe.html"></iframe> - </body> - </html>`, - "tab-subframe.html": `<!DOCTYPE> - <head> - <meta charset="utf-8"> - <script src="tab-subframe.js"><\/script> - </head> - </html>`, - "tab-subframe.js": tabSubframeScript, - }, - }; - let extension = ExtensionTestUtils.loadExtension(extensionData); - - yield extension.startup(); - - yield extension.awaitFinish("webext-tab-subframe-privileges"); - yield extension.unload(); -}); - -add_task(function* test_webext_background_subframe_privileges() { - function backgroundSubframeScript() { - browser.test.assertTrue(browser.tabs != undefined, - "Subframe of a background page has access to privileged APIs"); - browser.test.notifyPass("webext-background-subframe-privileges"); - } - - let extensionData = { - manifest: { - background: { - page: "background.html", - }, - }, - files: { - "background.html": `<!DOCTYPE> - <head> - <meta charset="utf-8"> - </head> - <body> - <iframe src="background-subframe.html"></iframe> - </body> - </html>`, - "background-subframe.html": `<!DOCTYPE> - <head> - <meta charset="utf-8"> - <script src="background-subframe.js"><\/script> - </head> - </html>`, - "background-subframe.js": backgroundSubframeScript, - }, - }; - let extension = ExtensionTestUtils.loadExtension(extensionData); - - yield extension.startup(); - - yield extension.awaitFinish("webext-background-subframe-privileges"); - yield extension.unload(); -}); - -add_task(function* test_webext_contentscript_iframe_subframe_privileges() { - function background() { - browser.runtime.onMessage.addListener(({name, hasTabsAPI, hasStorageAPI}) => { - if (name == "contentscript-iframe-loaded") { - browser.test.assertFalse(hasTabsAPI, - "Subframe of a content script privileged iframes has no access to privileged APIs"); - browser.test.assertTrue(hasStorageAPI, - "Subframe of a content script privileged iframes has access to content script APIs"); - - browser.test.notifyPass("webext-contentscript-subframe-privileges"); - } - }); - } - - function subframeScript() { - browser.runtime.sendMessage({ - name: "contentscript-iframe-loaded", - hasTabsAPI: browser.tabs != undefined, - hasStorageAPI: browser.storage != undefined, - }); - } - - function contentScript() { - let iframe = document.createElement("iframe"); - iframe.setAttribute("src", browser.runtime.getURL("/contentscript-iframe.html")); - document.body.appendChild(iframe); - } - - let extensionData = { - background, - manifest: { - "permissions": ["storage"], - "content_scripts": [{ - "matches": ["http://example.com/*"], - "js": ["contentscript.js"], - }], - web_accessible_resources: [ - "contentscript-iframe.html", - ], - }, - files: { - "contentscript.js": contentScript, - "contentscript-iframe.html": `<!DOCTYPE> - <head> - <meta charset="utf-8"> - </head> - <body> - <iframe src="contentscript-iframe-subframe.html"></iframe> - </body> - </html>`, - "contentscript-iframe-subframe.html": `<!DOCTYPE> - <head> - <meta charset="utf-8"> - <script src="contentscript-iframe-subframe.js"><\/script> - </head> - </html>`, - "contentscript-iframe-subframe.js": subframeScript, - }, - }; - let extension = ExtensionTestUtils.loadExtension(extensionData); - - yield extension.startup(); - - let win = window.open("http://example.com"); - - yield extension.awaitFinish("webext-contentscript-subframe-privileges"); - - win.close(); - - yield extension.unload(); -}); - -</script> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_tab_teardown.html b/toolkit/components/webextensions/test/mochitest/test_ext_tab_teardown.html deleted file mode 100644 index dc351e48a..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_tab_teardown.html +++ /dev/null @@ -1,150 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test for extension tab 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"; - -// Test for tabs opened using tabs.create and window.open -function* runTabReloadAndCloseTest(extension) { - 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"); - dump(JSON.stringify(contextEvents)); - return contextEvents.filter(event => event.extensionId == extension.id); - } - - extension.sendMessage("open extension page"); - let extensionPageUrl = yield extension.awaitMessage("extension page loaded"); - - let contextEvents = yield* getContextEvents(); - is(contextEvents.length, 1, "ExtensionContext change for opening a tab"); - is(contextEvents[0].eventType, "load", "create ExtensionContext for tab"); - is(contextEvents[0].url, extensionPageUrl, - "ExtensionContext URL after tab creation should be tab URL"); - - extension.sendMessage("reload extension page"); - let extensionPageUrl2 = yield extension.awaitMessage("extension page loaded"); - - is(extensionPageUrl, extensionPageUrl2, - "The tab's URL is expected to not change after a page reload"); - - contextEvents = yield* getContextEvents(); - is(contextEvents.length, 2, "ExtensionContext change after tab reload"); - is(contextEvents[0].eventType, "unload", "unload old ExtensionContext"); - is(contextEvents[0].url, extensionPageUrl, - "ExtensionContext URL before reload should be tab URL"); - is(contextEvents[1].eventType, "load", "create new ExtensionContext for tab"); - is(contextEvents[1].url, extensionPageUrl2, - "ExtensionContext URL after reload should be tab URL"); - - extension.sendMessage("close extension page"); - yield extension.awaitMessage("closed extension page"); - - contextEvents = yield* getContextEvents(); - is(contextEvents.length, 1, "ExtensionContext after closing tab"); - is(contextEvents[0].eventType, "unload", "unload tab's ExtensionContext"); - is(contextEvents[0].url, extensionPageUrl2, - "ExtensionContext URL at closing tab should be tab URL"); - - chromeScript.sendAsyncMessage("cleanup"); - chromeScript.destroy(); - yield extension.unload(); -} - -add_task(function* test_extension_page_tabs_create_reload_and_close() { - function background() { - let tabId; - browser.test.onMessage.addListener(msg => { - if (msg === "open extension page") { - chrome.tabs.create({url: "page.html"}, tab => { - tabId = tab.id; - }); - } else if (msg === "reload extension page") { - chrome.tabs.reload(tabId); - } else if (msg === "close extension page") { - chrome.tabs.remove(tabId, () => { - browser.test.sendMessage("closed extension page"); - }); - } - }); - } - - function pageScript() { - browser.test.sendMessage("extension page loaded", document.URL); - } - - let extensionData = { - background, - files: { - "page.html": `<!DOCTYPE html><meta charset="utf-8"><script src="page.js"><\/script>`, - "page.js": pageScript, - }, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - - yield* runTabReloadAndCloseTest(extension); -}); - -add_task(function* test_extension_page_window_open_reload_and_close() { - // This tests whether a context that is opened via window.open is properly - // disposed when the tab closes. - // The background page cannot use window.open (bugzil.la/1282021), so we open - // another extension page that manages the window.open-tab for testing. - function background() { - chrome.tabs.create({url: "window.open.html"}); - } - - function windowOpenScript() { - let win; - browser.test.onMessage.addListener(msg => { - if (msg === "open extension page") { - win = window.open("page.html"); - } else if (msg === "reload extension page") { - win.location.reload(); - } else if (msg === "close extension page") { - browser.tabs.onRemoved.addListener(function listener() { - browser.tabs.onRemoved.removeListener(listener); - browser.test.sendMessage("closed extension page"); - }); - win.close(); - } - }); - browser.test.sendMessage("setup-intermediate-tab"); - } - - function pageScript() { - browser.test.sendMessage("extension page loaded", document.URL); - } - - let extensionData = { - background, - files: { - "page.html": `<!DOCTYPE html><meta charset="utf-8"><script src="page.js"><\/script>`, - "page.js": pageScript, - "window.open.html": `<!DOCTYPE html><meta charset="utf-8"><script src="window.open.js"><\/script>`, - "window.open.js": windowOpenScript, - }, - }; - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - yield extension.awaitMessage("setup-intermediate-tab"); - yield* runTabReloadAndCloseTest(extension); -}); -</script> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_test.html b/toolkit/components/webextensions/test/mochitest/test_ext_test.html deleted file mode 100644 index fef31e0e2..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_test.html +++ /dev/null @@ -1,191 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Testing 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="head.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"> -</head> -<body> - -<script> -"use strict"; - -function loadExtensionAndInterceptTest(extensionData) { - let results = []; - let testResolve; - let testDone = new Promise(resolve => { testResolve = resolve; }); - let handler = { - testResult(...result) { - result.pop(); - results.push(result); - SimpleTest.info(`Received test result: ${JSON.stringify(result)}`); - }, - - testMessage(msg, ...args) { - results.push(["test-message", msg, ...args]); - SimpleTest.info(`Received message: ${msg} ${JSON.stringify(args)}`); - if (msg === "This is the last browser.test call") { - testResolve(); - } - }, - }; - let extension = SpecialPowers.loadExtension(extensionData, handler); - SimpleTest.registerCleanupFunction(() => { - if (extension.state == "pending" || extension.state == "running") { - SimpleTest.ok(false, "Extension left running at test shutdown"); - return extension.unload(); - } else if (extension.state == "unloading") { - SimpleTest.ok(false, "Extension not fully unloaded at test shutdown"); - } - }); - extension.awaitResults = () => testDone.then(() => results); - return extension; -} - -function testScript() { - // Note: The result of these browser.test calls are intercepted by the test. - // See verifyTestResults for the expectations of each browser.test call. - browser.test.notifyPass("dot notifyPass"); - browser.test.notifyFail("dot notifyFail"); - browser.test.log("dot log"); - browser.test.fail("dot fail"); - browser.test.succeed("dot succeed"); - browser.test.assertTrue(true); - browser.test.assertFalse(false); - browser.test.assertEq("", ""); - - let obj = {}; - let arr = []; - let dom = document.createElement("body"); - browser.test.assertTrue(obj, "Object truthy"); - browser.test.assertTrue(arr, "Array truthy"); - browser.test.assertTrue(dom, "Element truthy"); - browser.test.assertTrue(true, "True truthy"); - browser.test.assertTrue(false, "False truthy"); - browser.test.assertTrue(null, "Null truthy"); - browser.test.assertTrue(undefined, "Void truthy"); - browser.test.assertTrue(false, document.createElement("html")); - - browser.test.assertFalse(obj, "Object falsey"); - browser.test.assertFalse(arr, "Array falsey"); - browser.test.assertFalse(dom, "Element falsey"); - browser.test.assertFalse(true, "True falsey"); - browser.test.assertFalse(false, "False falsey"); - browser.test.assertFalse(null, "Null falsey"); - browser.test.assertFalse(undefined, "Void falsey"); - browser.test.assertFalse(true, document.createElement("head")); - - browser.test.assertEq(obj, obj, "Object equality"); - browser.test.assertEq(arr, arr, "Array equality"); - browser.test.assertEq(dom, dom, "Element equality"); - browser.test.assertEq(null, null, "Null equality"); - browser.test.assertEq(undefined, undefined, "Void equality"); - - browser.test.assertEq({}, {}, "Object reference ineqality"); - browser.test.assertEq([], [], "Array reference ineqality"); - browser.test.assertEq(dom, document.createElement("body"), "Element ineqality"); - browser.test.assertEq(null, undefined, "Null and void ineqality"); - browser.test.assertEq(true, false, document.createElement("div")); - - obj = { - toString() { - return "Dynamic toString forbidden"; - }, - }; - browser.test.assertEq(obj, obj, "obj with dynamic toString()"); - browser.test.sendMessage("Ran test at", location.protocol); - browser.test.sendMessage("This is the last browser.test call"); -} - -function verifyTestResults(results, shortName, expectedProtocol) { - let expectations = [ - ["test-done", true, "dot notifyPass"], - ["test-done", false, "dot notifyFail"], - ["test-log", true, "dot log"], - ["test-result", false, "dot fail"], - ["test-result", true, "dot succeed"], - ["test-result", true, "undefined"], - ["test-result", true, "undefined"], - ["test-eq", true, "undefined", "", ""], - - ["test-result", true, "Object truthy"], - ["test-result", true, "Array truthy"], - ["test-result", true, "Element truthy"], - ["test-result", true, "True truthy"], - ["test-result", false, "False truthy"], - ["test-result", false, "Null truthy"], - ["test-result", false, "Void truthy"], - ["test-result", false, "[object HTMLHtmlElement]"], - - ["test-result", false, "Object falsey"], - ["test-result", false, "Array falsey"], - ["test-result", false, "Element falsey"], - ["test-result", false, "True falsey"], - ["test-result", true, "False falsey"], - ["test-result", true, "Null falsey"], - ["test-result", true, "Void falsey"], - ["test-result", false, "[object HTMLHeadElement]"], - - ["test-eq", true, "Object equality", "[object Object]", "[object Object]"], - ["test-eq", true, "Array equality", "", ""], - ["test-eq", true, "Element equality", "[object HTMLBodyElement]", "[object HTMLBodyElement]"], - ["test-eq", true, "Null equality", "null", "null"], - ["test-eq", true, "Void equality", "undefined", "undefined"], - - ["test-eq", false, "Object reference ineqality", "[object Object]", "[object Object] (different)"], - ["test-eq", false, "Array reference ineqality", "", " (different)"], - ["test-eq", false, "Element ineqality", "[object HTMLBodyElement]", "[object HTMLBodyElement] (different)"], - ["test-eq", false, "Null and void ineqality", "null", "undefined"], - ["test-eq", false, "[object HTMLDivElement]", "true", "false"], - - ["test-eq", true, "obj with dynamic toString()", "[object Object]", "[object Object]"], - - ["test-message", "Ran test at", expectedProtocol], - ["test-message", "This is the last browser.test call"], - ]; - - expectations.forEach((expectation, i) => { - let msg = expectation.slice(2).join(" - "); - isDeeply(results[i], expectation, `${shortName} (${msg})`); - }); - is(results[expectations.length], undefined, "No more results"); -} - -add_task(function* test_test_in_background() { - let extensionData = { - background: `(${testScript})()`, - }; - - let extension = loadExtensionAndInterceptTest(extensionData); - yield extension.startup(); - let results = yield extension.awaitResults(); - verifyTestResults(results, "background page", "moz-extension:"); - yield extension.unload(); -}); - -add_task(function* test_test_in_content_script() { - let extensionData = { - manifest: { - content_scripts: [{ - matches: ["http://mochi.test/*/file_sample.html"], - js: ["contentscript.js"], - }], - }, - files: { - "contentscript.js": `(${testScript})()`, - }, - }; - - let extension = loadExtensionAndInterceptTest(extensionData); - yield extension.startup(); - let win = window.open("file_sample.html"); - let results = yield extension.awaitResults(); - win.close(); - verifyTestResults(results, "content script", "http:"); - yield extension.unload(); -}); -</script> -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_unload_frame.html b/toolkit/components/webextensions/test/mochitest/test_ext_unload_frame.html deleted file mode 100644 index 5572de281..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_unload_frame.html +++ /dev/null @@ -1,170 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>WebExtensions 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"; - -/* globals delayedNotifyPass */ // Available in the background page of the test extensions. - -// Background and content script for testSendMessage_* -function sendMessage_background() { - browser.runtime.onMessage.addListener((msg, sender, sendResponse) => { - browser.test.assertEq("from frame", msg, "Expected message from frame"); - sendResponse("msg from back"); // Should not throw or anything like that. - delayedNotifyPass("Received sendMessage from closing frame"); - }); -} -function sendMessage_contentScript(testType) { - browser.runtime.sendMessage("from frame", reply => { - // The frame has been removed, so we should not get this callback! - browser.test.fail(`Unexpected reply: ${reply}`); - }); - if (testType == "frame") { - frameElement.remove(); - } else { - window.close(); - } -} - -// Background and content script for testConnect_* -function connect_background() { - browser.runtime.onConnect.addListener(port => { - browser.test.assertEq("port from frame", port.name); - - let disconnected = false; - let hasMessage = false; - port.onDisconnect.addListener(() => { - browser.test.assertFalse(disconnected, "onDisconnect should fire once"); - disconnected = true; - browser.test.assertTrue(hasMessage, "Expected onMessage before onDisconnect"); - browser.test.assertEq(null, port.error, "The port is implicitly closed without errors when the other context unloads"); - delayedNotifyPass("Received onDisconnect from closing frame"); - }); - port.onMessage.addListener(msg => { - browser.test.assertFalse(hasMessage, "onMessage should fire once"); - hasMessage = true; - browser.test.assertFalse(disconnected, "Should get message before disconnect"); - browser.test.assertEq("from frame", msg, "Expected message from frame"); - }); - - port.postMessage("reply to closing frame"); - }); -} -function connect_contentScript(testType) { - let isUnloading = false; - addEventListener("pagehide", () => { isUnloading = true; }, {once: true}); - - let port = browser.runtime.connect({name: "port from frame"}); - port.onMessage.addListener(msg => { - // The background page sends a reply as soon as we call runtime.connect(). - // It is possible that the reply reaches this frame before the - // window.close() request has been processed. - if (!isUnloading) { - browser.test.log(`Ignorting unexpected reply ("${msg}") because the page is not being unloaded.`); - return; - } - - // The frame has been removed, so we should not get a reply. - browser.test.fail(`Unexpected reply: ${msg}`); - }); - port.postMessage("from frame"); - - // Removing the frame or window should disconnect the port. - if (testType == "frame") { - frameElement.remove(); - } else { - window.close(); - } -} - -// `testType` is "window" or "frame". -function createTestExtension(testType, backgroundScript, contentScript) { - // Make a roundtrip between the background page and the test runner (which is - // in the same process as the content script) to make sure that we record a - // failure in case the content script's sendMessage or onMessage handlers are - // called even after the frame or window was removed. - function delayedNotifyPass(msg) { - browser.test.onMessage.addListener((type, echoMsg) => { - if (type == "pong") { - browser.test.assertEq(msg, echoMsg, "Echoed reply should be the same"); - browser.test.notifyPass(msg); - } - }); - browser.test.log("Starting ping-pong to flush messages..."); - browser.test.sendMessage("ping", msg); - } - let extension = ExtensionTestUtils.loadExtension({ - background: `${delayedNotifyPass};(${backgroundScript})();`, - manifest: { - content_scripts: [{ - js: ["contentscript.js"], - all_frames: testType == "frame", - matches: ["http://mochi.test/*/file_sample.html"], - }], - }, - files: { - "contentscript.js": `(${contentScript})("${testType}");`, - }, - }); - extension.awaitMessage("ping").then(msg => { - extension.sendMessage("pong", msg); - }); - return extension; -} - -add_task(function* testSendMessage_and_remove_frame() { - let extension = createTestExtension("frame", sendMessage_background, sendMessage_contentScript); - yield extension.startup(); - - let frame = document.createElement("iframe"); - frame.src = "file_sample.html"; - document.body.appendChild(frame); - - yield extension.awaitFinish("Received sendMessage from closing frame"); - yield extension.unload(); -}); - -add_task(function* testConnect_and_remove_frame() { - let extension = createTestExtension("frame", connect_background, connect_contentScript); - yield extension.startup(); - - let frame = document.createElement("iframe"); - frame.src = "file_sample.html"; - document.body.appendChild(frame); - - yield extension.awaitFinish("Received onDisconnect from closing frame"); - yield extension.unload(); -}); - -add_task(function* testSendMessage_and_remove_window() { - let extension = createTestExtension("window", sendMessage_background, sendMessage_contentScript); - yield extension.startup(); - - window.open("file_sample.html"); - - yield extension.awaitFinish("Received sendMessage from closing frame"); - yield extension.unload(); -}); - -add_task(function* testConnect_and_remove_window() { - let extension = createTestExtension("window", connect_background, connect_contentScript); - yield extension.startup(); - - window.open("file_sample.html"); - - yield extension.awaitFinish("Received onDisconnect from closing frame"); - yield extension.unload(); -}); - -</script> -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_web_accessible_resources.html b/toolkit/components/webextensions/test/mochitest/test_ext_web_accessible_resources.html deleted file mode 100644 index fa3228739..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_web_accessible_resources.html +++ /dev/null @@ -1,353 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test the web_accessible_resources manifest directive</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 */ - -SimpleTest.registerCleanupFunction(() => { - SpecialPowers.clearUserPref("security.mixed_content.block_display_content"); -}); - -let image = atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" + - "ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII="); -const IMAGE_ARRAYBUFFER = Uint8Array.from(image, byte => byte.charCodeAt(0)).buffer; - -async function testImageLoading(src, expectedAction) { - let imageLoadingPromise = new Promise((resolve, reject) => { - let cleanupListeners; - let testImage = document.createElement("img"); - testImage.setAttribute("src", src); - - let loadListener = () => { - cleanupListeners(); - resolve(expectedAction === "loaded"); - }; - - let errorListener = () => { - cleanupListeners(); - resolve(expectedAction === "blocked"); - }; - - cleanupListeners = () => { - testImage.removeEventListener("load", loadListener); - testImage.removeEventListener("error", errorListener); - }; - - testImage.addEventListener("load", loadListener); - testImage.addEventListener("error", errorListener); - - document.body.appendChild(testImage); - }); - - let success = await imageLoadingPromise; - browser.runtime.sendMessage({name: "image-loading", expectedAction, success}); -} - -add_task(function* test_web_accessible_resources() { - function background() { - let gotURL; - let tabId; - - function loadFrame(url) { - return new Promise(resolve => { - browser.tabs.sendMessage(tabId, ["load-iframe", url], reply => { - resolve(reply); - }); - }); - } - - let urls = [ - [browser.extension.getURL("accessible.html"), true], - [browser.extension.getURL("accessible.html") + "?foo=bar", true], - [browser.extension.getURL("accessible.html") + "#!foo=bar", true], - [browser.extension.getURL("forbidden.html"), false], - [browser.extension.getURL("wild1.html"), true], - [browser.extension.getURL("wild2.htm"), false], - ]; - - async function runTests() { - for (let [url, shouldLoad] of urls) { - let success = await loadFrame(url); - - browser.test.assertEq(shouldLoad, success, "Load was successful"); - if (shouldLoad) { - browser.test.assertEq(url, gotURL, "Got expected url"); - } else { - browser.test.assertEq(undefined, gotURL, "Got no url"); - } - gotURL = undefined; - } - - browser.test.notifyPass("web-accessible-resources"); - } - - browser.runtime.onMessage.addListener(([msg, url], sender) => { - if (msg == "content-script-ready") { - tabId = sender.tab.id; - runTests(); - } else if (msg == "page-script") { - browser.test.assertEq(undefined, gotURL, "Should have gotten only one message"); - browser.test.assertEq("string", typeof(url), "URL should be a string"); - gotURL = url; - } - }); - - browser.test.sendMessage("ready"); - } - - function contentScript() { - browser.runtime.onMessage.addListener(([msg, url], sender, respond) => { - if (msg == "load-iframe") { - let iframe = document.createElement("iframe"); - iframe.setAttribute("src", url); - iframe.addEventListener("load", () => { respond(true); }); - iframe.addEventListener("error", () => { respond(false); }); - document.body.appendChild(iframe); - return true; - } - }); - browser.runtime.sendMessage(["content-script-ready"]); - } - - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - content_scripts: [ - { - "matches": ["http://example.com/"], - "js": ["content_script.js"], - "run_at": "document_idle", - }, - ], - - "web_accessible_resources": [ - "/accessible.html", - "wild*.html", - ], - }, - - background, - - files: { - "content_script.js": contentScript, - - "accessible.html": `<html><head> - <meta charset="utf-8"> - <script src="accessible.js"><\/script> - </head></html>`, - - "accessible.js": 'browser.runtime.sendMessage(["page-script", location.href]);', - - "inaccessible.html": `<html><head> - <meta charset="utf-8"> - <script src="inaccessible.js"><\/script> - </head></html>`, - - "inaccessible.js": 'browser.runtime.sendMessage(["page-script", location.href]);', - - "wild1.html": `<html><head> - <meta charset="utf-8"> - <script src="wild.js"><\/script> - </head></html>`, - - "wild2.htm": `<html><head> - <meta charset="utf-8"> - <script src="wild.js"><\/script> - </head></html>`, - - "wild.js": 'browser.runtime.sendMessage(["page-script", location.href]);', - }, - }); - - yield extension.startup(); - - yield extension.awaitMessage("ready"); - - let win = window.open("http://example.com/"); - - yield extension.awaitFinish("web-accessible-resources"); - - win.close(); - - yield extension.unload(); -}); - -add_task(function* test_web_accessible_resources_csp() { - function background() { - browser.runtime.onMessage.addListener((msg, sender) => { - if (msg.name === "image-loading") { - browser.test.assertTrue(msg.success, `Image was ${msg.expectedAction}`); - browser.test.sendMessage(`image-${msg.expectedAction}`); - } else { - browser.test.sendMessage(msg); - } - }); - - browser.test.sendMessage("background-ready"); - } - - function content() { - window.addEventListener("message", function rcv(event) { - browser.runtime.sendMessage("script-ran"); - window.removeEventListener("message", rcv, false); - }, false); - - testImageLoading(browser.extension.getURL("image.png"), "loaded"); - - let testScriptElement = document.createElement("script"); - testScriptElement.setAttribute("src", browser.extension.getURL("test_script.js")); - document.head.appendChild(testScriptElement); - browser.runtime.sendMessage("script-loaded"); - } - - function testScript() { - window.postMessage("test-script-loaded", "*"); - } - - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - "content_scripts": [{ - "matches": ["http://example.com/*/file_csp.html"], - "run_at": "document_start", - "js": ["content_script_helper.js", "content_script.js"], - }], - "web_accessible_resources": [ - "image.png", - "test_script.js", - ], - }, - background, - files: { - "content_script_helper.js": `${testImageLoading}`, - "content_script.js": content, - "test_script.js": testScript, - "image.png": IMAGE_ARRAYBUFFER, - }, - }); - - // This is used to watch the blocked data bounce off CSP. - function examiner() { - SpecialPowers.addObserver(this, "csp-on-violate-policy", false); - } - - let cspEventCount = 0; - - examiner.prototype = { - observe: function(subject, topic, data) { - cspEventCount++; - let spec = SpecialPowers.wrap(subject).QueryInterface(SpecialPowers.Ci.nsIURI).spec; - ok(spec.includes("file_image_bad.png") || spec.includes("file_script_bad.js"), - `Expected file: ${spec} rejected by CSP`); - }, - - // We must eventually call this to remove the listener, - // or mochitests might get borked. - remove: function() { - SpecialPowers.removeObserver(this, "csp-on-violate-policy"); - }, - }; - - let observer = new examiner(); - - yield Promise.all([extension.startup(), extension.awaitMessage("background-ready")]); - - let win = window.open("http://example.com/tests/toolkit/components/extensions/test/mochitest/file_csp.html"); - - yield Promise.all([ - extension.awaitMessage("image-loaded"), - extension.awaitMessage("script-loaded"), - extension.awaitMessage("script-ran"), - ]); - is(cspEventCount, 2, "Two items were rejected by CSP"); - win.close(); - - observer.remove(); - yield extension.unload(); -}); - -add_task(function* test_web_accessible_resources_mixed_content() { - function background() { - browser.runtime.onMessage.addListener(msg => { - if (msg.name === "image-loading") { - browser.test.assertTrue(msg.success, `Image was ${msg.expectedAction}`); - browser.test.sendMessage(`image-${msg.expectedAction}`); - } else { - browser.test.sendMessage(msg); - if (msg === "accessible-script-loaded") { - browser.test.notifyPass("mixed-test"); - } - } - }); - - browser.test.sendMessage("background-ready"); - } - - function content() { - testImageLoading("http://example.com/tests/toolkit/components/extensions/test/mochitest/file_image_bad.png", "blocked"); - testImageLoading(browser.extension.getURL("image.png"), "loaded"); - - let testScriptElement = document.createElement("script"); - testScriptElement.setAttribute("src", browser.extension.getURL("test_script.js")); - document.head.appendChild(testScriptElement); - - window.addEventListener("message", event => { - browser.runtime.sendMessage(event.data); - }); - } - - function testScript() { - window.postMessage("accessible-script-loaded", "*"); - } - - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - "content_scripts": [{ - "matches": ["https://example.com/*/file_mixed.html"], - "run_at": "document_start", - "js": ["content_script_helper.js", "content_script.js"], - }], - "web_accessible_resources": [ - "image.png", - "test_script.js", - ], - }, - background, - files: { - "content_script_helper.js": `${testImageLoading}`, - "content_script.js": content, - "test_script.js": testScript, - "image.png": IMAGE_ARRAYBUFFER, - }, - }); - - SpecialPowers.setBoolPref("security.mixed_content.block_display_content", true); - - yield Promise.all([extension.startup(), extension.awaitMessage("background-ready")]); - - let win = window.open("https://example.com/tests/toolkit/components/extensions/test/mochitest/file_mixed.html"); - - yield Promise.all([ - extension.awaitMessage("image-blocked"), - extension.awaitMessage("image-loaded"), - extension.awaitMessage("accessible-script-loaded"), - ]); - yield extension.awaitFinish("mixed-test"); - win.close(); - - yield extension.unload(); -}); - -</script> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_webnavigation.html b/toolkit/components/webextensions/test/mochitest/test_ext_webnavigation.html deleted file mode 100644 index 2287fd9b1..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_webnavigation.html +++ /dev/null @@ -1,559 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test for simple WebExtension</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="/tests/SimpleTest/EventUtils.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"; - -/* globals sendMouseEvent */ - -function backgroundScript() { - const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest"; - const URL = BASE + "/file_WebNavigation_page1.html"; - - const EVENTS = [ - "onTabReplaced", - "onBeforeNavigate", - "onCommitted", - "onDOMContentLoaded", - "onCompleted", - "onErrorOccurred", - "onReferenceFragmentUpdated", - "onHistoryStateUpdated", - ]; - - let expectedTabId = -1; - - function gotEvent(event, details) { - if (!details.url.startsWith(BASE)) { - return; - } - browser.test.log(`Got ${event} ${details.url} ${details.frameId} ${details.parentFrameId}`); - - if (expectedTabId == -1) { - browser.test.assertTrue(details.tabId !== undefined, "tab ID defined"); - expectedTabId = details.tabId; - } - - browser.test.assertEq(details.tabId, expectedTabId, "correct tab"); - - browser.test.sendMessage("received", {url: details.url, event}); - - if (details.url == URL) { - browser.test.assertEq(details.frameId, 0, "root frame ID correct"); - browser.test.assertEq(details.parentFrameId, -1, "root parent frame ID correct"); - } else { - browser.test.assertEq(details.parentFrameId, 0, "parent frame ID correct"); - browser.test.assertTrue(details.frameId != 0, "frame ID probably okay"); - } - - browser.test.assertTrue(details.frameId !== undefined); - browser.test.assertTrue(details.parentFrameId !== undefined); - } - - let listeners = {}; - for (let event of EVENTS) { - listeners[event] = gotEvent.bind(null, event); - browser.webNavigation[event].addListener(listeners[event]); - } - - browser.test.sendMessage("ready"); -} - -const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest"; -const URL = BASE + "/file_WebNavigation_page1.html"; -const FRAME = BASE + "/file_WebNavigation_page2.html"; -const FRAME2 = BASE + "/file_WebNavigation_page3.html"; -const FRAME_PUSHSTATE = BASE + "/file_WebNavigation_page3_pushState.html"; -const REDIRECT = BASE + "/redirection.sjs"; -const REDIRECTED = BASE + "/dummy_page.html"; -const CLIENT_REDIRECT = BASE + "/file_webNavigation_clientRedirect.html"; -const CLIENT_REDIRECT_HTTPHEADER = BASE + "/file_webNavigation_clientRedirect_httpHeaders.html"; -const FRAME_CLIENT_REDIRECT = BASE + "/file_webNavigation_frameClientRedirect.html"; -const FRAME_REDIRECT = BASE + "/file_webNavigation_frameRedirect.html"; -const FRAME_MANUAL = BASE + "/file_webNavigation_manualSubframe.html"; -const FRAME_MANUAL_PAGE1 = BASE + "/file_webNavigation_manualSubframe_page1.html"; -const FRAME_MANUAL_PAGE2 = BASE + "/file_webNavigation_manualSubframe_page2.html"; -const INVALID_PAGE = "https://invalid.localhost/"; - -const REQUIRED = [ - "onBeforeNavigate", - "onCommitted", - "onDOMContentLoaded", - "onCompleted", -]; - -var received = []; -var completedResolve; -var waitingURL, waitingEvent; - -function loadAndWait(win, event, url, script) { - received = []; - waitingEvent = event; - waitingURL = url; - dump(`RUN ${script}\n`); - script(); - return new Promise(resolve => { completedResolve = resolve; }); -} - -add_task(function* webnav_transitions_props() { - function backgroundScriptTransitions() { - const EVENTS = [ - "onCommitted", - "onCompleted", - ]; - - function gotEvent(event, details) { - browser.test.log(`Got ${event} ${details.url} ${details.transitionType} ${details.transitionQualifiers && JSON.stringify(details.transitionQualifiers)}`); - - browser.test.sendMessage("received", {url: details.url, details, event}); - } - - let listeners = {}; - for (let event of EVENTS) { - listeners[event] = gotEvent.bind(null, event); - browser.webNavigation[event].addListener(listeners[event]); - } - - browser.test.sendMessage("ready"); - } - - let extensionData = { - manifest: { - permissions: [ - "webNavigation", - ], - }, - background: backgroundScriptTransitions, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - - extension.onMessage("received", ({url, event, details}) => { - received.push({url, event, details}); - - if (event == waitingEvent && url == waitingURL) { - completedResolve(); - } - }); - - yield Promise.all([extension.startup(), extension.awaitMessage("ready")]); - info("webnavigation extension loaded"); - - let win = window.open(); - - yield loadAndWait(win, "onCompleted", URL, () => { win.location = URL; }); - - // transitionType: reload - received = []; - yield loadAndWait(win, "onCompleted", URL, () => { win.location.reload(); }); - - let found = received.find((data) => (data.event == "onCommitted" && data.url == URL)); - - ok(found, "Got the onCommitted event"); - - if (found) { - is(found.details.transitionType, "reload", - "Got the expected 'reload' transitionType in the OnCommitted event"); - ok(Array.isArray(found.details.transitionQualifiers), - "transitionQualifiers found in the OnCommitted events"); - } - - // transitionType: auto_subframe - found = received.find((data) => (data.event == "onCommitted" && data.url == FRAME)); - - ok(found, "Got the sub-frame onCommitted event"); - - if (found) { - is(found.details.transitionType, "auto_subframe", - "Got the expected 'auto_subframe' transitionType in the OnCommitted event"); - ok(Array.isArray(found.details.transitionQualifiers), - "transitionQualifiers found in the OnCommitted events"); - } - - // transitionType: form_submit - received = []; - yield loadAndWait(win, "onCompleted", URL, () => { - win.document.querySelector("form").submit(); - }); - - found = received.find((data) => (data.event == "onCommitted" && data.url == URL)); - - ok(found, "Got the onCommitted event"); - - if (found) { - is(found.details.transitionType, "form_submit", - "Got the expected 'form_submit' transitionType in the OnCommitted event"); - ok(Array.isArray(found.details.transitionQualifiers), - "transitionQualifiers found in the OnCommitted events"); - } - - // transitionQualifier: server_redirect - received = []; - yield loadAndWait(win, "onCompleted", REDIRECTED, () => { win.location = REDIRECT; }); - - found = received.find((data) => (data.event == "onCommitted" && data.url == REDIRECTED)); - - ok(found, "Got the onCommitted event"); - - if (found) { - is(found.details.transitionType, "link", - "Got the expected 'link' transitionType in the OnCommitted event"); - ok(Array.isArray(found.details.transitionQualifiers) && - found.details.transitionQualifiers.find((q) => q == "server_redirect"), - "Got the expected 'server_redirect' transitionQualifiers in the OnCommitted events"); - } - - // transitionQualifier: forward_back - received = []; - yield loadAndWait(win, "onCompleted", URL, () => { win.history.back(); }); - - found = received.find((data) => (data.event == "onCommitted" && data.url == URL)); - - ok(found, "Got the onCommitted event"); - - if (found) { - is(found.details.transitionType, "link", - "Got the expected 'link' transitionType in the OnCommitted event"); - ok(Array.isArray(found.details.transitionQualifiers) && - found.details.transitionQualifiers.find((q) => q == "forward_back"), - "Got the expected 'forward_back' transitionQualifiers in the OnCommitted events"); - } - - // transitionQualifier: client_redirect - // (from meta http-equiv tag) - received = []; - yield loadAndWait(win, "onCompleted", REDIRECTED, () => { - win.location = CLIENT_REDIRECT; - }); - - found = received.find((data) => (data.event == "onCommitted" && data.url == REDIRECTED)); - - ok(found, "Got the onCommitted event"); - - if (found) { - is(found.details.transitionType, "link", - "Got the expected 'link' transitionType in the OnCommitted event"); - ok(Array.isArray(found.details.transitionQualifiers) && - found.details.transitionQualifiers.find((q) => q == "client_redirect"), - "Got the expected 'client_redirect' transitionQualifiers in the OnCommitted events"); - } - - // transitionQualifier: client_redirect - // (from http headers) - received = []; - yield loadAndWait(win, "onCompleted", REDIRECTED, () => { - win.location = CLIENT_REDIRECT_HTTPHEADER; - }); - - found = received.find((data) => (data.event == "onCommitted" && - data.url == CLIENT_REDIRECT_HTTPHEADER)); - - ok(found, "Got the onCommitted event"); - - if (found) { - is(found.details.transitionType, "link", - "Got the expected 'link' transitionType in the OnCommitted event"); - ok(Array.isArray(found.details.transitionQualifiers) && - found.details.transitionQualifiers.find((q) => q == "client_redirect"), - "Got the expected 'client_redirect' transitionQualifiers in the OnCommitted events"); - } - - // transitionQualifier: client_redirect (sub-frame) - // (from meta http-equiv tag) - received = []; - yield loadAndWait(win, "onCompleted", REDIRECTED, () => { - win.location = FRAME_CLIENT_REDIRECT; - }); - - found = received.find((data) => (data.event == "onCommitted" && data.url == REDIRECTED)); - - ok(found, "Got the onCommitted event"); - - if (found) { - is(found.details.transitionType, "auto_subframe", - "Got the expected 'auto_subframe' transitionType in the OnCommitted event"); - ok(Array.isArray(found.details.transitionQualifiers) && - found.details.transitionQualifiers.find((q) => q == "client_redirect"), - "Got the expected 'client_redirect' transitionQualifiers in the OnCommitted events"); - } - - // transitionQualifier: server_redirect (sub-frame) - received = []; - yield loadAndWait(win, "onCompleted", REDIRECTED, () => { win.location = FRAME_REDIRECT; }); - - found = received.find((data) => (data.event == "onCommitted" && data.url == REDIRECT)); - - ok(found, "Got the onCommitted event"); - - if (found) { - is(found.details.transitionType, "auto_subframe", - "Got the expected 'auto_subframe' transitionType in the OnCommitted event"); - // BUG 1264936: currently the server_redirect is not detected in sub-frames - // once we fix it we can test it here: - // - // ok(Array.isArray(found.details.transitionQualifiers) && - // found.details.transitionQualifiers.find((q) => q == "server_redirect"), - // "Got the expected 'server_redirect' transitionQualifiers in the OnCommitted events"); - } - - // transitionType: manual_subframe - received = []; - yield loadAndWait(win, "onCompleted", FRAME_MANUAL, () => { win.location = FRAME_MANUAL; }); - found = received.find((data) => (data.event == "onCommitted" && - data.url == FRAME_MANUAL_PAGE1)); - - ok(found, "Got the onCommitted event"); - - if (found) { - is(found.details.transitionType, "auto_subframe", - "Got the expected 'auto_subframe' transitionType in the OnCommitted event"); - } - - received = []; - yield loadAndWait(win, "onCompleted", FRAME_MANUAL_PAGE2, () => { - let el = win.document.querySelector("iframe") - .contentDocument.querySelector("a"); - sendMouseEvent({type: "click"}, el, win); - }); - - found = received.find((data) => (data.event == "onCommitted" && - data.url == FRAME_MANUAL_PAGE2)); - - ok(found, "Got the onCommitted event"); - - if (found) { - is(found.details.transitionType, "manual_subframe", - "Got the expected 'manual_subframe' transitionType in the OnCommitted event"); - } - - // cleanup phase - win.close(); - - yield extension.unload(); - info("webnavigation extension unloaded"); -}); - -add_task(function* webnav_ordering() { - let extensionData = { - manifest: { - permissions: [ - "webNavigation", - ], - }, - background: backgroundScript, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - - extension.onMessage("received", ({url, event}) => { - received.push({url, event}); - - if (event == waitingEvent && url == waitingURL) { - completedResolve(); - } - }); - - yield extension.startup(); - yield extension.awaitMessage("ready"); - info("webnavigation extension loaded"); - - let win = window.open(); - - yield loadAndWait(win, "onCompleted", URL, () => { win.location = URL; }); - - function checkRequired(url) { - for (let event of REQUIRED) { - let found = false; - for (let r of received) { - if (r.url == url && r.event == event) { - found = true; - } - } - ok(found, `Received event ${event} from ${url}`); - } - } - - checkRequired(URL); - checkRequired(FRAME); - - function checkBefore(action1, action2) { - function find(action) { - for (let i = 0; i < received.length; i++) { - if (received[i].url == action.url && received[i].event == action.event) { - return i; - } - } - return -1; - } - - let index1 = find(action1); - let index2 = find(action2); - ok(index1 != -1, `Action ${JSON.stringify(action1)} happened`); - ok(index2 != -1, `Action ${JSON.stringify(action2)} happened`); - ok(index1 < index2, `Action ${JSON.stringify(action1)} happened before ${JSON.stringify(action2)}`); - } - - // As required in the webNavigation API documentation: - // If a navigating frame contains subframes, its onCommitted is fired before any - // of its children's onBeforeNavigate; while onCompleted is fired after - // all of its children's onCompleted. - checkBefore({url: URL, event: "onCommitted"}, {url: FRAME, event: "onBeforeNavigate"}); - checkBefore({url: FRAME, event: "onCompleted"}, {url: URL, event: "onCompleted"}); - - // As required in the webNAvigation API documentation, check the event sequence: - // onBeforeNavigate -> onCommitted -> onDOMContentLoaded -> onCompleted - let expectedEventSequence = [ - "onBeforeNavigate", "onCommitted", "onDOMContentLoaded", "onCompleted", - ]; - - for (let i = 1; i < expectedEventSequence.length; i++) { - let after = expectedEventSequence[i]; - let before = expectedEventSequence[i - 1]; - checkBefore({url: URL, event: before}, {url: URL, event: after}); - checkBefore({url: FRAME, event: before}, {url: FRAME, event: after}); - } - - yield loadAndWait(win, "onCompleted", FRAME2, () => { win.frames[0].location = FRAME2; }); - - checkRequired(FRAME2); - - let navigationSequence = [ - { - action: () => { win.frames[0].document.getElementById("elt").click(); }, - waitURL: `${FRAME2}#ref`, - expectedEvent: "onReferenceFragmentUpdated", - description: "clicked an anchor link", - }, - { - action: () => { win.frames[0].history.pushState({}, "History PushState", `${FRAME2}#ref2`); }, - waitURL: `${FRAME2}#ref2`, - expectedEvent: "onReferenceFragmentUpdated", - description: "history.pushState, same pathname, different hash", - }, - { - action: () => { win.frames[0].history.pushState({}, "History PushState", `${FRAME2}#ref2`); }, - waitURL: `${FRAME2}#ref2`, - expectedEvent: "onHistoryStateUpdated", - description: "history.pushState, same pathname, same hash", - }, - { - action: () => { - win.frames[0].history.pushState({}, "History PushState", `${FRAME2}?query_param1=value#ref2`); - }, - waitURL: `${FRAME2}?query_param1=value#ref2`, - expectedEvent: "onHistoryStateUpdated", - description: "history.pushState, same pathname, same hash, different query params", - }, - { - action: () => { - win.frames[0].history.pushState({}, "History PushState", `${FRAME2}?query_param2=value#ref3`); - }, - waitURL: `${FRAME2}?query_param2=value#ref3`, - expectedEvent: "onHistoryStateUpdated", - description: "history.pushState, same pathname, different hash, different query params", - }, - { - action: () => { win.frames[0].history.pushState(null, "History PushState", FRAME_PUSHSTATE); }, - waitURL: FRAME_PUSHSTATE, - expectedEvent: "onHistoryStateUpdated", - description: "history.pushState, different pathname", - }, - ]; - - for (let navigation of navigationSequence) { - let {expectedEvent, waitURL, action, description} = navigation; - info(`Waiting ${expectedEvent} from ${waitURL} - ${description}`); - yield loadAndWait(win, expectedEvent, waitURL, action); - info(`Received ${expectedEvent} from ${waitURL} - ${description}`); - } - - for (let i = navigationSequence.length - 1; i > 0; i--) { - let {waitURL: fromURL, expectedEvent} = navigationSequence[i]; - let {waitURL} = navigationSequence[i - 1]; - info(`Waiting ${expectedEvent} from ${waitURL} - history.back() from ${fromURL} to ${waitURL}`); - yield loadAndWait(win, expectedEvent, waitURL, () => { win.frames[0].history.back(); }); - info(`Received ${expectedEvent} from ${waitURL} - history.back() from ${fromURL} to ${waitURL}`); - } - - for (let i = 0; i < navigationSequence.length - 1; i++) { - let {waitURL: fromURL} = navigationSequence[i]; - let {waitURL, expectedEvent} = navigationSequence[i + 1]; - info(`Waiting ${expectedEvent} from ${waitURL} - history.forward() from ${fromURL} to ${waitURL}`); - yield loadAndWait(win, expectedEvent, waitURL, () => { win.frames[0].history.forward(); }); - info(`Received ${expectedEvent} from ${waitURL} - history.forward() from ${fromURL} to ${waitURL}`); - } - - win.close(); - - yield extension.unload(); - info("webnavigation extension unloaded"); -}); - -add_task(function* webnav_error_event() { - function backgroundScriptErrorEvent() { - browser.webNavigation.onErrorOccurred.addListener((details) => { - browser.test.log(`Got onErrorOccurred ${details.url} ${details.error}`); - - browser.test.sendMessage("received", {url: details.url, details, event: "onErrorOccurred"}); - }); - - browser.test.sendMessage("ready"); - } - - let extensionData = { - manifest: { - permissions: [ - "webNavigation", - ], - }, - background: backgroundScriptErrorEvent, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - - extension.onMessage("received", ({url, event, details}) => { - received.push({url, event, details}); - - if (event == waitingEvent && url == waitingURL) { - completedResolve(); - } - }); - - yield Promise.all([extension.startup(), extension.awaitMessage("ready")]); - info("webnavigation extension loaded"); - - let win = window.open(); - - received = []; - yield loadAndWait(win, "onErrorOccurred", INVALID_PAGE, () => { win.location = INVALID_PAGE; }); - - let found = received.find((data) => (data.event == "onErrorOccurred" && - data.url == INVALID_PAGE)); - - ok(found, "Got the onErrorOccurred event"); - - if (found) { - ok(found.details.error.match(/Error code [0-9]+/), - "Got the expected error string in the onErrorOccurred event"); - } - - // cleanup phase - win.close(); - - yield extension.unload(); - info("webnavigation extension unloaded"); -}); -</script> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_webnavigation_filters.html b/toolkit/components/webextensions/test/mochitest/test_ext_webnavigation_filters.html deleted file mode 100644 index a0de5e9e5..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_webnavigation_filters.html +++ /dev/null @@ -1,308 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test for simple WebExtension</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_webnav_unresolved_uri_on_expected_URI_scheme() { - function background() { - let lastTest; - - function cleanupTestListeners() { - if (lastTest) { - let {event, okListener, failListener} = lastTest; - lastTest = null; - browser.test.log(`Cleanup previous test event listeners`); - browser.webNavigation[event].removeListener(okListener); - browser.webNavigation[event].removeListener(failListener); - } - } - - function createTestListener(event, fail, urlFilter) { - function listener(details) { - let log = JSON.stringify({url: details.url, urlFilter}); - if (fail) { - browser.test.fail(`Got an unexpected ${event} on the failure listener: ${log}`); - } else { - browser.test.succeed(`Got the expected ${event} on the success listener: ${log}`); - } - - cleanupTestListeners(); - browser.test.sendMessage("test-filter-next"); - } - - browser.webNavigation[event].addListener(listener, urlFilter); - - return listener; - } - - browser.test.onMessage.addListener((msg, event, okFilter, failFilter) => { - if (msg !== "test-filter") { - return; - } - - lastTest = { - event, - // Register the failListener first, which should not be called - // and if it is called the test scenario is marked as a failure. - failListener: createTestListener(event, true, failFilter), - okListener: createTestListener(event, false, okFilter), - }; - - browser.test.sendMessage("test-filter-ready"); - }); - - browser.test.sendMessage("ready"); - } - - let extensionData = { - manifest: { - permissions: [ - "webNavigation", - ], - }, - background, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - - yield extension.startup(); - - yield extension.awaitMessage("ready"); - - let win = window.open(); - - let testFilterScenarios = [ - { - url: "http://example.net/browser", - filters: [ - // schemes - { - okFilter: [{schemes: ["http"]}], - failFilter: [{schemes: ["https"]}], - }, - // ports - { - okFilter: [{ports: [80, 22, 443]}], - failFilter: [{ports: [81, 82, 83]}], - }, - { - okFilter: [{ports: [22, 443, [10, 80]]}], - failFilter: [{ports: [22, 23, [81, 100]]}], - }, - ], - }, - { - url: "http://example.net/browser?param=1#ref", - filters: [ - // host: Equals, Contains, Prefix, Suffix - { - okFilter: [{hostEquals: "example.net"}], - failFilter: [{hostEquals: "example.com"}], - }, - { - okFilter: [{hostContains: ".example"}], - failFilter: [{hostContains: ".www"}], - }, - { - okFilter: [{hostPrefix: "example"}], - failFilter: [{hostPrefix: "www"}], - }, - { - okFilter: [{hostSuffix: "net"}], - failFilter: [{hostSuffix: "com"}], - }, - // path: Equals, Contains, Prefix, Suffix - { - okFilter: [{pathEquals: "/browser"}], - failFilter: [{pathEquals: "/"}], - }, - { - okFilter: [{pathContains: "brow"}], - failFilter: [{pathContains: "tool"}], - }, - { - okFilter: [{pathPrefix: "/bro"}], - failFilter: [{pathPrefix: "/tool"}], - }, - { - okFilter: [{pathSuffix: "wser"}], - failFilter: [{pathSuffix: "kit"}], - }, - // query: Equals, Contains, Prefix, Suffix - { - okFilter: [{queryEquals: "param=1"}], - failFilter: [{queryEquals: "wrongparam=2"}], - }, - { - okFilter: [{queryContains: "param"}], - failFilter: [{queryContains: "wrongparam"}], - }, - { - okFilter: [{queryPrefix: "param="}], - failFilter: [{queryPrefix: "wrong"}], - }, - { - okFilter: [{querySuffix: "=1"}], - failFilter: [{querySuffix: "=2"}], - }, - // urlMatches, originAndPathMatches - { - okFilter: [{urlMatches: "example.net/.*\?param=1"}], - failFilter: [{urlMatches: "example.net/.*\?wrongparam=2"}], - }, - { - okFilter: [{originAndPathMatches: "example.net\/browser"}], - failFilter: [{originAndPathMatches: "example.net/.*\?param=1"}], - }, - ], - }, - { - url: "http://example.net/browser", - filters: [ - // multiple criteria in a single filter: - // if one of the critera is not verified, the event should not be received. - { - okFilter: [{schemes: ["http"], ports: [80, 22, 443]}], - failFilter: [{schemes: ["http"], ports: [81, 82, 83]}], - }, - // multiple urlFilters on the same listener - // if at least one of the critera is verified, the event should be received. - { - okFilter: [{schemes: ["https"]}, {ports: [80, 22, 443]}], - failFilter: [{schemes: ["https"]}, {ports: [81, 82, 83]}], - }, - ], - }, - ]; - - function* runTestScenario(event, {url, filters}) { - for (let testFilters of filters) { - let {okFilter, failFilter} = testFilters; - - info(`Prepare the new test scenario: ${event} ${url} ${JSON.stringify(testFilters)}`); - win.location = "about:blank"; - - extension.sendMessage("test-filter", event, {url: okFilter}, {url: failFilter}); - yield extension.awaitMessage("test-filter-ready"); - - info(`Loading the test url: ${url}`); - win.location = url; - - yield extension.awaitMessage("test-filter-next"); - - info("Test scenario completed. Moving to the next test scenario."); - } - } - - const BASE_WEBNAV_EVENTS = [ - "onBeforeNavigate", - "onCommitted", - "onDOMContentLoaded", - "onCompleted", - ]; - - info("WebNavigation event filters test scenarios starting..."); - - for (let filterScenario of testFilterScenarios) { - for (let event of BASE_WEBNAV_EVENTS) { - yield runTestScenario(event, filterScenario); - } - } - - info("WebNavigation event filters test onReferenceFragmentUpdated scenario starting..."); - - const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest"; - let url = BASE + "/file_WebNavigation_page3.html"; - - let okFilter = [{urlContains: "_page3.html"}]; - let failFilter = [{ports: [444]}]; - let event = "onCompleted"; - - info(`Loading the initial test url: ${url}`); - extension.sendMessage("test-filter", event, {url: okFilter}, {url: failFilter}); - - yield extension.awaitMessage("test-filter-ready"); - win.location = url; - yield extension.awaitMessage("test-filter-next"); - - event = "onReferenceFragmentUpdated"; - extension.sendMessage("test-filter", event, {url: okFilter}, {url: failFilter}); - - yield extension.awaitMessage("test-filter-ready"); - win.location = url + "#ref1"; - yield extension.awaitMessage("test-filter-next"); - - info("WebNavigation event filters test onHistoryStateUpdated scenario starting..."); - - event = "onHistoryStateUpdated"; - extension.sendMessage("test-filter", event, {url: okFilter}, {url: failFilter}); - yield extension.awaitMessage("test-filter-ready"); - - win.history.pushState({}, "", BASE + "/pushState_page3.html"); - yield extension.awaitMessage("test-filter-next"); - - // TODO: add additional specific tests for the other webNavigation events: - // onErrorOccurred (and onCreatedNavigationTarget on supported) - - info("WebNavigation event filters test scenarios completed."); - - yield extension.unload(); - - win.close(); -}); - -add_task(function* test_webnav_empty_filter_validation_error() { - function background() { - let catchedException; - - try { - browser.webNavigation.onCompleted.addListener( - // Empty callback (not really used) - () => {}, - // Empty filter (which should raise a validation error exception). - {url: []} - ); - } catch (e) { - catchedException = e; - browser.test.log(`Got an exception`); - } - - if (catchedException && - catchedException.message.includes("Type error for parameter filters") && - catchedException.message.includes("Array requires at least 1 items; you have 0")) { - browser.test.notifyPass("webNav.emptyFilterValidationError"); - } else { - browser.test.notifyFail("webNav.emptyFilterValidationError"); - } - } - - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - permissions: [ - "webNavigation", - ], - }, - background, - }); - - yield extension.startup(); - - yield extension.awaitFinish("webNav.emptyFilterValidationError"); - - yield extension.unload(); -}); - -</script> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_background_events.html b/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_background_events.html deleted file mode 100644 index 78efeab35..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_background_events.html +++ /dev/null @@ -1,116 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test for simple WebExtension</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_webRequest_serviceworker_events() { - yield SpecialPowers.pushPrefEnv({ - set: [["dom.serviceWorkers.testing.enabled", true], - ["dom.serviceWorkers.enabled", true], - ["dom.serviceWorkers.openWindow.enabled", true], - ], - }); - - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - permissions: [ - "webRequest", - "<all_urls>", - ], - }, - background() { - let eventNames = new Set([ - "onBeforeRequest", - "onBeforeSendHeaders", - "onSendHeaders", - "onHeadersReceived", - "onResponseStarted", - "onCompleted", - ]); - - function listener(name, details) { - browser.test.assertTrue(eventNames.has(name), `recieved ${name}`); - eventNames.delete(name); - if (eventNames.size == 0) { - browser.test.sendMessage("done"); - } - } - - for (let name of eventNames) { - browser.webRequest[name].addListener( - listener.bind(null, name), - {urls: ["https://example.com/*"]} - ); - } - }, - }); - - yield extension.startup(); - let registration = yield navigator.serviceWorker.register("webrequest_worker.js", {scope: "."}); - yield extension.awaitMessage("done"); - yield registration.unregister(); - yield extension.unload(); -}); - -add_task(function* test_webRequest_background_events() { - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - permissions: [ - "webRequest", - "<all_urls>", - ], - }, - background() { - let eventNames = new Set([ - "onBeforeRequest", - "onBeforeSendHeaders", - "onSendHeaders", - "onHeadersReceived", - "onResponseStarted", - "onCompleted", - ]); - - function listener(name, details) { - browser.test.assertTrue(eventNames.has(name), `recieved ${name}`); - eventNames.delete(name); - - if (eventNames.size === 0) { - browser.test.assertEq(0, eventNames.size, "messages recieved"); - browser.test.sendMessage("done"); - } - } - - for (let name of eventNames) { - browser.webRequest[name].addListener( - listener.bind(null, name), - {urls: ["https://example.com/*"]} - ); - } - - fetch("https://example.com/example.txt").then(() => { - browser.test.pass("Fetch succeeded."); - }, () => { - browser.test.fail("fetch recieved"); - browser.test.sendMessage("done"); - }); - }, - }); - - yield extension.startup(); - yield extension.awaitMessage("done"); - yield extension.unload(); -}); -</script> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_basic.html b/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_basic.html deleted file mode 100644 index ef77fee3b..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_basic.html +++ /dev/null @@ -1,327 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<head> -<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> - <script type="text/javascript" src="head_webrequest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> -<script> -"use strict"; - -let extension; -add_task(function* setup() { - // SelfSupport has a tendency to fire when running this test alone, without - // a good way to turn it off we just set the url to "" - yield SpecialPowers.pushPrefEnv({ - set: [["browser.selfsupport.url", ""]], - }); - - // Clear the image cache, since it gets in the way otherwise. - let imgTools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService(SpecialPowers.Ci.imgITools); - let cache = imgTools.getImgCacheForDocument(document); - cache.clearCache(false); - - extension = makeExtension(); - yield extension.startup(); -}); - -// expect is a set of test values used by the background script. -// -// type: type of request action -// events: optional, If defined only the events listed are expected for the -// request. If undefined, all events except onErrorOccurred -// and onBeforeRedirect are expected. Must be in order received. -// redirect: url to redirect to during onBeforeSendHeaders -// status: number expected status during onHeadersReceived, 200 default -// cancel: event in which we return cancel=true. cancelled message is sent. -// cached: expected fromCache value, default is false, checked in onCompletion -// headers: request or response headers to modify - -add_task(function* test_webRequest_links() { - let expect = { - "file_style_bad.css": { - type: "stylesheet", - events: ["onBeforeRequest", "onErrorOccurred"], - cancel: "onBeforeRequest", - }, - "file_style_redirect.css": { - type: "stylesheet", - events: ["onBeforeRequest", "onBeforeSendHeaders", "onBeforeRedirect"], - optional_events: ["onHeadersReceived"], - redirect: "file_style_good.css", - }, - "file_style_good.css": { - type: "stylesheet", - }, - }; - extension.sendMessage("set-expected", {expect, origin: location.href}); - yield extension.awaitMessage("continue"); - addStylesheet("file_style_bad.css"); - yield extension.awaitMessage("cancelled"); - // we redirect to style_good which completes the test - addStylesheet("file_style_redirect.css"); - yield extension.awaitMessage("done"); - - let style = window.getComputedStyle(document.getElementById("test"), null); - is(style.getPropertyValue("color"), "rgb(255, 0, 0)", "Good CSS loaded"); -}); - -add_task(function* test_webRequest_images() { - let expect = { - "file_image_bad.png": { - type: "image", - events: ["onBeforeRequest", "onErrorOccurred"], - cancel: "onBeforeRequest", - }, - "file_image_redirect.png": { - type: "image", - events: ["onBeforeRequest", "onBeforeSendHeaders", "onBeforeRedirect"], - optional_events: ["onHeadersReceived"], - redirect: "file_image_good.png", - }, - "file_image_good.png": { - type: "image", - }, - }; - extension.sendMessage("set-expected", {expect, origin: location.href}); - yield extension.awaitMessage("continue"); - addImage("file_image_bad.png"); - yield extension.awaitMessage("cancelled"); - // we redirect to image_good which completes the test - addImage("file_image_redirect.png"); - yield extension.awaitMessage("done"); -}); - -add_task(function* test_webRequest_scripts() { - let expect = { - "file_script_bad.js": { - type: "script", - events: ["onBeforeRequest", "onErrorOccurred"], - cancel: "onBeforeRequest", - }, - "file_script_redirect.js": { - type: "script", - events: ["onBeforeRequest", "onBeforeSendHeaders", "onBeforeRedirect"], - optional_events: ["onHeadersReceived"], - redirect: "file_script_good.js", - }, - "file_script_good.js": { - type: "script", - }, - }; - extension.sendMessage("set-expected", {expect, origin: location.href}); - yield extension.awaitMessage("continue"); - addScript("file_script_bad.js"); - yield extension.awaitMessage("cancelled"); - // we redirect to script_good which completes the test - addScript("file_script_redirect.js"); - yield extension.awaitMessage("done"); - - is(window.success, 1, "Good script ran"); - is(window.failure, undefined, "Failure script didn't run"); -}); - -add_task(function* test_webRequest_xhr_get() { - let expect = { - "file_script_xhr.js": { - type: "script", - }, - "xhr_resource": { - status: 404, - type: "xmlhttprequest", - }, - }; - extension.sendMessage("set-expected", {expect, origin: location.href}); - yield extension.awaitMessage("continue"); - addScript("file_script_xhr.js"); - yield extension.awaitMessage("done"); -}); - -add_task(function* test_webRequest_nonexistent() { - let expect = { - "nonexistent_script_url.js": { - status: 404, - type: "script", - }, - }; - extension.sendMessage("set-expected", {expect, origin: location.href}); - yield extension.awaitMessage("continue"); - addScript("nonexistent_script_url.js"); - yield extension.awaitMessage("done"); -}); - -add_task(function* test_webRequest_checkCached() { - let expect = { - "file_image_good.png": { - type: "image", - cached: true, - }, - "file_script_good.js": { - type: "script", - cached: true, - }, - "file_style_good.css": { - type: "stylesheet", - cached: true, - }, - "nonexistent_script_url.js": { - status: 404, - type: "script", - cached: false, - }, - }; - extension.sendMessage("set-expected", {expect, origin: location.href}); - yield extension.awaitMessage("continue"); - addImage("file_image_good.png"); - addScript("file_script_good.js"); - addStylesheet("file_style_good.css"); - addScript("nonexistent_script_url.js"); - yield extension.awaitMessage("done"); - - is(window.success, 2, "Good script ran"); - is(window.failure, undefined, "Failure script didn't run"); -}); - -add_task(function* test_webRequest_headers() { - let expect = { - "file_script_nonexistent.js": { - type: "script", - status: 404, - headers: { - request: { - add: { - "X-WebRequest-request": "text", - "X-WebRequest-request-binary": "binary", - }, - modify: { - "user-agent": "WebRequest", - }, - remove: [ - "referer", - ], - }, - response: { - add: { - "X-WebRequest-response": "text", - "X-WebRequest-response-binary": "binary", - }, - modify: { - "server": "WebRequest", - "content-type": "text/html; charset=utf-8", - }, - remove: [ - "connection", - ], - }, - }, - completion: "onCompleted", - }, - }; - extension.sendMessage("set-expected", {expect, origin: location.href}); - yield extension.awaitMessage("continue"); - addScript("file_script_nonexistent.js"); - yield extension.awaitMessage("done"); -}); - -add_task(function* test_webRequest_tabId() { - let expect = { - "file_WebRequest_page3.html": { - type: "main_frame", - }, - }; - extension.sendMessage("set-expected", {expect, origin: location.href}); - yield extension.awaitMessage("continue"); - let a = addLink("file_WebRequest_page3.html?trigger=a"); - a.click(); - yield extension.awaitMessage("done"); -}); - -add_task(function* test_webRequest_tabId_browser() { - async function background(url) { - let tabId; - browser.test.onMessage.addListener(async (msg, expected) => { - await browser.tabs.remove(tabId); - browser.test.sendMessage("done"); - }); - - let tab = await browser.tabs.create({url}); - tabId = tab.id; - } - - let tabExt = ExtensionTestUtils.loadExtension({ - manifest: { - permissions: [ - "tabs", - ], - }, - background: `(${background})('${SimpleTest.getTestFileURL("file_sample.html")}?nocache=${Math.random()}')`, - }); - - let expect = { - "file_sample.html": { - type: "main_frame", - }, - }; - // expecting origin == undefined - extension.sendMessage("set-expected", {expect}); - yield extension.awaitMessage("continue"); - - // open a tab from a system principal - yield tabExt.startup(); - - yield extension.awaitMessage("done"); - tabExt.sendMessage("done"); - yield tabExt.awaitMessage("done"); - yield tabExt.unload(); -}); - -add_task(function* test_webRequest_frames() { - let expect = { - "text/plain,webRequestTest": { - type: "sub_frame", - events: ["onBeforeRequest", "onCompleted"], - }, - "text/plain,webRequestTest_bad": { - type: "sub_frame", - events: ["onBeforeRequest", "onCompleted"], - cancel: "onBeforeRequest", - }, - "redirection.sjs": { - status: 302, - type: "sub_frame", - events: ["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders", "onHeadersReceived", "onBeforeRedirect"], - }, - "dummy_page.html": { - type: "sub_frame", - status: 404, - }, - "badrobot": { - type: "sub_frame", - status: 404, - events: ["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders", "onErrorOccurred"], - }, - }; - extension.sendMessage("set-expected", {expect, origin: location.href}); - yield extension.awaitMessage("continue"); - addFrame("data:text/plain,webRequestTest"); - addFrame("data:text/plain,webRequestTest_bad"); - yield extension.awaitMessage("cancelled"); - addFrame("redirection.sjs"); - addFrame("https://invalid.localhost/badrobot"); - yield extension.awaitMessage("done"); -}); - -add_task(function* teardown() { - yield extension.unload(); -}); -</script> -</head> -<body> -<div id="test">Sample text</div> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_suspend.html b/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_suspend.html deleted file mode 100644 index c8423ec7c..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_suspend.html +++ /dev/null @@ -1,216 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test for simple WebExtension</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_suspend() { - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - permissions: [ - "webRequest", - "webRequestBlocking", - ], - }, - - background() { - browser.webRequest.onBeforeSendHeaders.addListener( - details => { - // Make sure that returning undefined or a promise that resolves to - // undefined does not break later handlers. - }, - {urls: ["<all_urls>"]}, - ["blocking", "requestHeaders"]); - - browser.webRequest.onBeforeSendHeaders.addListener( - details => { - return Promise.resolve(); - }, - {urls: ["<all_urls>"]}, - ["blocking", "requestHeaders"]); - - browser.webRequest.onBeforeSendHeaders.addListener( - details => { - let requestHeaders = details.requestHeaders.concat({name: "Foo", value: "Bar"}); - - return new Promise(resolve => { - setTimeout(resolve, 500); - }).then(() => { - return {requestHeaders}; - }); - }, - {urls: ["<all_urls>"]}, - ["blocking", "requestHeaders"]); - }, - }); - - yield extension.startup(); - - let result = yield fetch(SimpleTest.getTestFileURL("return_headers.sjs")); - - let headers = JSON.parse(yield result.text()); - - is(headers.foo, "Bar", "Request header was correctly set on suspended request"); - - yield extension.unload(); -}); - - -// Test that requests that were canceled while suspended for a blocking -// listener are correctly resumed. -add_task(function* test_error_resume() { - let chromeScript = SpecialPowers.loadChromeScript(() => { - const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - Cu.import("resource://gre/modules/Services.jsm"); - - let observer = channel => { - if (channel instanceof Ci.nsIHttpChannel && channel.URI.spec === "http://example.com/") { - Services.obs.removeObserver(observer, "http-on-modify-request"); - - // Wait until the next tick to make sure this runs after WebRequest observers. - Promise.resolve().then(() => { - channel.cancel(Cr.NS_BINDING_ABORTED); - }); - } - }; - - Services.obs.addObserver(observer, "http-on-modify-request", false); - }); - - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - permissions: [ - "webRequest", - "webRequestBlocking", - ], - }, - - background() { - browser.webRequest.onBeforeSendHeaders.addListener( - details => { - browser.test.log(`onBeforeSendHeaders({url: ${details.url}})`); - - if (details.url === "http://example.com/") { - browser.test.sendMessage("got-before-send-headers"); - } - }, - {urls: ["<all_urls>"]}, - ["blocking"]); - - browser.webRequest.onErrorOccurred.addListener( - details => { - browser.test.log(`onErrorOccurred({url: ${details.url}})`); - - if (details.url === "http://example.com/") { - browser.test.sendMessage("got-error-occurred"); - } - }, - {urls: ["<all_urls>"]}); - }, - }); - - yield extension.startup(); - - try { - yield fetch("http://example.com/"); - ok(false, "Fetch should have failed."); - } catch (e) { - ok(true, "Got expected error."); - } - - yield extension.awaitMessage("got-before-send-headers"); - yield extension.awaitMessage("got-error-occurred"); - - yield extension.unload(); - chromeScript.destroy(); -}); - - -// Test that response header modifications take effect before onStartRequest fires. -add_task(function* test_set_responseHeaders() { - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - permissions: [ - "webRequest", - "webRequestBlocking", - "http://example.com/", - ], - }, - - background() { - browser.webRequest.onHeadersReceived.addListener( - details => { - browser.test.log(`onHeadersReceived({url: ${details.url}})`); - - details.responseHeaders.push({name: "foo", value: "bar"}); - - return {responseHeaders: details.responseHeaders}; - }, - {urls: ["http://example.com/?modify_headers"]}, - ["blocking", "responseHeaders"]); - }, - }); - - yield extension.startup(); - - yield new Promise(resolve => setTimeout(resolve, 0)); - - let chromeScript = SpecialPowers.loadChromeScript(() => { - const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - - Cu.import("resource://gre/modules/NetUtil.jsm"); - Cu.import("resource://gre/modules/Services.jsm"); - Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - - let ssm = Services.scriptSecurityManager; - - let channel = NetUtil.newChannel({ - uri: "http://example.com/?modify_headers", - loadingPrincipal: ssm.createCodebasePrincipalFromOrigin("http://example.com"), - contentPolicyType: Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST, - securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, - }); - - channel.asyncOpen2({ - QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener]), - - onStartRequest(request, context) { - request.QueryInterface(Ci.nsIHttpChannel); - - try { - sendAsyncMessage("response-header-foo", request.getResponseHeader("foo")); - } catch (e) { - sendAsyncMessage("response-header-foo", null); - } - request.cancel(Cr.NS_BINDING_ABORTED); - }, - - onStopRequest() { - }, - - onDataAvailable() { - throw new Components.Exception("", Cr.NS_ERROR_FAILURE); - }, - }); - }); - - let headerValue = yield chromeScript.promiseOneMessage("response-header-foo"); - is(headerValue, "bar", "Expected Foo header value"); - - yield extension.unload(); - chromeScript.destroy(); -}); - - -</script> -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_upload.html b/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_upload.html deleted file mode 100644 index 998ab9800..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_webrequest_upload.html +++ /dev/null @@ -1,199 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<head> -<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> - -<form method="post" - action="file_WebRequest_page3.html?trigger=form" - target="_blank" - enctype="multipart/form-data" - > -<input type="text" name=""special" chˆrs" value="spÛcial"> -<input type="file" name="testFile"> -<input type="file" name="emptyFile"> -<input type="text" name="textInput1" value="value1"> -</form> - -<form method="post" - action="file_WebRequest_page3.html?trigger=form" - target="_blank" - enctype="multipart/form-data" - > -<input type="text" name="textInput2" value="value2"> -<input type="file" name="testFile"> -<input type="file" name="emptyFile"> -</form> - -</form> -<form method="post" - action="file_WebRequest_page3.html?trigger=form" - target="_blank" - > -<input type="text" name="textInput" value="value1"> -<input type="text" name="textInput" value="value2"> -</form> -<script> -"use strict"; - -let files, testFile, blob, file, uploads; -add_task(function* test_setup() { - files = yield new Promise(resolve => { - SpecialPowers.createFiles([{name: "testFile.pdf", data: "Not really a PDF file :)", "type": "application/x-pdf"}], (result) => { - resolve(result); - }); - }); - testFile = files[0]; - blob = { - name: "blobAsFile", - content: new Blob(["A blob sent as a file"], {type: "text/csv"}), - fileName: "blobAsFile.csv", - }; - file = { - name: "testFile", - fileName: testFile.name, - }; - uploads = { - [blob.name]: blob, - [file.name]: file, - }; -}); - -function background() { - const FILTERS = {urls: ["<all_urls>"]}; - - let requestBodySupported = true; - - function onUpload(details) { - let url = new URL(details.url); - let upload = url.searchParams.get("upload"); - if (!upload || !requestBodySupported) { - return; - } - let requestBody = details.requestBody; - browser.test.log(`onBeforeRequest upload: ${details.url} ${JSON.stringify(details.requestBody)}`); - browser.test.assertTrue(!!requestBody, `Intercepted upload ${details.url} #${details.requestId} ${upload} have a requestBody`); - if (!requestBody) { - return; - } - let byteLength = parseInt(upload, 10); - if (byteLength) { - browser.test.assertTrue(!!requestBody.raw, `Binary upload ${details.url} #${details.requestId} ${upload} have a raw attribute`); - browser.test.assertEq(byteLength, requestBody.raw && requestBody.raw.map(r => r.bytes && r.bytes.byteLength || 0).reduce((a, b) => a + b), `Binary upload size matches`); - return; - } - if ("raw" in requestBody) { - browser.test.assertEq(upload, JSON.stringify(requestBody.raw).replace(/(\bfile: ")[^"]+/, "$1<file>"), `Upload ${details.url} #${details.requestId} matches raw data`); - } else { - browser.test.assertEq(upload, JSON.stringify(requestBody.formData), `Upload ${details.url} #${details.requestId} matches form data.`); - } - } - - browser.webRequest.onCompleted.addListener( - details => { - browser.test.log(`onCompleted ${details.requestId} ${details.url}`); - - browser.test.sendMessage("done"); - }, - FILTERS); - - let onBeforeRequest = details => { - browser.test.log(`${name} ${details.requestId} ${details.url}`); - - onUpload(details); - }; - - try { - browser.webRequest.onBeforeRequest.addListener( - onBeforeRequest, FILTERS, ["requestBody"]); - } 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; - } - - browser.webRequest.onBeforeRequest.addListener( - onBeforeRequest, FILTERS); - } -} - -add_task(function* test_xhr_forms() { - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - permissions: [ - "webRequest", - "webRequestBlocking", - "<all_urls>", - ], - }, - background, - }); - - yield extension.startup(); - - for (let form of document.forms) { - if (file.name in form.elements) { - SpecialPowers.wrap(form.elements[file.name]).mozSetFileArray(files); - } - let action = new URL(form.action); - let formData = new FormData(form); - let webRequestFD = {}; - - let updateActionURL = () => { - for (let name of formData.keys()) { - webRequestFD[name] = name in uploads ? [uploads[name].fileName] : formData.getAll(name); - } - action.searchParams.set("upload", JSON.stringify(webRequestFD)); - action.searchParams.set("enctype", form.enctype); - }; - - updateActionURL(); - - form.action = action; - form.submit(); - yield extension.awaitMessage("done"); - - if (form.enctype !== "multipart/form-data") { - continue; - } - - let post = (data) => { - let xhr = new XMLHttpRequest(); - action.searchParams.set("xhr", "1"); - xhr.open("POST", action.href); - xhr.send(data); - action.searchParams.delete("xhr"); - return extension.awaitMessage("done"); - }; - - formData.append(blob.name, blob.content, blob.fileName); - formData.append("formDataField", "some value"); - updateActionURL(); - yield post(formData); - - action.searchParams.set("upload", JSON.stringify([{file: "<file>"}])); - yield post(testFile); - - action.searchParams.set("upload", `${blob.content.size} bytes`); - yield post(blob.content); - - let byteLength = 16; - action.searchParams.set("upload", `${byteLength} bytes`); - yield post(new ArrayBuffer(byteLength)); - } - - yield extension.unload(); -}); -</script> -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_window_postMessage.html b/toolkit/components/webextensions/test/mochitest/test_ext_window_postMessage.html deleted file mode 100644 index 7d49d55ba..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_window_postMessage.html +++ /dev/null @@ -1,105 +0,0 @@ -<!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"; - -/* eslint-disable mozilla/balanced-listeners */ - -add_task(function* test_postMessage() { - let extensionData = { - manifest: { - content_scripts: [ - { - "matches": ["http://mochi.test/*/file_sample.html"], - "js": ["content_script.js"], - "run_at": "document_start", - "all_frames": true, - }, - ], - - web_accessible_resources: ["iframe.html"], - }, - - background() { - browser.test.sendMessage("iframe-url", browser.runtime.getURL("iframe.html")); - }, - - files: { - "content_script.js": function() { - window.addEventListener("message", event => { - if (event.data == "ping") { - event.source.postMessage({pong: location.href}, - event.origin); - } - }); - }, - - "iframe.html": `<!DOCTYPE html> - <html> - <head> - <meta charset="utf-8"> - <script src="content_script.js"><\/script> - </head> - </html>`, - }, - }; - - let createIframe = url => { - let iframe = document.createElement("iframe"); - return new Promise(resolve => { - iframe.src = url; - iframe.onload = resolve; - document.body.appendChild(iframe); - }).then(() => { - return iframe; - }); - }; - - let awaitMessage = () => { - return new Promise(resolve => { - let listener = event => { - if (event.data.pong) { - window.removeEventListener("message", listener); - resolve(event.data); - } - }; - window.addEventListener("message", listener); - }); - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - - let iframeURL = yield extension.awaitMessage("iframe-url"); - let testURL = SimpleTest.getTestFileURL("file_sample.html"); - - for (let url of [iframeURL, testURL]) { - info(`Testing URL ${url}`); - - let iframe = yield createIframe(url); - - iframe.contentWindow.postMessage( - "ping", url); - - let pong = yield awaitMessage(); - is(pong.pong, url, "Got expected pong"); - - iframe.remove(); - } - - yield extension.unload(); -}); -</script> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/test_ext_xhr_capabilities.html b/toolkit/components/webextensions/test/mochitest/test_ext_xhr_capabilities.html deleted file mode 100644 index 1afdadb9f..000000000 --- a/toolkit/components/webextensions/test/mochitest/test_ext_xhr_capabilities.html +++ /dev/null @@ -1,86 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test XHR capabilities</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_xhr_capabilities() { - function backgroundScript() { - let xhr = new XMLHttpRequest(); - xhr.open("GET", browser.extension.getURL("bad.xml")); - - browser.test.sendMessage("result", - {name: "Background script XHRs should not be privileged", - result: xhr.channel === undefined}); - - xhr.onload = () => { - browser.test.sendMessage("result", - {name: "Background script XHRs should not yield <parsererrors>", - result: xhr.responseXML === null}); - }; - xhr.send(); - } - - function contentScript() { - let xhr = new XMLHttpRequest(); - xhr.open("GET", browser.extension.getURL("bad.xml")); - - browser.test.sendMessage("result", - {name: "Content script XHRs should not be privileged", - result: xhr.channel === undefined}); - - xhr.onload = () => { - browser.test.sendMessage("result", - {name: "Content script XHRs should not yield <parsererrors>", - result: xhr.responseXML === null}); - }; - xhr.send(); - } - - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - background: { - "scripts": ["background.js"], - }, - content_scripts: [{ - "matches": ["http://example.com/"], - "js": ["content_script.js"], - }], - web_accessible_resources: [ - "bad.xml", - ], - }, - - files: { - "bad.xml": "<xml", - "background.js": `(${backgroundScript})()`, - "content_script.js": `(${contentScript})()`, - }, - }); - - yield extension.startup(); - - let win = window.open("http://example.com/"); - - // We expect four test results from the content/background scripts. - for (let i = 0; i < 4; ++i) { - let result = yield extension.awaitMessage("result"); - ok(result.result, result.name); - } - - win.close(); - yield extension.unload(); -}); -</script> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/mochitest/webrequest_chromeworker.js b/toolkit/components/webextensions/test/mochitest/webrequest_chromeworker.js deleted file mode 100644 index ccfb2ac1f..000000000 --- a/toolkit/components/webextensions/test/mochitest/webrequest_chromeworker.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; - -onmessage = function(event) { - fetch("https://example.com/example.txt").then(() => { - postMessage("Done!"); - }); -}; - diff --git a/toolkit/components/webextensions/test/mochitest/webrequest_test.jsm b/toolkit/components/webextensions/test/mochitest/webrequest_test.jsm deleted file mode 100644 index bfb148301..000000000 --- a/toolkit/components/webextensions/test/mochitest/webrequest_test.jsm +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; - -this.EXPORTED_SYMBOLS = ["webrequest_test"]; - -Components.utils.importGlobalProperties(["fetch", "XMLHttpRequest"]); - -this.webrequest_test = { - testFetch(url) { - return fetch(url); - }, - - testXHR(url) { - return new Promise(resolve => { - let xhr = new XMLHttpRequest(); - xhr.open("HEAD", url); - xhr.onload = () => { - resolve(); - }; - xhr.send(); - }); - }, -}; diff --git a/toolkit/components/webextensions/test/mochitest/webrequest_worker.js b/toolkit/components/webextensions/test/mochitest/webrequest_worker.js deleted file mode 100644 index dcffd0857..000000000 --- a/toolkit/components/webextensions/test/mochitest/webrequest_worker.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict"; - -fetch("https://example.com/example.txt"); diff --git a/toolkit/components/webextensions/test/xpcshell/.eslintrc.js b/toolkit/components/webextensions/test/xpcshell/.eslintrc.js deleted file mode 100644 index 3758537ef..000000000 --- a/toolkit/components/webextensions/test/xpcshell/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; - -module.exports = { // eslint-disable-line no-undef - "extends": "../../../../../testing/xpcshell/xpcshell.eslintrc.js", - - "globals": { - "browser": false, - }, -}; diff --git a/toolkit/components/webextensions/test/xpcshell/data/file_download.html b/toolkit/components/webextensions/test/xpcshell/data/file_download.html deleted file mode 100644 index d970c6325..000000000 --- a/toolkit/components/webextensions/test/xpcshell/data/file_download.html +++ /dev/null @@ -1,12 +0,0 @@ -<!DOCTYPE HTML> - -<html> -<head> -<meta charset="utf-8"> -</head> -<body> - -<div>Download HTML File</div> - -</body> -</html> diff --git a/toolkit/components/webextensions/test/xpcshell/data/file_download.txt b/toolkit/components/webextensions/test/xpcshell/data/file_download.txt deleted file mode 100644 index 6293c7af7..000000000 --- a/toolkit/components/webextensions/test/xpcshell/data/file_download.txt +++ /dev/null @@ -1 +0,0 @@ -This is a sample file used in download tests. diff --git a/toolkit/components/webextensions/test/xpcshell/head.js b/toolkit/components/webextensions/test/xpcshell/head.js deleted file mode 100644 index 9e22be6da..000000000 --- a/toolkit/components/webextensions/test/xpcshell/head.js +++ /dev/null @@ -1,111 +0,0 @@ -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -/* exported createHttpServer, promiseConsoleOutput, cleanupDir */ - -Components.utils.import("resource://gre/modules/Task.jsm"); -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/Timer.jsm"); -Components.utils.import("resource://testing-common/AddonTestUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "AppConstants", - "resource://gre/modules/AppConstants.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Extension", - "resource://gre/modules/Extension.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData", - "resource://gre/modules/Extension.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement", - "resource://gre/modules/ExtensionManagement.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils", - "resource://testing-common/ExtensionXPCShellUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", - "resource://gre/modules/FileUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "HttpServer", - "resource://testing-common/httpd.js"); -XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", - "resource://gre/modules/NetUtil.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Schemas", - "resource://gre/modules/Schemas.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Services", - "resource://gre/modules/Services.jsm"); - -ExtensionTestUtils.init(this); - -/** - * Creates a new HttpServer for testing, and begins listening on the - * specified port. Automatically shuts down the server when the test - * unit ends. - * - * @param {integer} [port] - * The port to listen on. If omitted, listen on a random - * port. The latter is the preferred behavior. - * - * @returns {HttpServer} - */ -function createHttpServer(port = -1) { - let server = new HttpServer(); - server.start(port); - - do_register_cleanup(() => { - return new Promise(resolve => { - server.stop(resolve); - }); - }); - - return server; -} - -var promiseConsoleOutput = Task.async(function* (task) { - const DONE = `=== console listener ${Math.random()} done ===`; - - let listener; - let messages = []; - let awaitListener = new Promise(resolve => { - listener = msg => { - if (msg == DONE) { - resolve(); - } else { - void (msg instanceof Ci.nsIConsoleMessage); - messages.push(msg); - } - }; - }); - - Services.console.registerListener(listener); - try { - let result = yield task(); - - Services.console.logStringMessage(DONE); - yield awaitListener; - - return {messages, result}; - } finally { - Services.console.unregisterListener(listener); - } -}); - -// Attempt to remove a directory. If the Windows OS is still using the -// file sometimes remove() will fail. So try repeatedly until we can -// remove it or we give up. -function cleanupDir(dir) { - let count = 0; - return new Promise((resolve, reject) => { - function tryToRemoveDir() { - count += 1; - try { - dir.remove(true); - } catch (e) { - // ignore - } - if (!dir.exists()) { - return resolve(); - } - if (count >= 25) { - return reject(`Failed to cleanup directory: ${dir}`); - } - setTimeout(tryToRemoveDir, 100); - } - tryToRemoveDir(); - }); -} diff --git a/toolkit/components/webextensions/test/xpcshell/head_native_messaging.js b/toolkit/components/webextensions/test/xpcshell/head_native_messaging.js deleted file mode 100644 index f7c619b76..000000000 --- a/toolkit/components/webextensions/test/xpcshell/head_native_messaging.js +++ /dev/null @@ -1,131 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -/* globals AppConstants, FileUtils */ -/* exported getSubprocessCount, setupHosts, waitForSubprocessExit */ - -XPCOMUtils.defineLazyModuleGetter(this, "MockRegistry", - "resource://testing-common/MockRegistry.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "OS", - "resource://gre/modules/osfile.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "setTimeout", - "resource://gre/modules/Timer.jsm"); - -let {Subprocess, SubprocessImpl} = Cu.import("resource://gre/modules/Subprocess.jsm"); - - -// It's important that we use a space in this directory name to make sure we -// correctly handle executing batch files with spaces in their path. -let tmpDir = FileUtils.getDir("TmpD", ["Native Messaging"]); -tmpDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - -do_register_cleanup(() => { - tmpDir.remove(true); -}); - -function getPath(filename) { - return OS.Path.join(tmpDir.path, filename); -} - -const ID = "native@tests.mozilla.org"; - - -function* setupHosts(scripts) { - const PERMS = {unixMode: 0o755}; - - const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - const pythonPath = yield Subprocess.pathSearch(env.get("PYTHON")); - - function* writeManifest(script, scriptPath, path) { - let body = `#!${pythonPath} -u\n${script.script}`; - - yield OS.File.writeAtomic(scriptPath, body); - yield OS.File.setPermissions(scriptPath, PERMS); - - let manifest = { - name: script.name, - description: script.description, - path, - type: "stdio", - allowed_extensions: [ID], - }; - - let manifestPath = getPath(`${script.name}.json`); - yield OS.File.writeAtomic(manifestPath, JSON.stringify(manifest)); - - return manifestPath; - } - - switch (AppConstants.platform) { - case "macosx": - case "linux": - let dirProvider = { - getFile(property) { - if (property == "XREUserNativeMessaging") { - return tmpDir.clone(); - } else if (property == "XRESysNativeMessaging") { - return tmpDir.clone(); - } - return null; - }, - }; - - Services.dirsvc.registerProvider(dirProvider); - do_register_cleanup(() => { - Services.dirsvc.unregisterProvider(dirProvider); - }); - - for (let script of scripts) { - let path = getPath(`${script.name}.py`); - - yield writeManifest(script, path, path); - } - break; - - case "win": - const REGKEY = String.raw`Software\Mozilla\NativeMessagingHosts`; - - let registry = new MockRegistry(); - do_register_cleanup(() => { - registry.shutdown(); - }); - - for (let script of scripts) { - // It's important that we use a space in this filename. See directory - // name comment above. - let batPath = getPath(`batch ${script.name}.bat`); - let scriptPath = getPath(`${script.name}.py`); - - let batBody = `@ECHO OFF\n${pythonPath} -u "${scriptPath}" %*\n`; - yield OS.File.writeAtomic(batPath, batBody); - - // Create absolute and relative path versions of the entry. - for (let [name, path] of [[script.name, batPath], - [`relative.${script.name}`, OS.Path.basename(batPath)]]) { - script.name = name; - let manifestPath = yield writeManifest(script, scriptPath, path); - - registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, - `${REGKEY}\\${script.name}`, "", manifestPath); - } - } - break; - - default: - ok(false, `Native messaging is not supported on ${AppConstants.platform}`); - } -} - - -function getSubprocessCount() { - return SubprocessImpl.Process.getWorker().call("getProcesses", []) - .then(result => result.size); -} -function waitForSubprocessExit() { - return SubprocessImpl.Process.getWorker().call("waitForNoProcesses", []).then(() => { - // Return to the main event loop to give IO handlers enough time to consume - // their remaining buffered input. - return new Promise(resolve => setTimeout(resolve, 0)); - }); -} diff --git a/toolkit/components/webextensions/test/xpcshell/head_sync.js b/toolkit/components/webextensions/test/xpcshell/head_sync.js deleted file mode 100644 index 9b66b78e7..000000000 --- a/toolkit/components/webextensions/test/xpcshell/head_sync.js +++ /dev/null @@ -1,67 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -/* exported withSyncContext */ - -Components.utils.import("resource://gre/modules/Services.jsm", this); -Components.utils.import("resource://gre/modules/ExtensionCommon.jsm", this); - -var { - BaseContext, -} = ExtensionCommon; - -class Context extends BaseContext { - constructor(principal) { - super(); - Object.defineProperty(this, "principal", { - value: principal, - configurable: true, - }); - this.sandbox = Components.utils.Sandbox(principal, {wantXrays: false}); - this.extension = {id: "test@web.extension"}; - } - - get cloneScope() { - return this.sandbox; - } -} - -/** - * Call the given function with a newly-constructed context. - * Unload the context on the way out. - * - * @param {function} f the function to call - */ -function* withContext(f) { - const ssm = Services.scriptSecurityManager; - const PRINCIPAL1 = ssm.createCodebasePrincipalFromOrigin("http://www.example.org"); - const context = new Context(PRINCIPAL1); - try { - yield* f(context); - } finally { - yield context.unload(); - } -} - -/** - * Like withContext(), but also turn on the "storage.sync" pref for - * the duration of the function. - * Calls to this function can be replaced with calls to withContext - * once the pref becomes on by default. - * - * @param {function} f the function to call - */ -function* withSyncContext(f) { - const STORAGE_SYNC_PREF = "webextensions.storage.sync.enabled"; - let prefs = Services.prefs; - - try { - prefs.setBoolPref(STORAGE_SYNC_PREF, true); - yield* withContext(f); - } finally { - prefs.clearUserPref(STORAGE_SYNC_PREF); - } -} diff --git a/toolkit/components/webextensions/test/xpcshell/native_messaging.ini b/toolkit/components/webextensions/test/xpcshell/native_messaging.ini deleted file mode 100644 index d0e1da163..000000000 --- a/toolkit/components/webextensions/test/xpcshell/native_messaging.ini +++ /dev/null @@ -1,13 +0,0 @@ -[DEFAULT] -head = head.js head_native_messaging.js -tail = -firefox-appdir = browser -skip-if = appname == "thunderbird" || os == "android" -subprocess = true -support-files = - data/** -tags = webextensions - -[test_ext_native_messaging.js] -[test_ext_native_messaging_perf.js] -[test_ext_native_messaging_unresponsive.js] diff --git a/toolkit/components/webextensions/test/xpcshell/test_csp_custom_policies.js b/toolkit/components/webextensions/test/xpcshell/test_csp_custom_policies.js deleted file mode 100644 index b6213baac..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_csp_custom_policies.js +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -Cu.import("resource://gre/modules/Preferences.jsm"); - -const ADDON_ID = "test@web.extension"; - -const aps = Cc["@mozilla.org/addons/policy-service;1"] - .getService(Ci.nsIAddonPolicyService).wrappedJSObject; - -do_register_cleanup(() => { - aps.setAddonCSP(ADDON_ID, null); -}); - -add_task(function* test_addon_csp() { - equal(aps.baseCSP, Preferences.get("extensions.webextensions.base-content-security-policy"), - "Expected base CSP value"); - - equal(aps.defaultCSP, Preferences.get("extensions.webextensions.default-content-security-policy"), - "Expected default CSP value"); - - equal(aps.getAddonCSP(ADDON_ID), aps.defaultCSP, - "CSP for unknown add-on ID should be the default CSP"); - - - const CUSTOM_POLICY = "script-src: 'self' https://xpcshell.test.custom.csp; object-src: 'none'"; - - aps.setAddonCSP(ADDON_ID, CUSTOM_POLICY); - - equal(aps.getAddonCSP(ADDON_ID), CUSTOM_POLICY, "CSP should point to add-on's custom policy"); - - - aps.setAddonCSP(ADDON_ID, null); - - equal(aps.getAddonCSP(ADDON_ID), aps.defaultCSP, - "CSP should revert to default when set to null"); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_csp_validator.js b/toolkit/components/webextensions/test/xpcshell/test_csp_validator.js deleted file mode 100644 index 59a7322bc..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_csp_validator.js +++ /dev/null @@ -1,85 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -const cps = Cc["@mozilla.org/addons/content-policy;1"].getService(Ci.nsIAddonContentPolicy); - -add_task(function* test_csp_validator() { - let checkPolicy = (policy, expectedResult, message = null) => { - do_print(`Checking policy: ${policy}`); - - let result = cps.validateAddonCSP(policy); - equal(result, expectedResult); - }; - - checkPolicy("script-src 'self'; object-src 'self';", - null); - - let hash = "'sha256-NjZhMDQ1YjQ1MjEwMmM1OWQ4NDBlYzA5N2Q1OWQ5NDY3ZTEzYTNmMzRmNjQ5NGU1MzlmZmQzMmMxYmIzNWYxOCAgLQo='"; - - checkPolicy(`script-src 'self' https://com https://*.example.com moz-extension://09abcdef blob: filesystem: ${hash} 'unsafe-eval'; ` + - `object-src 'self' https://com https://*.example.com moz-extension://09abcdef blob: filesystem: ${hash}`, - null); - - checkPolicy("", - "Policy is missing a required \u2018script-src\u2019 directive"); - - checkPolicy("object-src 'none';", - "Policy is missing a required \u2018script-src\u2019 directive"); - - - checkPolicy("default-src 'self'", null, - "A valid default-src should count as a valid script-src or object-src"); - - checkPolicy("default-src 'self'; script-src 'self'", null, - "A valid default-src should count as a valid script-src or object-src"); - - checkPolicy("default-src 'self'; object-src 'self'", null, - "A valid default-src should count as a valid script-src or object-src"); - - - checkPolicy("default-src 'self'; script-src http://example.com", - "\u2018script-src\u2019 directive contains a forbidden http: protocol source", - "A valid default-src should not allow an invalid script-src directive"); - - checkPolicy("default-src 'self'; object-src http://example.com", - "\u2018object-src\u2019 directive contains a forbidden http: protocol source", - "A valid default-src should not allow an invalid object-src directive"); - - - checkPolicy("script-src 'self';", - "Policy is missing a required \u2018object-src\u2019 directive"); - - checkPolicy("script-src 'none'; object-src 'none'", - "\u2018script-src\u2019 must include the source 'self'"); - - checkPolicy("script-src 'self'; object-src 'none';", - null); - - checkPolicy("script-src 'self' 'unsafe-inline'; object-src 'self';", - "\u2018script-src\u2019 directive contains a forbidden 'unsafe-inline' keyword"); - - - let directives = ["script-src", "object-src"]; - - for (let [directive, other] of [directives, directives.slice().reverse()]) { - for (let src of ["https://*", "https://*.blogspot.com", "https://*"]) { - checkPolicy(`${directive} 'self' ${src}; ${other} 'self';`, - `https: wildcard sources in \u2018${directive}\u2019 directives must include at least one non-generic sub-domain (e.g., *.example.com rather than *.com)`); - } - - checkPolicy(`${directive} 'self' https:; ${other} 'self';`, - `https: protocol requires a host in \u2018${directive}\u2019 directives`); - - checkPolicy(`${directive} 'self' http://example.com; ${other} 'self';`, - `\u2018${directive}\u2019 directive contains a forbidden http: protocol source`); - - for (let protocol of ["http", "ftp", "meh"]) { - checkPolicy(`${directive} 'self' ${protocol}:; ${other} 'self';`, - `\u2018${directive}\u2019 directive contains a forbidden ${protocol}: protocol source`); - } - - checkPolicy(`${directive} 'self' 'nonce-01234'; ${other} 'self';`, - `\u2018${directive}\u2019 directive contains a forbidden 'nonce-*' keyword`); - } -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_alarms.js b/toolkit/components/webextensions/test/xpcshell/test_ext_alarms.js deleted file mode 100644 index 936c984c6..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_alarms.js +++ /dev/null @@ -1,210 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_alarm_without_permissions() { - function backgroundScript() { - browser.test.assertTrue(!browser.alarms, - "alarm API is not available when the alarm permission is not required"); - browser.test.notifyPass("alarms_permission"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: [], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarms_permission"); - yield extension.unload(); -}); - - -add_task(function* test_alarm_fires() { - function backgroundScript() { - let ALARM_NAME = "test_ext_alarms"; - let timer; - - browser.alarms.onAlarm.addListener(alarm => { - browser.test.assertEq(ALARM_NAME, alarm.name, "alarm has the correct name"); - clearTimeout(timer); - browser.test.notifyPass("alarm-fires"); - }); - - browser.alarms.create(ALARM_NAME, {delayInMinutes: 0.02}); - - timer = setTimeout(async () => { - browser.test.fail("alarm fired within expected time"); - let wasCleared = await browser.alarms.clear(ALARM_NAME); - browser.test.assertTrue(wasCleared, "alarm was cleared"); - browser.test.notifyFail("alarm-fires"); - }, 10000); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarm-fires"); - yield extension.unload(); -}); - - -add_task(function* test_alarm_fires_with_when() { - function backgroundScript() { - let ALARM_NAME = "test_ext_alarms"; - let timer; - - browser.alarms.onAlarm.addListener(alarm => { - browser.test.assertEq(ALARM_NAME, alarm.name, "alarm has the expected name"); - clearTimeout(timer); - browser.test.notifyPass("alarm-when"); - }); - - browser.alarms.create(ALARM_NAME, {when: Date.now() + 1000}); - - timer = setTimeout(async () => { - browser.test.fail("alarm fired within expected time"); - let wasCleared = await browser.alarms.clear(ALARM_NAME); - browser.test.assertTrue(wasCleared, "alarm was cleared"); - browser.test.notifyFail("alarm-when"); - }, 10000); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarm-when"); - yield extension.unload(); -}); - - -add_task(function* test_alarm_clear_non_matching_name() { - async function backgroundScript() { - let ALARM_NAME = "test_ext_alarms"; - - browser.alarms.create(ALARM_NAME, {when: Date.now() + 2000}); - - let wasCleared = await browser.alarms.clear(ALARM_NAME + "1"); - browser.test.assertFalse(wasCleared, "alarm was not cleared"); - - let alarms = await browser.alarms.getAll(); - browser.test.assertEq(1, alarms.length, "alarm was not removed"); - browser.test.notifyPass("alarm-clear"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarm-clear"); - yield extension.unload(); -}); - - -add_task(function* test_alarm_get_and_clear_single_argument() { - async function backgroundScript() { - browser.alarms.create({when: Date.now() + 2000}); - - let alarm = await browser.alarms.get(); - browser.test.assertEq("", alarm.name, "expected alarm returned"); - - let wasCleared = await browser.alarms.clear(); - browser.test.assertTrue(wasCleared, "alarm was cleared"); - - let alarms = await browser.alarms.getAll(); - browser.test.assertEq(0, alarms.length, "alarm was removed"); - - browser.test.notifyPass("alarm-single-arg"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarm-single-arg"); - yield extension.unload(); -}); - - -add_task(function* test_get_get_all_clear_all_alarms() { - async function backgroundScript() { - const ALARM_NAME = "test_alarm"; - - let suffixes = [0, 1, 2]; - - for (let suffix of suffixes) { - browser.alarms.create(ALARM_NAME + suffix, {when: Date.now() + (suffix + 1) * 10000}); - } - - let alarms = await browser.alarms.getAll(); - browser.test.assertEq(suffixes.length, alarms.length, "expected number of alarms were found"); - alarms.forEach((alarm, index) => { - browser.test.assertEq(ALARM_NAME + index, alarm.name, "alarm has the expected name"); - }); - - - for (let suffix of suffixes) { - let alarm = await browser.alarms.get(ALARM_NAME + suffix); - browser.test.assertEq(ALARM_NAME + suffix, alarm.name, "alarm has the expected name"); - browser.test.sendMessage(`get-${suffix}`); - } - - let wasCleared = await browser.alarms.clear(ALARM_NAME + suffixes[0]); - browser.test.assertTrue(wasCleared, "alarm was cleared"); - - alarms = await browser.alarms.getAll(); - browser.test.assertEq(2, alarms.length, "alarm was removed"); - - let alarm = await browser.alarms.get(ALARM_NAME + suffixes[0]); - browser.test.assertEq(undefined, alarm, "non-existent alarm is undefined"); - browser.test.sendMessage(`get-invalid`); - - wasCleared = await browser.alarms.clearAll(); - browser.test.assertTrue(wasCleared, "alarms were cleared"); - - alarms = await browser.alarms.getAll(); - browser.test.assertEq(0, alarms.length, "no alarms exist"); - browser.test.sendMessage("clearAll"); - browser.test.sendMessage("clear"); - browser.test.sendMessage("getAll"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield Promise.all([ - extension.startup(), - extension.awaitMessage("getAll"), - extension.awaitMessage("get-0"), - extension.awaitMessage("get-1"), - extension.awaitMessage("get-2"), - extension.awaitMessage("clear"), - extension.awaitMessage("get-invalid"), - extension.awaitMessage("clearAll"), - ]); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_alarms_does_not_fire.js b/toolkit/components/webextensions/test/xpcshell/test_ext_alarms_does_not_fire.js deleted file mode 100644 index 11407b108..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_alarms_does_not_fire.js +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_cleared_alarm_does_not_fire() { - async function backgroundScript() { - let ALARM_NAME = "test_ext_alarms"; - - browser.alarms.onAlarm.addListener(alarm => { - browser.test.fail("cleared alarm does not fire"); - browser.test.notifyFail("alarm-cleared"); - }); - browser.alarms.create(ALARM_NAME, {when: Date.now() + 1000}); - - let wasCleared = await browser.alarms.clear(ALARM_NAME); - browser.test.assertTrue(wasCleared, "alarm was cleared"); - - await new Promise(resolve => setTimeout(resolve, 2000)); - - browser.test.notifyPass("alarm-cleared"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarm-cleared"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_alarms_periodic.js b/toolkit/components/webextensions/test/xpcshell/test_ext_alarms_periodic.js deleted file mode 100644 index 6bcdf4e33..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_alarms_periodic.js +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_periodic_alarm_fires() { - function backgroundScript() { - const ALARM_NAME = "test_ext_alarms"; - let count = 0; - let timer; - - browser.alarms.onAlarm.addListener(async alarm => { - browser.test.assertEq(alarm.name, ALARM_NAME, "alarm has the expected name"); - if (count++ === 3) { - clearTimeout(timer); - let wasCleared = await browser.alarms.clear(ALARM_NAME); - browser.test.assertTrue(wasCleared, "alarm was cleared"); - - browser.test.notifyPass("alarm-periodic"); - } - }); - - browser.alarms.create(ALARM_NAME, {periodInMinutes: 0.02}); - - timer = setTimeout(async () => { - browser.test.fail("alarm fired expected number of times"); - - let wasCleared = await browser.alarms.clear(ALARM_NAME); - browser.test.assertTrue(wasCleared, "alarm was cleared"); - - browser.test.notifyFail("alarm-periodic"); - }, 30000); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarm-periodic"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_alarms_replaces.js b/toolkit/components/webextensions/test/xpcshell/test_ext_alarms_replaces.js deleted file mode 100644 index 96f61acb5..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_alarms_replaces.js +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - - -add_task(function* test_duplicate_alarm_name_replaces_alarm() { - function backgroundScript() { - let count = 0; - - browser.alarms.onAlarm.addListener(async alarm => { - if (alarm.name === "master alarm") { - browser.alarms.create("child alarm", {delayInMinutes: 0.05}); - let results = await browser.alarms.getAll(); - - browser.test.assertEq(2, results.length, "exactly two alarms exist"); - browser.test.assertEq("master alarm", results[0].name, "first alarm has the expected name"); - browser.test.assertEq("child alarm", results[1].name, "second alarm has the expected name"); - - if (count++ === 3) { - await browser.alarms.clear("master alarm"); - await browser.alarms.clear("child alarm"); - - browser.test.notifyPass("alarm-duplicate"); - } - } else { - browser.test.fail("duplicate named alarm replaced existing alarm"); - browser.test.notifyFail("alarm-duplicate"); - } - }); - - browser.alarms.create("master alarm", {delayInMinutes: 0.025, periodInMinutes: 0.025}); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarm-duplicate"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_api_permissions.js b/toolkit/components/webextensions/test/xpcshell/test_ext_api_permissions.js deleted file mode 100644 index d653d0e7a..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_api_permissions.js +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -let {Management} = Cu.import("resource://gre/modules/Extension.jsm", {}); -function getNextContext() { - return new Promise(resolve => { - Management.on("proxy-context-load", function listener(type, context) { - Management.off("proxy-context-load", listener); - resolve(context); - }); - }); -} - -add_task(function* test_storage_api_without_permissions() { - let extension = ExtensionTestUtils.loadExtension({ - background() { - // Force API initialization. - void browser.storage; - }, - - manifest: { - permissions: [], - }, - }); - - let contextPromise = getNextContext(); - yield extension.startup(); - - let context = yield contextPromise; - - // Force API initialization. - void context.apiObj; - - ok(!("storage" in context.apiObj), - "The storage API should not be initialized"); - - yield extension.unload(); -}); - -add_task(function* test_storage_api_with_permissions() { - let extension = ExtensionTestUtils.loadExtension({ - background() { - void browser.storage; - }, - - manifest: { - permissions: ["storage"], - }, - }); - - let contextPromise = getNextContext(); - yield extension.startup(); - - let context = yield contextPromise; - - // Force API initialization. - void context.apiObj; - - equal(typeof context.apiObj.storage, "object", - "The storage API should be initialized"); - - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_apimanager.js b/toolkit/components/webextensions/test/xpcshell/test_ext_apimanager.js deleted file mode 100644 index 3f6672a11..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_apimanager.js +++ /dev/null @@ -1,91 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -Cu.import("resource://gre/modules/ExtensionCommon.jsm"); - -const { - SchemaAPIManager, -} = ExtensionCommon; - -this.unknownvar = "Some module-global var"; - -var gUniqueId = 0; - -// SchemaAPIManager's loadScript uses loadSubScript to load a script. This -// requires a local (resource://) URL. So create such a temporary URL for -// testing. -function toLocalURI(code) { - let dataUrl = `data:charset=utf-8,${encodeURIComponent(code)}`; - let uniqueResPart = `need-a-local-uri-for-subscript-loading-${++gUniqueId}`; - Services.io.getProtocolHandler("resource") - .QueryInterface(Ci.nsIResProtocolHandler) - .setSubstitution(uniqueResPart, Services.io.newURI(dataUrl, null, null)); - return `resource://${uniqueResPart}`; -} - -add_task(function* test_global_isolation() { - let manA = new SchemaAPIManager("procA"); - let manB = new SchemaAPIManager("procB"); - - // The "global" variable should be persistent and shared. - manA.loadScript(toLocalURI`global.globalVar = 1;`); - do_check_eq(manA.global.globalVar, 1); - do_check_eq(manA.global.unknownvar, undefined); - manA.loadScript(toLocalURI`global.canSeeGlobal = global.globalVar;`); - do_check_eq(manA.global.canSeeGlobal, 1); - - // Each loadScript call should have their own scope, and global is shared. - manA.loadScript(toLocalURI`this.aVar = 1; global.thisScopeVar = aVar`); - do_check_eq(manA.global.aVar, undefined); - do_check_eq(manA.global.thisScopeVar, 1); - manA.loadScript(toLocalURI`global.differentScopeVar = this.aVar;`); - do_check_eq(manA.global.differentScopeVar, undefined); - manA.loadScript(toLocalURI`global.cantSeeOtherScope = typeof aVar;`); - do_check_eq(manA.global.cantSeeOtherScope, "undefined"); - - manB.loadScript(toLocalURI`global.tryReadOtherGlobal = global.tryagain;`); - do_check_eq(manA.global.tryReadOtherGlobal, undefined); - - // Cu.import without second argument exports to the caller's global. Let's - // verify that it does not leak to the SchemaAPIManager's global. - do_check_eq(typeof ExtensionUtils, "undefined"); // Sanity check #1. - manA.loadScript(toLocalURI`global.hasExtUtils = typeof ExtensionUtils;`); - do_check_eq(manA.global.hasExtUtils, "undefined"); // Sanity check #2 - - Cu.import("resource://gre/modules/ExtensionUtils.jsm"); - do_check_eq(typeof ExtensionUtils, "object"); // Sanity check #3. - - manA.loadScript(toLocalURI`global.hasExtUtils = typeof ExtensionUtils;`); - do_check_eq(manA.global.hasExtUtils, "undefined"); - manB.loadScript(toLocalURI`global.hasExtUtils = typeof ExtensionUtils;`); - do_check_eq(manB.global.hasExtUtils, "undefined"); - - // Confirm that Cu.import does not leak between SchemaAPIManager globals. - manA.loadScript(toLocalURI` - Cu.import("resource://gre/modules/ExtensionUtils.jsm"); - global.hasExtUtils = typeof ExtensionUtils; - `); - do_check_eq(manA.global.hasExtUtils, "object"); // Sanity check. - manB.loadScript(toLocalURI`global.hasExtUtils = typeof ExtensionUtils;`); - do_check_eq(manB.global.hasExtUtils, "undefined"); - - // Prototype modifications should be isolated. - manA.loadScript(toLocalURI` - Object.prototype.modifiedByA = "Prrft"; - global.fromA = {}; - `); - manA.loadScript(toLocalURI` - global.fromAagain = {}; - `); - manB.loadScript(toLocalURI` - global.fromB = {}; - `); - do_check_eq(manA.global.modifiedByA, "Prrft"); - do_check_eq(manA.global.fromA.modifiedByA, "Prrft"); - do_check_eq(manA.global.fromAagain.modifiedByA, "Prrft"); - do_check_eq(manB.global.modifiedByA, undefined); - do_check_eq(manB.global.fromB.modifiedByA, undefined); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_background_generated_load_events.js b/toolkit/components/webextensions/test/xpcshell/test_ext_background_generated_load_events.js deleted file mode 100644 index 26282fcb9..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_background_generated_load_events.js +++ /dev/null @@ -1,23 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -/* eslint-disable mozilla/balanced-listeners */ - -add_task(function* test_DOMContentLoaded_in_generated_background_page() { - let extension = ExtensionTestUtils.loadExtension({ - background() { - function reportListener(event) { - browser.test.sendMessage("eventname", event.type); - } - document.addEventListener("DOMContentLoaded", reportListener); - window.addEventListener("load", reportListener); - }, - }); - - yield extension.startup(); - equal("DOMContentLoaded", yield extension.awaitMessage("eventname")); - equal("load", yield extension.awaitMessage("eventname")); - - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_background_generated_reload.js b/toolkit/components/webextensions/test/xpcshell/test_ext_background_generated_reload.js deleted file mode 100644 index 4bf59b798..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_background_generated_reload.js +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_reload_generated_background_page() { - let extension = ExtensionTestUtils.loadExtension({ - background() { - if (location.hash !== "#firstrun") { - browser.test.sendMessage("first run"); - location.hash = "#firstrun"; - browser.test.assertEq("#firstrun", location.hash); - location.reload(); - } else { - browser.test.notifyPass("second run"); - } - }, - }); - - yield extension.startup(); - yield extension.awaitMessage("first run"); - yield extension.awaitFinish("second run"); - - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_background_global_history.js b/toolkit/components/webextensions/test/xpcshell/test_ext_background_global_history.js deleted file mode 100644 index 092a9f5b3..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_background_global_history.js +++ /dev/null @@ -1,22 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -Cu.import("resource://testing-common/PlacesTestUtils.jsm"); - -add_task(function* test_global_history() { - let extension = ExtensionTestUtils.loadExtension({ - background() { - browser.test.sendMessage("background-loaded", location.href); - }, - }); - - yield extension.startup(); - - let backgroundURL = yield extension.awaitMessage("background-loaded"); - - yield extension.unload(); - - let exists = yield PlacesTestUtils.isPageInDB(backgroundURL); - ok(!exists, "Background URL should not be in history database"); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_background_private_browsing.js b/toolkit/components/webextensions/test/xpcshell/test_ext_background_private_browsing.js deleted file mode 100644 index 8e8b5e0b0..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_background_private_browsing.js +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -Cu.import("resource://gre/modules/Preferences.jsm"); - -function* testBackgroundPage(expected) { - let extension = ExtensionTestUtils.loadExtension({ - async background() { - browser.test.assertEq(window, browser.extension.getBackgroundPage(), - "Caller should be able to access itself as a background page"); - browser.test.assertEq(window, await browser.runtime.getBackgroundPage(), - "Caller should be able to access itself as a background page"); - - browser.test.sendMessage("incognito", browser.extension.inIncognitoContext); - }, - }); - - yield extension.startup(); - - let incognito = yield extension.awaitMessage("incognito"); - equal(incognito, expected.incognito, "Expected incognito value"); - - yield extension.unload(); -} - -add_task(function* test_background_incognito() { - do_print("Test background page incognito value with permanent private browsing disabled"); - - yield testBackgroundPage({incognito: false}); - - do_print("Test background page incognito value with permanent private browsing enabled"); - - Preferences.set("browser.privatebrowsing.autostart", true); - do_register_cleanup(() => { - Preferences.reset("browser.privatebrowsing.autostart"); - }); - - yield testBackgroundPage({incognito: true}); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_background_runtime_connect_params.js b/toolkit/components/webextensions/test/xpcshell/test_ext_background_runtime_connect_params.js deleted file mode 100644 index 426833edd..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_background_runtime_connect_params.js +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -function backgroundScript() { - let received_ports_number = 0; - - const expected_received_ports_number = 1; - - function countReceivedPorts(port) { - received_ports_number++; - - if (port.name == "check-results") { - browser.runtime.onConnect.removeListener(countReceivedPorts); - - browser.test.assertEq(expected_received_ports_number, received_ports_number, "invalid connect should not create a port"); - - browser.test.notifyPass("runtime.connect invalid params"); - } - } - - browser.runtime.onConnect.addListener(countReceivedPorts); - - let childFrame = document.createElement("iframe"); - childFrame.src = "extensionpage.html"; - document.body.appendChild(childFrame); -} - -function senderScript() { - let detected_invalid_connect_params = 0; - - const invalid_connect_params = [ - // too many params - ["fake-extensions-id", {name: "fake-conn-name"}, "unexpected third params"], - // invalid params format - [{}, {}], - ["fake-extensions-id", "invalid-connect-info-format"], - ]; - const expected_detected_invalid_connect_params = invalid_connect_params.length; - - function assertInvalidConnectParamsException(params) { - try { - browser.runtime.connect(...params); - } catch (e) { - detected_invalid_connect_params++; - browser.test.assertTrue(e.toString().indexOf("Incorrect argument types for runtime.connect.") >= 0, "exception message is correct"); - } - } - for (let params of invalid_connect_params) { - assertInvalidConnectParamsException(params); - } - browser.test.assertEq(expected_detected_invalid_connect_params, detected_invalid_connect_params, "all invalid runtime.connect params detected"); - - browser.runtime.connect(browser.runtime.id, {name: "check-results"}); -} - -let extensionData = { - background: backgroundScript, - files: { - "senderScript.js": senderScript, - "extensionpage.html": `<!DOCTYPE html><meta charset="utf-8"><script src="senderScript.js"></script>`, - }, -}; - -add_task(function* test_backgroundRuntimeConnectParams() { - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - - yield extension.awaitFinish("runtime.connect invalid params"); - - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_background_sub_windows.js b/toolkit/components/webextensions/test/xpcshell/test_ext_background_sub_windows.js deleted file mode 100644 index c5f2f1332..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_background_sub_windows.js +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* testBackgroundWindow() { - let extension = ExtensionTestUtils.loadExtension({ - background() { - browser.test.log("background script executed"); - - browser.test.sendMessage("background-script-load"); - - let img = document.createElement("img"); - img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; - document.body.appendChild(img); - - img.onload = () => { - browser.test.log("image loaded"); - - let iframe = document.createElement("iframe"); - iframe.src = "about:blank?1"; - - iframe.onload = () => { - browser.test.log("iframe loaded"); - setTimeout(() => { - browser.test.notifyPass("background sub-window test done"); - }, 0); - }; - document.body.appendChild(iframe); - }; - }, - }); - - let loadCount = 0; - extension.onMessage("background-script-load", () => { - loadCount++; - }); - - yield extension.startup(); - - yield extension.awaitFinish("background sub-window test done"); - - equal(loadCount, 1, "background script loaded only once"); - - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_background_window_properties.js b/toolkit/components/webextensions/test/xpcshell/test_ext_background_window_properties.js deleted file mode 100644 index 948e2913e..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_background_window_properties.js +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* testBackgroundWindowProperties() { - let extension = ExtensionTestUtils.loadExtension({ - background() { - let expectedValues = { - screenX: 0, - screenY: 0, - outerWidth: 0, - outerHeight: 0, - }; - - for (let k in window) { - try { - if (k in expectedValues) { - browser.test.assertEq(expectedValues[k], window[k], - `should return the expected value for window property: ${k}`); - } else { - void window[k]; - } - } catch (e) { - browser.test.assertEq(null, e, `unexpected exception accessing window property: ${k}`); - } - } - - browser.test.notifyPass("background.testWindowProperties.done"); - }, - }); - yield extension.startup(); - yield extension.awaitFinish("background.testWindowProperties.done"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_contexts.js b/toolkit/components/webextensions/test/xpcshell/test_ext_contexts.js deleted file mode 100644 index 56a14e189..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_contexts.js +++ /dev/null @@ -1,190 +0,0 @@ -"use strict"; - -const global = this; - -Cu.import("resource://gre/modules/Timer.jsm"); - -Cu.import("resource://gre/modules/ExtensionCommon.jsm"); -Cu.import("resource://gre/modules/ExtensionUtils.jsm"); - -var { - BaseContext, -} = ExtensionCommon; - -var { - EventManager, - SingletonEventManager, -} = ExtensionUtils; - -class StubContext extends BaseContext { - constructor() { - let fakeExtension = {id: "test@web.extension"}; - super("testEnv", fakeExtension); - this.sandbox = Cu.Sandbox(global); - } - - get cloneScope() { - return this.sandbox; - } -} - - -add_task(function* test_post_unload_promises() { - let context = new StubContext(); - - let fail = result => { - ok(false, `Unexpected callback: ${result}`); - }; - - // Make sure promises resolve normally prior to unload. - let promises = [ - context.wrapPromise(Promise.resolve()), - context.wrapPromise(Promise.reject({message: ""})).catch(() => {}), - ]; - - yield Promise.all(promises); - - // Make sure promises that resolve after unload do not trigger - // resolution handlers. - - context.wrapPromise(Promise.resolve("resolved")) - .then(fail); - - context.wrapPromise(Promise.reject({message: "rejected"})) - .then(fail, fail); - - context.unload(); - - // The `setTimeout` ensures that we return to the event loop after - // promise resolution, which means we're guaranteed to return after - // any micro-tasks that get enqueued by the resolution handlers above. - yield new Promise(resolve => setTimeout(resolve, 0)); -}); - - -add_task(function* test_post_unload_listeners() { - let context = new StubContext(); - - let fireEvent; - let onEvent = new EventManager(context, "onEvent", fire => { - fireEvent = fire; - return () => {}; - }); - - let fireSingleton; - let onSingleton = new SingletonEventManager(context, "onSingleton", callback => { - fireSingleton = () => { - Promise.resolve().then(callback); - }; - return () => {}; - }); - - let fail = event => { - ok(false, `Unexpected event: ${event}`); - }; - - // Check that event listeners aren't called after they've been removed. - onEvent.addListener(fail); - onSingleton.addListener(fail); - - let promises = [ - new Promise(resolve => onEvent.addListener(resolve)), - new Promise(resolve => onSingleton.addListener(resolve)), - ]; - - fireEvent("onEvent"); - fireSingleton("onSingleton"); - - // Both `fireEvent` calls are dispatched asynchronously, so they won't - // have fired by this point. The `fail` listeners that we remove now - // should not be called, even though the events have already been - // enqueued. - onEvent.removeListener(fail); - onSingleton.removeListener(fail); - - // Wait for the remaining listeners to be called, which should always - // happen after the `fail` listeners would normally be called. - yield Promise.all(promises); - - // Check that event listeners aren't called after the context has - // unloaded. - onEvent.addListener(fail); - onSingleton.addListener(fail); - - // The EventManager `fire` callback always dispatches events - // asynchronously, so we need to test that any pending event callbacks - // aren't fired after the context unloads. We also need to test that - // any `fire` calls that happen *after* the context is unloaded also - // do not trigger callbacks. - fireEvent("onEvent"); - Promise.resolve("onEvent").then(fireEvent); - - fireSingleton("onSingleton"); - Promise.resolve("onSingleton").then(fireSingleton); - - context.unload(); - - // The `setTimeout` ensures that we return to the event loop after - // promise resolution, which means we're guaranteed to return after - // any micro-tasks that get enqueued by the resolution handlers above. - yield new Promise(resolve => setTimeout(resolve, 0)); -}); - -class Context extends BaseContext { - constructor(principal) { - let fakeExtension = {id: "test@web.extension"}; - super("testEnv", fakeExtension); - Object.defineProperty(this, "principal", { - value: principal, - configurable: true, - }); - this.sandbox = Cu.Sandbox(principal, {wantXrays: false}); - } - - get cloneScope() { - return this.sandbox; - } -} - -let ssm = Services.scriptSecurityManager; -const PRINCIPAL1 = ssm.createCodebasePrincipalFromOrigin("http://www.example.org"); -const PRINCIPAL2 = ssm.createCodebasePrincipalFromOrigin("http://www.somethingelse.org"); - -// Test that toJSON() works in the json sandbox -add_task(function* test_stringify_toJSON() { - let context = new Context(PRINCIPAL1); - let obj = Cu.evalInSandbox("({hidden: true, toJSON() { return {visible: true}; } })", context.sandbox); - - let stringified = context.jsonStringify(obj); - let expected = JSON.stringify({visible: true}); - equal(stringified, expected, "Stringified object with toJSON() method is as expected"); -}); - -// Test that stringifying in inaccessible property throws -add_task(function* test_stringify_inaccessible() { - let context = new Context(PRINCIPAL1); - let sandbox = context.sandbox; - let sandbox2 = Cu.Sandbox(PRINCIPAL2); - - Cu.waiveXrays(sandbox).subobj = Cu.evalInSandbox("({ subobject: true })", sandbox2); - let obj = Cu.evalInSandbox("({ local: true, nested: subobj })", sandbox); - Assert.throws(() => { - context.jsonStringify(obj); - }); -}); - -add_task(function* test_stringify_accessible() { - // Test that an accessible property from another global is included - let principal = Cu.getObjectPrincipal(Cu.Sandbox([PRINCIPAL1, PRINCIPAL2])); - let context = new Context(principal); - let sandbox = context.sandbox; - let sandbox2 = Cu.Sandbox(PRINCIPAL2); - - Cu.waiveXrays(sandbox).subobj = Cu.evalInSandbox("({ subobject: true })", sandbox2); - let obj = Cu.evalInSandbox("({ local: true, nested: subobj })", sandbox); - let stringified = context.jsonStringify(obj); - - let expected = JSON.stringify({local: true, nested: {subobject: true}}); - equal(stringified, expected, "Stringified object with accessible property is as expected"); -}); - diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_downloads.js b/toolkit/components/webextensions/test/xpcshell/test_ext_downloads.js deleted file mode 100644 index 058b9b18c..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_downloads.js +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_downloads_api_namespace_and_permissions() { - function backgroundScript() { - browser.test.assertTrue(!!browser.downloads, "`downloads` API is present."); - browser.test.assertTrue(!!browser.downloads.FilenameConflictAction, - "`downloads.FilenameConflictAction` enum is present."); - browser.test.assertTrue(!!browser.downloads.InterruptReason, - "`downloads.InterruptReason` enum is present."); - browser.test.assertTrue(!!browser.downloads.DangerType, - "`downloads.DangerType` enum is present."); - browser.test.assertTrue(!!browser.downloads.State, - "`downloads.State` enum is present."); - browser.test.notifyPass("downloads tests"); - } - - let extensionData = { - background: backgroundScript, - manifest: { - permissions: ["downloads", "downloads.open", "downloads.shelf"], - }, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - yield extension.awaitFinish("downloads tests"); - yield extension.unload(); -}); - -add_task(function* test_downloads_open_permission() { - function backgroundScript() { - browser.test.assertFalse("open" in browser.downloads, - "`downloads.open` permission is required."); - browser.test.notifyPass("downloads tests"); - } - - let extensionData = { - background: backgroundScript, - manifest: { - permissions: ["downloads"], - }, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - yield extension.awaitFinish("downloads tests"); - yield extension.unload(); -}); - -add_task(function* test_downloads_open() { - async function backgroundScript() { - await browser.test.assertRejects( - browser.downloads.open(10), - "Invalid download id 10", - "The error is informative."); - - browser.test.notifyPass("downloads tests"); - - // TODO: Once downloads.{pause,cancel,resume} lands (bug 1245602) test that this gives a good - // error when called with an incompleted download. - } - - let extensionData = { - background: backgroundScript, - manifest: { - permissions: ["downloads", "downloads.open"], - }, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - yield extension.awaitFinish("downloads tests"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_downloads_download.js b/toolkit/components/webextensions/test/xpcshell/test_ext_downloads_download.js deleted file mode 100644 index 37ddd4d7c..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_downloads_download.js +++ /dev/null @@ -1,354 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -/* global OS */ - -Cu.import("resource://gre/modules/osfile.jsm"); -Cu.import("resource://gre/modules/Downloads.jsm"); - -const gServer = createHttpServer(); -gServer.registerDirectory("/data/", do_get_file("data")); - -const WINDOWS = AppConstants.platform == "win"; - -const BASE = `http://localhost:${gServer.identity.primaryPort}/data`; -const FILE_NAME = "file_download.txt"; -const FILE_URL = BASE + "/" + FILE_NAME; -const FILE_NAME_UNIQUE = "file_download(1).txt"; -const FILE_LEN = 46; - -let downloadDir; - -function setup() { - downloadDir = FileUtils.getDir("TmpD", ["downloads"]); - downloadDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - do_print(`Using download directory ${downloadDir.path}`); - - Services.prefs.setIntPref("browser.download.folderList", 2); - Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, downloadDir); - - do_register_cleanup(() => { - Services.prefs.clearUserPref("browser.download.folderList"); - Services.prefs.clearUserPref("browser.download.dir"); - - let entries = downloadDir.directoryEntries; - while (entries.hasMoreElements()) { - let entry = entries.getNext().QueryInterface(Ci.nsIFile); - ok(false, `Leftover file ${entry.path} in download directory`); - entry.remove(false); - } - - downloadDir.remove(false); - }); -} - -function backgroundScript() { - let blobUrl; - browser.test.onMessage.addListener(async (msg, ...args) => { - if (msg == "download.request") { - let options = args[0]; - - if (options.blobme) { - let blob = new Blob(options.blobme); - delete options.blobme; - blobUrl = options.url = window.URL.createObjectURL(blob); - } - - try { - let id = await browser.downloads.download(options); - browser.test.sendMessage("download.done", {status: "success", id}); - } catch (error) { - browser.test.sendMessage("download.done", {status: "error", errmsg: error.message}); - } - } else if (msg == "killTheBlob") { - window.URL.revokeObjectURL(blobUrl); - blobUrl = null; - } - }); - - browser.test.sendMessage("ready"); -} - -// This function is a bit of a sledgehammer, it looks at every download -// the browser knows about and waits for all active downloads to complete. -// But we only start one at a time and only do a handful in total, so -// this lets us test download() without depending on anything else. -async function waitForDownloads() { - let list = await Downloads.getList(Downloads.ALL); - let downloads = await list.getAll(); - - let inprogress = downloads.filter(dl => !dl.stopped); - return Promise.all(inprogress.map(dl => dl.whenSucceeded())); -} - -// Create a file in the downloads directory. -function touch(filename) { - let file = downloadDir.clone(); - file.append(filename); - file.create(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); -} - -// Remove a file in the downloads directory. -function remove(filename, recursive = false) { - let file = downloadDir.clone(); - file.append(filename); - file.remove(recursive); -} - -add_task(function* test_downloads() { - setup(); - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["downloads"], - }, - }); - - function download(options) { - extension.sendMessage("download.request", options); - return extension.awaitMessage("download.done"); - } - - async function testDownload(options, localFile, expectedSize, description) { - let msg = await download(options); - equal(msg.status, "success", `downloads.download() works with ${description}`); - - await waitForDownloads(); - - let localPath = downloadDir.clone(); - let parts = Array.isArray(localFile) ? localFile : [localFile]; - - parts.map(p => localPath.append(p)); - equal(localPath.fileSize, expectedSize, "Downloaded file has expected size"); - localPath.remove(false); - } - - yield extension.startup(); - yield extension.awaitMessage("ready"); - do_print("extension started"); - - // Call download() with just the url property. - yield testDownload({url: FILE_URL}, FILE_NAME, FILE_LEN, "just source"); - - // Call download() with a filename property. - yield testDownload({ - url: FILE_URL, - filename: "newpath.txt", - }, "newpath.txt", FILE_LEN, "source and filename"); - - // Call download() with a filename with subdirs. - yield testDownload({ - url: FILE_URL, - filename: "sub/dir/file", - }, ["sub", "dir", "file"], FILE_LEN, "source and filename with subdirs"); - - // Call download() with a filename with existing subdirs. - yield testDownload({ - url: FILE_URL, - filename: "sub/dir/file2", - }, ["sub", "dir", "file2"], FILE_LEN, "source and filename with existing subdirs"); - - // Only run Windows path separator test on Windows. - if (WINDOWS) { - // Call download() with a filename with Windows path separator. - yield testDownload({ - url: FILE_URL, - filename: "sub\\dir\\file3", - }, ["sub", "dir", "file3"], FILE_LEN, "filename with Windows path separator"); - } - remove("sub", true); - - // Call download(), filename with subdir, skipping parts. - yield testDownload({ - url: FILE_URL, - filename: "skip//part", - }, ["skip", "part"], FILE_LEN, "source, filename, with subdir, skipping parts"); - remove("skip", true); - - // Check conflictAction of "uniquify". - touch(FILE_NAME); - yield testDownload({ - url: FILE_URL, - conflictAction: "uniquify", - }, FILE_NAME_UNIQUE, FILE_LEN, "conflictAction=uniquify"); - // todo check that preexisting file was not modified? - remove(FILE_NAME); - - // Check conflictAction of "overwrite". - touch(FILE_NAME); - yield testDownload({ - url: FILE_URL, - conflictAction: "overwrite", - }, FILE_NAME, FILE_LEN, "conflictAction=overwrite"); - - // Try to download in invalid url - yield download({url: "this is not a valid URL"}).then(msg => { - equal(msg.status, "error", "downloads.download() fails with invalid url"); - ok(/not a valid URL/.test(msg.errmsg), "error message for invalid url is correct"); - }); - - // Try to download to an empty path. - yield download({ - url: FILE_URL, - filename: "", - }).then(msg => { - equal(msg.status, "error", "downloads.download() fails with empty filename"); - equal(msg.errmsg, "filename must not be empty", "error message for empty filename is correct"); - }); - - // Try to download to an absolute path. - const absolutePath = OS.Path.join(WINDOWS ? "\\tmp" : "/tmp", "file_download.txt"); - yield download({ - url: FILE_URL, - filename: absolutePath, - }).then(msg => { - equal(msg.status, "error", "downloads.download() fails with absolute filename"); - equal(msg.errmsg, "filename must not be an absolute path", `error message for absolute path (${absolutePath}) is correct`); - }); - - if (WINDOWS) { - yield download({ - url: FILE_URL, - filename: "C:\\file_download.txt", - }).then(msg => { - equal(msg.status, "error", "downloads.download() fails with absolute filename"); - equal(msg.errmsg, "filename must not be an absolute path", "error message for absolute path with drive letter is correct"); - }); - } - - // Try to download to a relative path containing .. - yield download({ - url: FILE_URL, - filename: OS.Path.join("..", "file_download.txt"), - }).then(msg => { - equal(msg.status, "error", "downloads.download() fails with back-references"); - equal(msg.errmsg, "filename must not contain back-references (..)", "error message for back-references is correct"); - }); - - // Try to download to a long relative path containing .. - yield download({ - url: FILE_URL, - filename: OS.Path.join("foo", "..", "..", "file_download.txt"), - }).then(msg => { - equal(msg.status, "error", "downloads.download() fails with back-references"); - equal(msg.errmsg, "filename must not contain back-references (..)", "error message for back-references is correct"); - }); - - // Try to download a blob url - const BLOB_STRING = "Hello, world"; - yield testDownload({ - blobme: [BLOB_STRING], - filename: FILE_NAME, - }, FILE_NAME, BLOB_STRING.length, "blob url"); - extension.sendMessage("killTheBlob"); - - // Try to download a blob url without a given filename - yield testDownload({ - blobme: [BLOB_STRING], - }, "download", BLOB_STRING.length, "blob url with no filename"); - extension.sendMessage("killTheBlob"); - - yield extension.unload(); -}); - -add_task(function* test_download_post() { - const server = createHttpServer(); - const url = `http://localhost:${server.identity.primaryPort}/post-log`; - - let received; - server.registerPathHandler("/post-log", request => { - received = request; - }); - - // Confirm received vs. expected values. - function confirm(method, headers = {}, body) { - equal(received.method, method, "method is correct"); - - for (let name in headers) { - ok(received.hasHeader(name), `header ${name} received`); - equal(received.getHeader(name), headers[name], `header ${name} is correct`); - } - - if (body) { - const str = NetUtil.readInputStreamToString(received.bodyInputStream, - received.bodyInputStream.available()); - equal(str, body, "body is correct"); - } - } - - function background() { - browser.test.onMessage.addListener(async options => { - try { - await browser.downloads.download(options); - } catch (err) { - browser.test.sendMessage("done", {err: err.message}); - } - }); - browser.downloads.onChanged.addListener(({state}) => { - if (state && state.current === "complete") { - browser.test.sendMessage("done", {ok: true}); - } - }); - } - - const manifest = {permissions: ["downloads"]}; - const extension = ExtensionTestUtils.loadExtension({background, manifest}); - yield extension.startup(); - - function download(options) { - options.url = url; - options.conflictAction = "overwrite"; - - extension.sendMessage(options); - return extension.awaitMessage("done"); - } - - // Test method option. - let result = yield download({}); - ok(result.ok, "download works without the method option, defaults to GET"); - confirm("GET"); - - result = yield download({method: "PUT"}); - ok(!result.ok, "download rejected with PUT method"); - ok(/method: Invalid enumeration/.test(result.err), "descriptive error message"); - - result = yield download({method: "POST"}); - ok(result.ok, "download works with POST method"); - confirm("POST"); - - // Test body option values. - result = yield download({body: []}); - ok(!result.ok, "download rejected because of non-string body"); - ok(/body: Expected string/.test(result.err), "descriptive error message"); - - result = yield download({method: "POST", body: "of work"}); - ok(result.ok, "download works with POST method and body"); - confirm("POST", {"Content-Length": 7}, "of work"); - - // Test custom headers. - result = yield download({headers: [{name: "X-Custom"}]}); - ok(!result.ok, "download rejected because of missing header value"); - ok(/"value" is required/.test(result.err), "descriptive error message"); - - result = yield download({headers: [{name: "X-Custom", value: "13"}]}); - ok(result.ok, "download works with a custom header"); - confirm("GET", {"X-Custom": "13"}); - - // Test forbidden headers. - result = yield download({headers: [{name: "DNT", value: "1"}]}); - ok(!result.ok, "download rejected because of forbidden header name DNT"); - ok(/Forbidden request header/.test(result.err), "descriptive error message"); - - result = yield download({headers: [{name: "Proxy-Connection", value: "keep"}]}); - ok(!result.ok, "download rejected because of forbidden header name prefix Proxy-"); - ok(/Forbidden request header/.test(result.err), "descriptive error message"); - - result = yield download({headers: [{name: "Sec-ret", value: "13"}]}); - ok(!result.ok, "download rejected because of forbidden header name prefix Sec-"); - ok(/Forbidden request header/.test(result.err), "descriptive error message"); - - remove("post-log"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_downloads_misc.js b/toolkit/components/webextensions/test/xpcshell/test_ext_downloads_misc.js deleted file mode 100644 index d08aab666..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_downloads_misc.js +++ /dev/null @@ -1,862 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -Cu.import("resource://gre/modules/Downloads.jsm"); - -const server = createHttpServer(); -server.registerDirectory("/data/", do_get_file("data")); - -const ROOT = `http://localhost:${server.identity.primaryPort}`; -const BASE = `${ROOT}/data`; -const TXT_FILE = "file_download.txt"; -const TXT_URL = BASE + "/" + TXT_FILE; - -// Keep these in sync with code in interruptible.sjs -const INT_PARTIAL_LEN = 15; -const INT_TOTAL_LEN = 31; - -const TEST_DATA = "This is 31 bytes of sample data"; -const TOTAL_LEN = TEST_DATA.length; -const PARTIAL_LEN = 15; - -// A handler to let us systematically test pausing/resuming/canceling -// of downloads. This target represents a small text file but a simple -// GET will stall after sending part of the data, to give the test code -// a chance to pause or do other operations on an in-progress download. -// A resumed download (ie, a GET with a Range: header) will allow the -// download to complete. -function handleRequest(request, response) { - response.setHeader("Content-Type", "text/plain", false); - - if (request.hasHeader("Range")) { - let start, end; - let matches = request.getHeader("Range") - .match(/^\s*bytes=(\d+)?-(\d+)?\s*$/); - if (matches != null) { - start = matches[1] ? parseInt(matches[1], 10) : 0; - end = matches[2] ? parseInt(matches[2], 10) : (TOTAL_LEN - 1); - } - - if (end == undefined || end >= TOTAL_LEN) { - response.setStatusLine(request.httpVersion, 416, "Requested Range Not Satisfiable"); - response.setHeader("Content-Range", `*/${TOTAL_LEN}`, false); - response.finish(); - return; - } - - response.setStatusLine(request.httpVersion, 206, "Partial Content"); - response.setHeader("Content-Range", `${start}-${end}/${TOTAL_LEN}`, false); - response.write(TEST_DATA.slice(start, end + 1)); - } else { - response.processAsync(); - response.setHeader("Content-Length", `${TOTAL_LEN}`, false); - response.write(TEST_DATA.slice(0, PARTIAL_LEN)); - } - - do_register_cleanup(() => { - try { - response.finish(); - } catch (e) { - // This will throw, but we don't care at this point. - } - }); -} - -server.registerPathHandler("/interruptible.html", handleRequest); - -let interruptibleCount = 0; -function getInterruptibleUrl() { - let n = interruptibleCount++; - return `${ROOT}/interruptible.html?count=${n}`; -} - -function backgroundScript() { - let events = new Set(); - let eventWaiter = null; - - browser.downloads.onCreated.addListener(data => { - events.add({type: "onCreated", data}); - if (eventWaiter) { - eventWaiter(); - } - }); - - browser.downloads.onChanged.addListener(data => { - events.add({type: "onChanged", data}); - if (eventWaiter) { - eventWaiter(); - } - }); - - browser.downloads.onErased.addListener(data => { - events.add({type: "onErased", data}); - if (eventWaiter) { - eventWaiter(); - } - }); - - // Returns a promise that will resolve when the given list of expected - // events have all been seen. By default, succeeds only if the exact list - // of expected events is seen in the given order. options.exact can be - // set to false to allow other events and options.inorder can be set to - // false to allow the events to arrive in any order. - function waitForEvents(expected, options = {}) { - function compare(a, b) { - if (typeof b == "object" && b != null) { - if (typeof a != "object") { - return false; - } - return Object.keys(b).every(fld => compare(a[fld], b[fld])); - } - return (a == b); - } - - const exact = ("exact" in options) ? options.exact : true; - const inorder = ("inorder" in options) ? options.inorder : true; - return new Promise((resolve, reject) => { - function check() { - function fail(msg) { - browser.test.fail(msg); - reject(new Error(msg)); - } - if (events.size < expected.length) { - return; - } - if (exact && expected.length < events.size) { - fail(`Got ${events.size} events but only expected ${expected.length}`); - return; - } - - let remaining = new Set(events); - if (inorder) { - for (let event of events) { - if (compare(event, expected[0])) { - expected.shift(); - remaining.delete(event); - } - } - } else { - expected = expected.filter(val => { - for (let remainingEvent of remaining) { - if (compare(remainingEvent, val)) { - remaining.delete(remainingEvent); - return false; - } - } - return true; - }); - } - - // Events that did occur have been removed from expected so if - // expected is empty, we're done. If we didn't see all the - // expected events and we're not looking for an exact match, - // then we just may not have seen the event yet, so return without - // failing and check() will be called again when a new event arrives. - if (expected.length == 0) { - events = remaining; - eventWaiter = null; - resolve(); - } else if (exact) { - fail(`Mismatched event: expecting ${JSON.stringify(expected[0])} but got ${JSON.stringify(Array.from(remaining)[0])}`); - } - } - eventWaiter = check; - check(); - }); - } - - browser.test.onMessage.addListener(async (msg, ...args) => { - let match = msg.match(/(\w+).request$/); - if (!match) { - return; - } - - let what = match[1]; - if (what == "waitForEvents") { - try { - await waitForEvents(...args); - browser.test.sendMessage("waitForEvents.done", {status: "success"}); - } catch (error) { - browser.test.sendMessage("waitForEvents.done", {status: "error", errmsg: error.message}); - } - } else if (what == "clearEvents") { - events = new Set(); - browser.test.sendMessage("clearEvents.done", {status: "success"}); - } else { - try { - let result = await browser.downloads[what](...args); - browser.test.sendMessage(`${what}.done`, {status: "success", result}); - } catch (error) { - browser.test.sendMessage(`${what}.done`, {status: "error", errmsg: error.message}); - } - } - }); - - browser.test.sendMessage("ready"); -} - -let downloadDir; -let extension; - -async function clearDownloads(callback) { - let list = await Downloads.getList(Downloads.ALL); - let downloads = await list.getAll(); - - await Promise.all(downloads.map(download => list.remove(download))); - - return downloads; -} - -function runInExtension(what, ...args) { - extension.sendMessage(`${what}.request`, ...args); - return extension.awaitMessage(`${what}.done`); -} - -// This is pretty simplistic, it looks for a progress update for a -// download of the given url in which the total bytes are exactly equal -// to the given value. Unless you know exactly how data will arrive from -// the server (eg see interruptible.sjs), it probably isn't very useful. -async function waitForProgress(url, bytes) { - let list = await Downloads.getList(Downloads.ALL); - - return new Promise(resolve => { - const view = { - onDownloadChanged(download) { - if (download.source.url == url && download.currentBytes == bytes) { - list.removeView(view); - resolve(); - } - }, - }; - list.addView(view); - }); -} - -add_task(function* setup() { - const nsIFile = Ci.nsIFile; - downloadDir = FileUtils.getDir("TmpD", ["downloads"]); - downloadDir.createUnique(nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - do_print(`downloadDir ${downloadDir.path}`); - - Services.prefs.setIntPref("browser.download.folderList", 2); - Services.prefs.setComplexValue("browser.download.dir", nsIFile, downloadDir); - - do_register_cleanup(() => { - Services.prefs.clearUserPref("browser.download.folderList"); - Services.prefs.clearUserPref("browser.download.dir"); - downloadDir.remove(true); - - return clearDownloads(); - }); - - yield clearDownloads().then(downloads => { - do_print(`removed ${downloads.length} pre-existing downloads from history`); - }); - - extension = ExtensionTestUtils.loadExtension({ - background: backgroundScript, - manifest: { - permissions: ["downloads"], - }, - }); - - yield extension.startup(); - yield extension.awaitMessage("ready"); -}); - -add_task(function* test_events() { - let msg = yield runInExtension("download", {url: TXT_URL}); - equal(msg.status, "success", "download() succeeded"); - const id = msg.result; - - msg = yield runInExtension("waitForEvents", [ - {type: "onCreated", data: {id, url: TXT_URL}}, - { - type: "onChanged", - data: { - id, - state: { - previous: "in_progress", - current: "complete", - }, - }, - }, - ]); - equal(msg.status, "success", "got onCreated and onChanged events"); -}); - -add_task(function* test_cancel() { - let url = getInterruptibleUrl(); - do_print(url); - let msg = yield runInExtension("download", {url}); - equal(msg.status, "success", "download() succeeded"); - const id = msg.result; - - let progressPromise = waitForProgress(url, INT_PARTIAL_LEN); - - msg = yield runInExtension("waitForEvents", [ - {type: "onCreated", data: {id}}, - ]); - equal(msg.status, "success", "got created and changed events"); - - yield progressPromise; - do_print(`download reached ${INT_PARTIAL_LEN} bytes`); - - msg = yield runInExtension("cancel", id); - equal(msg.status, "success", "cancel() succeeded"); - - // This sequence of events is bogus (bug 1256243) - msg = yield runInExtension("waitForEvents", [ - { - type: "onChanged", - data: { - state: { - previous: "in_progress", - current: "interrupted", - }, - paused: { - previous: false, - current: true, - }, - }, - }, { - type: "onChanged", - data: { - id, - error: { - previous: null, - current: "USER_CANCELED", - }, - }, - }, { - type: "onChanged", - data: { - id, - paused: { - previous: true, - current: false, - }, - }, - }, - ]); - equal(msg.status, "success", "got onChanged events corresponding to cancel()"); - - msg = yield runInExtension("search", {error: "USER_CANCELED"}); - equal(msg.status, "success", "search() succeeded"); - equal(msg.result.length, 1, "search() found 1 download"); - equal(msg.result[0].id, id, "download.id is correct"); - equal(msg.result[0].state, "interrupted", "download.state is correct"); - equal(msg.result[0].paused, false, "download.paused is correct"); - equal(msg.result[0].canResume, false, "download.canResume is correct"); - equal(msg.result[0].error, "USER_CANCELED", "download.error is correct"); - equal(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct"); - equal(msg.result[0].exists, false, "download.exists is correct"); - - msg = yield runInExtension("pause", id); - equal(msg.status, "error", "cannot pause a canceled download"); - - msg = yield runInExtension("resume", id); - equal(msg.status, "error", "cannot resume a canceled download"); -}); - -add_task(function* test_pauseresume() { - let url = getInterruptibleUrl(); - let msg = yield runInExtension("download", {url}); - equal(msg.status, "success", "download() succeeded"); - const id = msg.result; - - let progressPromise = waitForProgress(url, INT_PARTIAL_LEN); - - msg = yield runInExtension("waitForEvents", [ - {type: "onCreated", data: {id}}, - ]); - equal(msg.status, "success", "got created and changed events"); - - yield progressPromise; - do_print(`download reached ${INT_PARTIAL_LEN} bytes`); - - msg = yield runInExtension("pause", id); - equal(msg.status, "success", "pause() succeeded"); - - msg = yield runInExtension("waitForEvents", [ - { - type: "onChanged", - data: { - id, - state: { - previous: "in_progress", - current: "interrupted", - }, - paused: { - previous: false, - current: true, - }, - canResume: { - previous: false, - current: true, - }, - }, - }, { - type: "onChanged", - data: { - id, - error: { - previous: null, - current: "USER_CANCELED", - }, - }, - }]); - equal(msg.status, "success", "got onChanged event corresponding to pause"); - - msg = yield runInExtension("search", {paused: true}); - equal(msg.status, "success", "search() succeeded"); - equal(msg.result.length, 1, "search() found 1 download"); - equal(msg.result[0].id, id, "download.id is correct"); - equal(msg.result[0].state, "interrupted", "download.state is correct"); - equal(msg.result[0].paused, true, "download.paused is correct"); - equal(msg.result[0].canResume, true, "download.canResume is correct"); - equal(msg.result[0].error, "USER_CANCELED", "download.error is correct"); - equal(msg.result[0].bytesReceived, INT_PARTIAL_LEN, "download.bytesReceived is correct"); - equal(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct"); - equal(msg.result[0].exists, false, "download.exists is correct"); - - msg = yield runInExtension("search", {error: "USER_CANCELED"}); - equal(msg.status, "success", "search() succeeded"); - let found = msg.result.filter(item => item.id == id); - equal(found.length, 1, "search() by error found the paused download"); - - msg = yield runInExtension("pause", id); - equal(msg.status, "error", "cannot pause an already paused download"); - - msg = yield runInExtension("resume", id); - equal(msg.status, "success", "resume() succeeded"); - - msg = yield runInExtension("waitForEvents", [ - { - type: "onChanged", - data: { - id, - state: { - previous: "interrupted", - current: "in_progress", - }, - paused: { - previous: true, - current: false, - }, - canResume: { - previous: true, - current: false, - }, - error: { - previous: "USER_CANCELED", - current: null, - }, - }, - }, - { - type: "onChanged", - data: { - id, - state: { - previous: "in_progress", - current: "complete", - }, - }, - }, - ]); - equal(msg.status, "success", "got onChanged events for resume and complete"); - - msg = yield runInExtension("search", {id}); - equal(msg.status, "success", "search() succeeded"); - equal(msg.result.length, 1, "search() found 1 download"); - equal(msg.result[0].state, "complete", "download.state is correct"); - equal(msg.result[0].paused, false, "download.paused is correct"); - equal(msg.result[0].canResume, false, "download.canResume is correct"); - equal(msg.result[0].error, null, "download.error is correct"); - equal(msg.result[0].bytesReceived, INT_TOTAL_LEN, "download.bytesReceived is correct"); - equal(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct"); - equal(msg.result[0].exists, true, "download.exists is correct"); - - msg = yield runInExtension("pause", id); - equal(msg.status, "error", "cannot pause a completed download"); - - msg = yield runInExtension("resume", id); - equal(msg.status, "error", "cannot resume a completed download"); -}); - -add_task(function* test_pausecancel() { - let url = getInterruptibleUrl(); - let msg = yield runInExtension("download", {url}); - equal(msg.status, "success", "download() succeeded"); - const id = msg.result; - - let progressPromise = waitForProgress(url, INT_PARTIAL_LEN); - - msg = yield runInExtension("waitForEvents", [ - {type: "onCreated", data: {id}}, - ]); - equal(msg.status, "success", "got created and changed events"); - - yield progressPromise; - do_print(`download reached ${INT_PARTIAL_LEN} bytes`); - - msg = yield runInExtension("pause", id); - equal(msg.status, "success", "pause() succeeded"); - - msg = yield runInExtension("waitForEvents", [ - { - type: "onChanged", - data: { - id, - state: { - previous: "in_progress", - current: "interrupted", - }, - paused: { - previous: false, - current: true, - }, - canResume: { - previous: false, - current: true, - }, - }, - }, { - type: "onChanged", - data: { - id, - error: { - previous: null, - current: "USER_CANCELED", - }, - }, - }]); - equal(msg.status, "success", "got onChanged event corresponding to pause"); - - msg = yield runInExtension("search", {paused: true}); - equal(msg.status, "success", "search() succeeded"); - equal(msg.result.length, 1, "search() found 1 download"); - equal(msg.result[0].id, id, "download.id is correct"); - equal(msg.result[0].state, "interrupted", "download.state is correct"); - equal(msg.result[0].paused, true, "download.paused is correct"); - equal(msg.result[0].canResume, true, "download.canResume is correct"); - equal(msg.result[0].error, "USER_CANCELED", "download.error is correct"); - equal(msg.result[0].bytesReceived, INT_PARTIAL_LEN, "download.bytesReceived is correct"); - equal(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct"); - equal(msg.result[0].exists, false, "download.exists is correct"); - - msg = yield runInExtension("search", {error: "USER_CANCELED"}); - equal(msg.status, "success", "search() succeeded"); - let found = msg.result.filter(item => item.id == id); - equal(found.length, 1, "search() by error found the paused download"); - - msg = yield runInExtension("cancel", id); - equal(msg.status, "success", "cancel() succeeded"); - - msg = yield runInExtension("waitForEvents", [ - { - type: "onChanged", - data: { - id, - paused: { - previous: true, - current: false, - }, - canResume: { - previous: true, - current: false, - }, - }, - }, - ]); - equal(msg.status, "success", "got onChanged event for cancel"); - - msg = yield runInExtension("search", {id}); - equal(msg.status, "success", "search() succeeded"); - equal(msg.result.length, 1, "search() found 1 download"); - equal(msg.result[0].state, "interrupted", "download.state is correct"); - equal(msg.result[0].paused, false, "download.paused is correct"); - equal(msg.result[0].canResume, false, "download.canResume is correct"); - equal(msg.result[0].error, "USER_CANCELED", "download.error is correct"); - equal(msg.result[0].totalBytes, INT_TOTAL_LEN, "download.totalBytes is correct"); - equal(msg.result[0].exists, false, "download.exists is correct"); -}); - -add_task(function* test_pause_resume_cancel_badargs() { - let BAD_ID = 1000; - - let msg = yield runInExtension("pause", BAD_ID); - equal(msg.status, "error", "pause() failed with a bad download id"); - ok(/Invalid download id/.test(msg.errmsg), "error message is descriptive"); - - msg = yield runInExtension("resume", BAD_ID); - equal(msg.status, "error", "resume() failed with a bad download id"); - ok(/Invalid download id/.test(msg.errmsg), "error message is descriptive"); - - msg = yield runInExtension("cancel", BAD_ID); - equal(msg.status, "error", "cancel() failed with a bad download id"); - ok(/Invalid download id/.test(msg.errmsg), "error message is descriptive"); -}); - -add_task(function* test_file_removal() { - let msg = yield runInExtension("download", {url: TXT_URL}); - equal(msg.status, "success", "download() succeeded"); - const id = msg.result; - - msg = yield runInExtension("waitForEvents", [ - {type: "onCreated", data: {id, url: TXT_URL}}, - { - type: "onChanged", - data: { - id, - state: { - previous: "in_progress", - current: "complete", - }, - }, - }, - ]); - - equal(msg.status, "success", "got onCreated and onChanged events"); - - msg = yield runInExtension("removeFile", id); - equal(msg.status, "success", "removeFile() succeeded"); - - msg = yield runInExtension("removeFile", id); - equal(msg.status, "error", "removeFile() fails since the file was already removed."); - ok(/file doesn't exist/.test(msg.errmsg), "removeFile() failed on removed file."); - - msg = yield runInExtension("removeFile", 1000); - ok(/Invalid download id/.test(msg.errmsg), "removeFile() failed due to non-existent id"); -}); - -add_task(function* test_removal_of_incomplete_download() { - let url = getInterruptibleUrl(); - let msg = yield runInExtension("download", {url}); - equal(msg.status, "success", "download() succeeded"); - const id = msg.result; - - let progressPromise = waitForProgress(url, INT_PARTIAL_LEN); - - msg = yield runInExtension("waitForEvents", [ - {type: "onCreated", data: {id}}, - ]); - equal(msg.status, "success", "got created and changed events"); - - yield progressPromise; - do_print(`download reached ${INT_PARTIAL_LEN} bytes`); - - msg = yield runInExtension("pause", id); - equal(msg.status, "success", "pause() succeeded"); - - msg = yield runInExtension("waitForEvents", [ - { - type: "onChanged", - data: { - id, - state: { - previous: "in_progress", - current: "interrupted", - }, - paused: { - previous: false, - current: true, - }, - canResume: { - previous: false, - current: true, - }, - }, - }, { - type: "onChanged", - data: { - id, - error: { - previous: null, - current: "USER_CANCELED", - }, - }, - }]); - equal(msg.status, "success", "got onChanged event corresponding to pause"); - - msg = yield runInExtension("removeFile", id); - equal(msg.status, "error", "removeFile() on paused download failed"); - - ok(/Cannot remove incomplete download/.test(msg.errmsg), "removeFile() failed due to download being incomplete"); - - msg = yield runInExtension("resume", id); - equal(msg.status, "success", "resume() succeeded"); - - msg = yield runInExtension("waitForEvents", [ - { - type: "onChanged", - data: { - id, - state: { - previous: "interrupted", - current: "in_progress", - }, - paused: { - previous: true, - current: false, - }, - canResume: { - previous: true, - current: false, - }, - error: { - previous: "USER_CANCELED", - current: null, - }, - }, - }, - { - type: "onChanged", - data: { - id, - state: { - previous: "in_progress", - current: "complete", - }, - }, - }, - ]); - equal(msg.status, "success", "got onChanged events for resume and complete"); - - msg = yield runInExtension("removeFile", id); - equal(msg.status, "success", "removeFile() succeeded following completion of resumed download."); -}); - -// Test erase(). We don't do elaborate testing of the query handling -// since it uses the exact same engine as search() which is tested -// more thoroughly in test_chrome_ext_downloads_search.html -add_task(function* test_erase() { - yield clearDownloads(); - - yield runInExtension("clearEvents"); - - function* download() { - let msg = yield runInExtension("download", {url: TXT_URL}); - equal(msg.status, "success", "download succeeded"); - let id = msg.result; - - msg = yield runInExtension("waitForEvents", [{ - type: "onChanged", data: {id, state: {current: "complete"}}, - }], {exact: false}); - equal(msg.status, "success", "download finished"); - - return id; - } - - let ids = {}; - ids.dl1 = yield download(); - ids.dl2 = yield download(); - ids.dl3 = yield download(); - - let msg = yield runInExtension("search", {}); - equal(msg.status, "success", "search succeded"); - equal(msg.result.length, 3, "search found 3 downloads"); - - msg = yield runInExtension("clearEvents"); - - msg = yield runInExtension("erase", {id: ids.dl1}); - equal(msg.status, "success", "erase by id succeeded"); - - msg = yield runInExtension("waitForEvents", [ - {type: "onErased", data: ids.dl1}, - ]); - equal(msg.status, "success", "received onErased event"); - - msg = yield runInExtension("search", {}); - equal(msg.status, "success", "search succeded"); - equal(msg.result.length, 2, "search found 2 downloads"); - - msg = yield runInExtension("erase", {}); - equal(msg.status, "success", "erase everything succeeded"); - - msg = yield runInExtension("waitForEvents", [ - {type: "onErased", data: ids.dl2}, - {type: "onErased", data: ids.dl3}, - ], {inorder: false}); - equal(msg.status, "success", "received 2 onErased events"); - - msg = yield runInExtension("search", {}); - equal(msg.status, "success", "search succeded"); - equal(msg.result.length, 0, "search found 0 downloads"); -}); - -function loadImage(img, data) { - return new Promise((resolve) => { - img.src = data; - img.onload = resolve; - }); -} - -add_task(function* test_getFileIcon() { - let webNav = Services.appShell.createWindowlessBrowser(false); - let docShell = webNav.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDocShell); - - let system = Services.scriptSecurityManager.getSystemPrincipal(); - docShell.createAboutBlankContentViewer(system); - - let img = webNav.document.createElement("img"); - - let msg = yield runInExtension("download", {url: TXT_URL}); - equal(msg.status, "success", "download() succeeded"); - const id = msg.result; - - msg = yield runInExtension("getFileIcon", id); - equal(msg.status, "success", "getFileIcon() succeeded"); - yield loadImage(img, msg.result); - equal(img.height, 32, "returns an icon with the right height"); - equal(img.width, 32, "returns an icon with the right width"); - - msg = yield runInExtension("waitForEvents", [ - {type: "onCreated", data: {id, url: TXT_URL}}, - {type: "onChanged"}, - ]); - equal(msg.status, "success", "got events"); - - msg = yield runInExtension("getFileIcon", id); - equal(msg.status, "success", "getFileIcon() succeeded"); - yield loadImage(img, msg.result); - equal(img.height, 32, "returns an icon with the right height after download"); - equal(img.width, 32, "returns an icon with the right width after download"); - - msg = yield runInExtension("getFileIcon", id + 100); - equal(msg.status, "error", "getFileIcon() failed"); - ok(msg.errmsg.includes("Invalid download id"), "download id is invalid"); - - msg = yield runInExtension("getFileIcon", id, {size: 127}); - equal(msg.status, "success", "getFileIcon() succeeded"); - yield loadImage(img, msg.result); - equal(img.height, 127, "returns an icon with the right custom height"); - equal(img.width, 127, "returns an icon with the right custom width"); - - msg = yield runInExtension("getFileIcon", id, {size: 1}); - equal(msg.status, "success", "getFileIcon() succeeded"); - yield loadImage(img, msg.result); - equal(img.height, 1, "returns an icon with the right custom height"); - equal(img.width, 1, "returns an icon with the right custom width"); - - msg = yield runInExtension("getFileIcon", id, {size: "foo"}); - equal(msg.status, "error", "getFileIcon() fails"); - ok(msg.errmsg.includes("Error processing size"), "size is not a number"); - - msg = yield runInExtension("getFileIcon", id, {size: 0}); - equal(msg.status, "error", "getFileIcon() fails"); - ok(msg.errmsg.includes("Error processing size"), "size is too small"); - - msg = yield runInExtension("getFileIcon", id, {size: 128}); - equal(msg.status, "error", "getFileIcon() fails"); - ok(msg.errmsg.includes("Error processing size"), "size is too big"); - - webNav.close(); -}); - -add_task(function* cleanup() { - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_downloads_search.js b/toolkit/components/webextensions/test/xpcshell/test_ext_downloads_search.js deleted file mode 100644 index 4caa82456..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_downloads_search.js +++ /dev/null @@ -1,402 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -Cu.import("resource://gre/modules/Downloads.jsm"); - -const server = createHttpServer(); -server.registerDirectory("/data/", do_get_file("data")); - -const BASE = `http://localhost:${server.identity.primaryPort}/data`; -const TXT_FILE = "file_download.txt"; -const TXT_URL = BASE + "/" + TXT_FILE; -const TXT_LEN = 46; -const HTML_FILE = "file_download.html"; -const HTML_URL = BASE + "/" + HTML_FILE; -const HTML_LEN = 117; -const BIG_LEN = 1000; // something bigger both TXT_LEN and HTML_LEN - -function backgroundScript() { - let complete = new Map(); - - function waitForComplete(id) { - if (complete.has(id)) { - return complete.get(id).promise; - } - - let promise = new Promise(resolve => { - complete.set(id, {resolve}); - }); - complete.get(id).promise = promise; - return promise; - } - - browser.downloads.onChanged.addListener(change => { - if (change.state && change.state.current == "complete") { - // Make sure we have a promise. - waitForComplete(change.id); - complete.get(change.id).resolve(); - } - }); - - browser.test.onMessage.addListener(async (msg, ...args) => { - if (msg == "download.request") { - try { - let id = await browser.downloads.download(args[0]); - browser.test.sendMessage("download.done", {status: "success", id}); - } catch (error) { - browser.test.sendMessage("download.done", {status: "error", errmsg: error.message}); - } - } else if (msg == "search.request") { - try { - let downloads = await browser.downloads.search(args[0]); - browser.test.sendMessage("search.done", {status: "success", downloads}); - } catch (error) { - browser.test.sendMessage("search.done", {status: "error", errmsg: error.message}); - } - } else if (msg == "waitForComplete.request") { - await waitForComplete(args[0]); - browser.test.sendMessage("waitForComplete.done"); - } - }); - - browser.test.sendMessage("ready"); -} - -async function clearDownloads(callback) { - let list = await Downloads.getList(Downloads.ALL); - let downloads = await list.getAll(); - - await Promise.all(downloads.map(download => list.remove(download))); - - return downloads; -} - -add_task(function* test_search() { - const nsIFile = Ci.nsIFile; - let downloadDir = FileUtils.getDir("TmpD", ["downloads"]); - downloadDir.createUnique(nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - do_print(`downloadDir ${downloadDir.path}`); - - function downloadPath(filename) { - let path = downloadDir.clone(); - path.append(filename); - return path.path; - } - - Services.prefs.setIntPref("browser.download.folderList", 2); - Services.prefs.setComplexValue("browser.download.dir", nsIFile, downloadDir); - - do_register_cleanup(async () => { - Services.prefs.clearUserPref("browser.download.folderList"); - Services.prefs.clearUserPref("browser.download.dir"); - await cleanupDir(downloadDir); - await clearDownloads(); - }); - - yield clearDownloads().then(downloads => { - do_print(`removed ${downloads.length} pre-existing downloads from history`); - }); - - let extension = ExtensionTestUtils.loadExtension({ - background: backgroundScript, - manifest: { - permissions: ["downloads"], - }, - }); - - async function download(options) { - extension.sendMessage("download.request", options); - let result = await extension.awaitMessage("download.done"); - - if (result.status == "success") { - do_print(`wait for onChanged event to indicate ${result.id} is complete`); - extension.sendMessage("waitForComplete.request", result.id); - - await extension.awaitMessage("waitForComplete.done"); - } - - return result; - } - - function search(query) { - extension.sendMessage("search.request", query); - return extension.awaitMessage("search.done"); - } - - yield extension.startup(); - yield extension.awaitMessage("ready"); - - // Do some downloads... - const time1 = new Date(); - - let downloadIds = {}; - let msg = yield download({url: TXT_URL}); - equal(msg.status, "success", "download() succeeded"); - downloadIds.txt1 = msg.id; - - const TXT_FILE2 = "NewFile.txt"; - msg = yield download({url: TXT_URL, filename: TXT_FILE2}); - equal(msg.status, "success", "download() succeeded"); - downloadIds.txt2 = msg.id; - - const time2 = new Date(); - - msg = yield download({url: HTML_URL}); - equal(msg.status, "success", "download() succeeded"); - downloadIds.html1 = msg.id; - - const HTML_FILE2 = "renamed.html"; - msg = yield download({url: HTML_URL, filename: HTML_FILE2}); - equal(msg.status, "success", "download() succeeded"); - downloadIds.html2 = msg.id; - - const time3 = new Date(); - - // Search for each individual download and check - // the corresponding DownloadItem. - function* checkDownloadItem(id, expect) { - let item = yield search({id}); - equal(item.status, "success", "search() succeeded"); - equal(item.downloads.length, 1, "search() found exactly 1 download"); - - Object.keys(expect).forEach(function(field) { - equal(item.downloads[0][field], expect[field], `DownloadItem.${field} is correct"`); - }); - } - yield checkDownloadItem(downloadIds.txt1, { - url: TXT_URL, - filename: downloadPath(TXT_FILE), - mime: "text/plain", - state: "complete", - bytesReceived: TXT_LEN, - totalBytes: TXT_LEN, - fileSize: TXT_LEN, - exists: true, - }); - - yield checkDownloadItem(downloadIds.txt2, { - url: TXT_URL, - filename: downloadPath(TXT_FILE2), - mime: "text/plain", - state: "complete", - bytesReceived: TXT_LEN, - totalBytes: TXT_LEN, - fileSize: TXT_LEN, - exists: true, - }); - - yield checkDownloadItem(downloadIds.html1, { - url: HTML_URL, - filename: downloadPath(HTML_FILE), - mime: "text/html", - state: "complete", - bytesReceived: HTML_LEN, - totalBytes: HTML_LEN, - fileSize: HTML_LEN, - exists: true, - }); - - yield checkDownloadItem(downloadIds.html2, { - url: HTML_URL, - filename: downloadPath(HTML_FILE2), - mime: "text/html", - state: "complete", - bytesReceived: HTML_LEN, - totalBytes: HTML_LEN, - fileSize: HTML_LEN, - exists: true, - }); - - function* checkSearch(query, expected, description, exact) { - let item = yield search(query); - equal(item.status, "success", "search() succeeded"); - equal(item.downloads.length, expected.length, `search() for ${description} found exactly ${expected.length} downloads`); - - let receivedIds = item.downloads.map(i => i.id); - if (exact) { - receivedIds.forEach((id, idx) => { - equal(id, downloadIds[expected[idx]], `search() for ${description} returned ${expected[idx]} in position ${idx}`); - }); - } else { - Object.keys(downloadIds).forEach(key => { - const id = downloadIds[key]; - const thisExpected = expected.includes(key); - equal(receivedIds.includes(id), thisExpected, - `search() for ${description} ${thisExpected ? "includes" : "does not include"} ${key}`); - }); - } - } - - // Check that search with an invalid id returns nothing. - // NB: for now ids are not persistent and we start numbering them at 1 - // so a sufficiently large number will be unused. - const INVALID_ID = 1000; - yield checkSearch({id: INVALID_ID}, [], "invalid id"); - - // Check that search on url works. - yield checkSearch({url: TXT_URL}, ["txt1", "txt2"], "url"); - - // Check that regexp on url works. - const HTML_REGEX = "[downlad]{8}\.html+$"; - yield checkSearch({urlRegex: HTML_REGEX}, ["html1", "html2"], "url regexp"); - - // Check that compatible url+regexp works - yield checkSearch({url: HTML_URL, urlRegex: HTML_REGEX}, ["html1", "html2"], "compatible url+urlRegex"); - - // Check that incompatible url+regexp works - yield checkSearch({url: TXT_URL, urlRegex: HTML_REGEX}, [], "incompatible url+urlRegex"); - - // Check that search on filename works. - yield checkSearch({filename: downloadPath(TXT_FILE)}, ["txt1"], "filename"); - - // Check that regexp on filename works. - yield checkSearch({filenameRegex: HTML_REGEX}, ["html1"], "filename regex"); - - // Check that compatible filename+regexp works - yield checkSearch({filename: downloadPath(HTML_FILE), filenameRegex: HTML_REGEX}, ["html1"], "compatible filename+filename regex"); - - // Check that incompatible filename+regexp works - yield checkSearch({filename: downloadPath(TXT_FILE), filenameRegex: HTML_REGEX}, [], "incompatible filename+filename regex"); - - // Check that simple positive search terms work. - yield checkSearch({query: ["file_download"]}, ["txt1", "txt2", "html1", "html2"], - "term file_download"); - yield checkSearch({query: ["NewFile"]}, ["txt2"], "term NewFile"); - - // Check that positive search terms work case-insensitive. - yield checkSearch({query: ["nEwfILe"]}, ["txt2"], "term nEwfiLe"); - - // Check that negative search terms work. - yield checkSearch({query: ["-txt"]}, ["html1", "html2"], "term -txt"); - - // Check that positive and negative search terms together work. - yield checkSearch({query: ["html", "-renamed"]}, ["html1"], "postive and negative terms"); - - function* checkSearchWithDate(query, expected, description) { - const fields = Object.keys(query); - if (fields.length != 1 || !(query[fields[0]] instanceof Date)) { - throw new Error("checkSearchWithDate expects exactly one Date field"); - } - const field = fields[0]; - const date = query[field]; - - let newquery = {}; - - // Check as a Date - newquery[field] = date; - yield checkSearch(newquery, expected, `${description} as Date`); - - // Check as numeric milliseconds - newquery[field] = date.valueOf(); - yield checkSearch(newquery, expected, `${description} as numeric ms`); - - // Check as stringified milliseconds - newquery[field] = date.valueOf().toString(); - yield checkSearch(newquery, expected, `${description} as string ms`); - - // Check as ISO string - newquery[field] = date.toISOString(); - yield checkSearch(newquery, expected, `${description} as iso string`); - } - - // Check startedBefore - yield checkSearchWithDate({startedBefore: time1}, [], "before time1"); - yield checkSearchWithDate({startedBefore: time2}, ["txt1", "txt2"], "before time2"); - yield checkSearchWithDate({startedBefore: time3}, ["txt1", "txt2", "html1", "html2"], "before time3"); - - // Check startedAfter - yield checkSearchWithDate({startedAfter: time1}, ["txt1", "txt2", "html1", "html2"], "after time1"); - yield checkSearchWithDate({startedAfter: time2}, ["html1", "html2"], "after time2"); - yield checkSearchWithDate({startedAfter: time3}, [], "after time3"); - - // Check simple search on totalBytes - yield checkSearch({totalBytes: TXT_LEN}, ["txt1", "txt2"], "totalBytes"); - yield checkSearch({totalBytes: HTML_LEN}, ["html1", "html2"], "totalBytes"); - - // Check simple test on totalBytes{Greater,Less} - // (NB: TXT_LEN < HTML_LEN < BIG_LEN) - yield checkSearch({totalBytesGreater: 0}, ["txt1", "txt2", "html1", "html2"], "totalBytesGreater than 0"); - yield checkSearch({totalBytesGreater: TXT_LEN}, ["html1", "html2"], `totalBytesGreater than ${TXT_LEN}`); - yield checkSearch({totalBytesGreater: HTML_LEN}, [], `totalBytesGreater than ${HTML_LEN}`); - yield checkSearch({totalBytesLess: TXT_LEN}, [], `totalBytesLess than ${TXT_LEN}`); - yield checkSearch({totalBytesLess: HTML_LEN}, ["txt1", "txt2"], `totalBytesLess than ${HTML_LEN}`); - yield checkSearch({totalBytesLess: BIG_LEN}, ["txt1", "txt2", "html1", "html2"], `totalBytesLess than ${BIG_LEN}`); - - // Check good combinations of totalBytes*. - yield checkSearch({totalBytes: HTML_LEN, totalBytesGreater: TXT_LEN}, ["html1", "html2"], "totalBytes and totalBytesGreater"); - yield checkSearch({totalBytes: TXT_LEN, totalBytesLess: HTML_LEN}, ["txt1", "txt2"], "totalBytes and totalBytesGreater"); - yield checkSearch({totalBytes: HTML_LEN, totalBytesLess: BIG_LEN, totalBytesGreater: 0}, ["html1", "html2"], "totalBytes and totalBytesLess and totalBytesGreater"); - - // Check bad combination of totalBytes*. - yield checkSearch({totalBytesLess: TXT_LEN, totalBytesGreater: HTML_LEN}, [], "bad totalBytesLess, totalBytesGreater combination"); - yield checkSearch({totalBytes: TXT_LEN, totalBytesGreater: HTML_LEN}, [], "bad totalBytes, totalBytesGreater combination"); - yield checkSearch({totalBytes: HTML_LEN, totalBytesLess: TXT_LEN}, [], "bad totalBytes, totalBytesLess combination"); - - // Check mime. - yield checkSearch({mime: "text/plain"}, ["txt1", "txt2"], "mime text/plain"); - yield checkSearch({mime: "text/html"}, ["html1", "html2"], "mime text/htmlplain"); - yield checkSearch({mime: "video/webm"}, [], "mime video/webm"); - - // Check fileSize. - yield checkSearch({fileSize: TXT_LEN}, ["txt1", "txt2"], "fileSize"); - yield checkSearch({fileSize: HTML_LEN}, ["html1", "html2"], "fileSize"); - - // Fields like bytesReceived, paused, state, exists are meaningful - // for downloads that are in progress but have not yet completed. - // todo: add tests for these when we have better support for in-progress - // downloads (e.g., after pause(), resume() and cancel() are implemented) - - // Check multiple query properties. - // We could make this testing arbitrarily complicated... - // We already tested combining fields with obvious interactions above - // (e.g., filename and filenameRegex or startTime and startedBefore/After) - // so now just throw as many fields as we can at a single search and - // make sure a simple case still works. - yield checkSearch({ - url: TXT_URL, - urlRegex: "download", - filename: downloadPath(TXT_FILE), - filenameRegex: "download", - query: ["download"], - startedAfter: time1.valueOf().toString(), - startedBefore: time2.valueOf().toString(), - totalBytes: TXT_LEN, - totalBytesGreater: 0, - totalBytesLess: BIG_LEN, - mime: "text/plain", - fileSize: TXT_LEN, - }, ["txt1"], "many properties"); - - // Check simple orderBy (forward and backward). - yield checkSearch({orderBy: ["startTime"]}, ["txt1", "txt2", "html1", "html2"], "orderBy startTime", true); - yield checkSearch({orderBy: ["-startTime"]}, ["html2", "html1", "txt2", "txt1"], "orderBy -startTime", true); - - // Check orderBy with multiple fields. - // NB: TXT_URL and HTML_URL differ only in extension and .html precedes .txt - yield checkSearch({orderBy: ["url", "-startTime"]}, ["html2", "html1", "txt2", "txt1"], "orderBy with multiple fields", true); - - // Check orderBy with limit. - yield checkSearch({orderBy: ["url"], limit: 1}, ["html1"], "orderBy with limit", true); - - // Check bad arguments. - function* checkBadSearch(query, pattern, description) { - let item = yield search(query); - equal(item.status, "error", "search() failed"); - ok(pattern.test(item.errmsg), `error message for ${description} was correct (${item.errmsg}).`); - } - - yield checkBadSearch("myquery", /Incorrect argument type/, "query is not an object"); - yield checkBadSearch({bogus: "boo"}, /Unexpected property/, "query contains an unknown field"); - yield checkBadSearch({query: "query string"}, /Expected array/, "query.query is a string"); - yield checkBadSearch({startedBefore: "i am not a time"}, /Type error/, "query.startedBefore is not a valid time"); - yield checkBadSearch({startedAfter: "i am not a time"}, /Type error/, "query.startedAfter is not a valid time"); - yield checkBadSearch({endedBefore: "i am not a time"}, /Type error/, "query.endedBefore is not a valid time"); - yield checkBadSearch({endedAfter: "i am not a time"}, /Type error/, "query.endedAfter is not a valid time"); - yield checkBadSearch({urlRegex: "["}, /Invalid urlRegex/, "query.urlRegexp is not a valid regular expression"); - yield checkBadSearch({filenameRegex: "["}, /Invalid filenameRegex/, "query.filenameRegexp is not a valid regular expression"); - yield checkBadSearch({orderBy: "startTime"}, /Expected array/, "query.orderBy is not an array"); - yield checkBadSearch({orderBy: ["bogus"]}, /Invalid orderBy field/, "query.orderBy references a non-existent field"); - - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_experiments.js b/toolkit/components/webextensions/test/xpcshell/test_ext_experiments.js deleted file mode 100644 index bc6bfcd68..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_experiments.js +++ /dev/null @@ -1,175 +0,0 @@ -"use strict"; - -/* globals browser */ - -XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", - "resource://gre/modules/AddonManager.jsm"); - -function promiseAddonStartup() { - const {Management} = Cu.import("resource://gre/modules/Extension.jsm"); - - return new Promise(resolve => { - let listener = (evt, extension) => { - Management.off("startup", listener); - resolve(extension); - }; - - Management.on("startup", listener); - }); -} - -add_task(function* setup() { - yield ExtensionTestUtils.startAddonManager(); -}); - -add_task(function* test_experiments_api() { - let apiAddonFile = Extension.generateZipFile({ - "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="meh@experiments.addons.mozilla.org" - em:name="Meh Experiment" - em:type="256" - em:version="0.1" - em:description="Meh experiment" - em:creator="Mozilla"> - - <em:targetApplication> - <Description - em:id="xpcshell@tests.mozilla.org" - em:minVersion="48" - em:maxVersion="*"/> - </em:targetApplication> - </Description> - </RDF> - `, - - "api.js": String.raw` - Components.utils.import("resource://gre/modules/Services.jsm"); - - Services.obs.notifyObservers(null, "webext-api-loaded", ""); - - class API extends ExtensionAPI { - getAPI(context) { - return { - meh: { - hello(text) { - Services.obs.notifyObservers(null, "webext-api-hello", text); - } - } - } - } - } - `, - - "schema.json": [ - { - "namespace": "meh", - "description": "All full of meh.", - "permissions": ["experiments.meh"], - "functions": [ - { - "name": "hello", - "type": "function", - "description": "Hates you. This is all.", - "parameters": [ - {"type": "string", "name": "text"}, - ], - }, - ], - }, - ], - }); - - let addonFile = Extension.generateXPI({ - manifest: { - applications: {gecko: {id: "meh@web.extension"}}, - permissions: ["experiments.meh"], - }, - - background() { - // The test code below checks that hello() is called at the right - // time with the string "Here I am". Verify that the api schema is - // being correctly interpreted by calling hello() with bad arguments - // and only calling hello() with the magic string if the call with - // bad arguments throws. - try { - browser.meh.hello("I should not see this", "since two arguments are bad"); - } catch (err) { - browser.meh.hello("Here I am"); - } - }, - }); - - let boringAddonFile = Extension.generateXPI({ - manifest: { - applications: {gecko: {id: "boring@web.extension"}}, - }, - background() { - if (browser.meh) { - browser.meh.hello("Here I should not be"); - } - }, - }); - - do_register_cleanup(() => { - for (let file of [apiAddonFile, addonFile, boringAddonFile]) { - Services.obs.notifyObservers(file, "flush-cache-entry", null); - file.remove(false); - } - }); - - - let resolveHello; - let observer = (subject, topic, data) => { - if (topic == "webext-api-loaded") { - ok(!!resolveHello, "Should not see API loaded until dependent extension loads"); - } else if (topic == "webext-api-hello") { - resolveHello(data); - } - }; - - Services.obs.addObserver(observer, "webext-api-loaded", false); - Services.obs.addObserver(observer, "webext-api-hello", false); - do_register_cleanup(() => { - Services.obs.removeObserver(observer, "webext-api-loaded"); - Services.obs.removeObserver(observer, "webext-api-hello"); - }); - - - // Install API add-on. - let apiAddon = yield AddonManager.installTemporaryAddon(apiAddonFile); - - let {APIs} = Cu.import("resource://gre/modules/ExtensionManagement.jsm", {}); - ok(APIs.apis.has("meh"), "Should have meh API."); - - - // Install boring WebExtension add-on. - let boringAddon = yield AddonManager.installTemporaryAddon(boringAddonFile); - yield promiseAddonStartup(); - - - // Install interesting WebExtension add-on. - let promise = new Promise(resolve => { - resolveHello = resolve; - }); - - let addon = yield AddonManager.installTemporaryAddon(addonFile); - yield promiseAddonStartup(); - - let hello = yield promise; - equal(hello, "Here I am", "Should get hello from add-on"); - - // Cleanup. - apiAddon.uninstall(); - - boringAddon.userDisabled = true; - yield new Promise(do_execute_soon); - - equal(addon.appDisabled, true, "Add-on should be app-disabled after its dependency is removed."); - - addon.uninstall(); - boringAddon.uninstall(); -}); - diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_extension.js b/toolkit/components/webextensions/test/xpcshell/test_ext_extension.js deleted file mode 100644 index f18845f6a..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_extension.js +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_is_allowed_incognito_access() { - async function background() { - let allowed = await browser.extension.isAllowedIncognitoAccess(); - - browser.test.assertEq(true, allowed, "isAllowedIncognitoAccess is true"); - browser.test.notifyPass("isAllowedIncognitoAccess"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: {}, - }); - - yield extension.startup(); - yield extension.awaitFinish("isAllowedIncognitoAccess"); - yield extension.unload(); -}); - -add_task(function* test_in_incognito_context_false() { - function background() { - browser.test.assertEq(false, browser.extension.inIncognitoContext, "inIncognitoContext returned false"); - browser.test.notifyPass("inIncognitoContext"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: {}, - }); - - yield extension.startup(); - yield extension.awaitFinish("inIncognitoContext"); - yield extension.unload(); -}); - -add_task(function* test_is_allowed_file_scheme_access() { - async function background() { - let allowed = await browser.extension.isAllowedFileSchemeAccess(); - - browser.test.assertEq(false, allowed, "isAllowedFileSchemeAccess is false"); - browser.test.notifyPass("isAllowedFileSchemeAccess"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: {}, - }); - - yield extension.startup(); - yield extension.awaitFinish("isAllowedFileSchemeAccess"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_idle.js b/toolkit/components/webextensions/test/xpcshell/test_ext_idle.js deleted file mode 100644 index 89bcac217..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_idle.js +++ /dev/null @@ -1,202 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -Cu.import("resource://testing-common/MockRegistrar.jsm"); - -let idleService = { - _observers: new Set(), - _activity: { - addCalls: [], - removeCalls: [], - observerFires: [], - }, - _reset: function() { - this._observers.clear(); - this._activity.addCalls = []; - this._activity.removeCalls = []; - this._activity.observerFires = []; - }, - _fireObservers: function(state) { - for (let observer of this._observers.values()) { - observer.observe(observer, state, null); - this._activity.observerFires.push(state); - } - }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIIdleService]), - idleTime: 19999, - addIdleObserver: function(observer, time) { - this._observers.add(observer); - this._activity.addCalls.push(time); - }, - removeIdleObserver: function(observer, time) { - this._observers.delete(observer); - this._activity.removeCalls.push(time); - }, -}; - -function checkActivity(expectedActivity) { - let {expectedAdd, expectedRemove, expectedFires} = expectedActivity; - let {addCalls, removeCalls, observerFires} = idleService._activity; - equal(expectedAdd.length, addCalls.length, "idleService.addIdleObserver was called the expected number of times"); - equal(expectedRemove.length, removeCalls.length, "idleService.removeIdleObserver was called the expected number of times"); - equal(expectedFires.length, observerFires.length, "idle observer was fired the expected number of times"); - deepEqual(addCalls, expectedAdd, "expected interval passed to idleService.addIdleObserver"); - deepEqual(removeCalls, expectedRemove, "expected interval passed to idleService.removeIdleObserver"); - deepEqual(observerFires, expectedFires, "expected topic passed to idle observer"); -} - -add_task(function* setup() { - let fakeIdleService = MockRegistrar.register("@mozilla.org/widget/idleservice;1", idleService); - do_register_cleanup(() => { - MockRegistrar.unregister(fakeIdleService); - }); -}); - -add_task(function* testQueryStateActive() { - function background() { - browser.idle.queryState(20).then(status => { - browser.test.assertEq("active", status, "Idle status is active"); - browser.test.notifyPass("idle"); - }, - err => { - browser.test.fail(`Error: ${err} :: ${err.stack}`); - browser.test.notifyFail("idle"); - }); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - permissions: ["idle"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("idle"); - yield extension.unload(); -}); - -add_task(function* testQueryStateIdle() { - function background() { - browser.idle.queryState(15).then(status => { - browser.test.assertEq("idle", status, "Idle status is idle"); - browser.test.notifyPass("idle"); - }, - err => { - browser.test.fail(`Error: ${err} :: ${err.stack}`); - browser.test.notifyFail("idle"); - }); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - permissions: ["idle"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("idle"); - yield extension.unload(); -}); - -add_task(function* testOnlySetDetectionInterval() { - function background() { - browser.idle.setDetectionInterval(99); - browser.test.sendMessage("detectionIntervalSet"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - permissions: ["idle"], - }, - }); - - idleService._reset(); - yield extension.startup(); - yield extension.awaitMessage("detectionIntervalSet"); - idleService._fireObservers("idle"); - checkActivity({expectedAdd: [], expectedRemove: [], expectedFires: []}); - yield extension.unload(); -}); - -add_task(function* testSetDetectionIntervalBeforeAddingListener() { - function background() { - browser.idle.setDetectionInterval(99); - browser.idle.onStateChanged.addListener(newState => { - browser.test.assertEq("idle", newState, "listener fired with the expected state"); - browser.test.sendMessage("listenerFired"); - }); - browser.test.sendMessage("listenerAdded"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - permissions: ["idle"], - }, - }); - - idleService._reset(); - yield extension.startup(); - yield extension.awaitMessage("listenerAdded"); - idleService._fireObservers("idle"); - yield extension.awaitMessage("listenerFired"); - checkActivity({expectedAdd: [99], expectedRemove: [], expectedFires: ["idle"]}); - yield extension.unload(); -}); - -add_task(function* testSetDetectionIntervalAfterAddingListener() { - function background() { - browser.idle.onStateChanged.addListener(newState => { - browser.test.assertEq("idle", newState, "listener fired with the expected state"); - browser.test.sendMessage("listenerFired"); - }); - browser.idle.setDetectionInterval(99); - browser.test.sendMessage("detectionIntervalSet"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - permissions: ["idle"], - }, - }); - - idleService._reset(); - yield extension.startup(); - yield extension.awaitMessage("detectionIntervalSet"); - idleService._fireObservers("idle"); - yield extension.awaitMessage("listenerFired"); - checkActivity({expectedAdd: [60, 99], expectedRemove: [60], expectedFires: ["idle"]}); - yield extension.unload(); -}); - -add_task(function* testOnlyAddingListener() { - function background() { - browser.idle.onStateChanged.addListener(newState => { - browser.test.assertEq("active", newState, "listener fired with the expected state"); - browser.test.sendMessage("listenerFired"); - }); - browser.test.sendMessage("listenerAdded"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - permissions: ["idle"], - }, - }); - - idleService._reset(); - yield extension.startup(); - yield extension.awaitMessage("listenerAdded"); - idleService._fireObservers("active"); - yield extension.awaitMessage("listenerFired"); - // check that "idle-daily" topic does not cause a listener to fire - idleService._fireObservers("idle-daily"); - checkActivity({expectedAdd: [60], expectedRemove: [], expectedFires: ["active", "idle-daily"]}); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_json_parser.js b/toolkit/components/webextensions/test/xpcshell/test_ext_json_parser.js deleted file mode 100644 index 652f41315..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_json_parser.js +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_json_parser() { - const ID = "json@test.web.extension"; - - let xpi = Extension.generateXPI({ - files: { - "manifest.json": String.raw`{ - // This is a manifest. - "applications": {"gecko": {"id": "${ID}"}}, - "name": "This \" is // not a comment", - "version": "0.1\\" // , "description": "This is not a description" - }`, - }, - }); - - let expectedManifest = { - "applications": {"gecko": {"id": ID}}, - "name": "This \" is // not a comment", - "version": "0.1\\", - }; - - let fileURI = Services.io.newFileURI(xpi); - let uri = NetUtil.newURI(`jar:${fileURI.spec}!/`); - - let extension = new ExtensionData(uri); - - yield extension.readManifest(); - - Assert.deepEqual(extension.rawManifest, expectedManifest, - "Manifest with correctly-filtered comments"); - - Services.obs.notifyObservers(xpi, "flush-cache-entry", null); - xpi.remove(false); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_legacy_extension_context.js b/toolkit/components/webextensions/test/xpcshell/test_ext_legacy_extension_context.js deleted file mode 100644 index 770851472..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_legacy_extension_context.js +++ /dev/null @@ -1,168 +0,0 @@ -"use strict"; - -/* globals browser */ - -Cu.import("resource://gre/modules/Extension.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -const {LegacyExtensionContext} = Cu.import("resource://gre/modules/LegacyExtensionsUtils.jsm"); - -/** - * This test case ensures that LegacyExtensionContext instances: - * - expose the expected API object and can join the messaging - * of a webextension given its addon id - * - the exposed API object can receive a port related to a `runtime.connect` - * Port created in the webextension's background page - * - the received Port instance can exchange messages with the background page - * - the received Port receive a disconnect event when the webextension is - * shutting down - */ -add_task(function* test_legacy_extension_context() { - function background() { - let bgURL = window.location.href; - - let extensionInfo = { - bgURL, - // Extract the assigned uuid from the background page url. - uuid: window.location.hostname, - }; - - browser.test.sendMessage("webextension-ready", extensionInfo); - - let port; - - browser.test.onMessage.addListener(async msg => { - if (msg == "do-send-message") { - let reply = await browser.runtime.sendMessage("webextension -> legacy_extension message"); - - browser.test.assertEq("legacy_extension -> webextension reply", reply, - "Got the expected message from the LegacyExtensionContext"); - browser.test.sendMessage("got-reply-message"); - } else if (msg == "do-connect") { - port = browser.runtime.connect(); - - port.onMessage.addListener(portMsg => { - browser.test.assertEq("legacy_extension -> webextension port message", portMsg, - "Got the expected message from the LegacyExtensionContext"); - port.postMessage("webextension -> legacy_extension port message"); - }); - } else if (msg == "do-disconnect") { - port.disconnect(); - } - }); - } - - let extensionData = { - background, - }; - - let extension = Extension.generate(extensionData); - - let waitForExtensionInfo = new Promise((resolve, reject) => { - extension.on("test-message", function testMessageListener(kind, msg, ...args) { - if (msg != "webextension-ready") { - reject(new Error(`Got an unexpected test-message: ${msg}`)); - } else { - extension.off("test-message", testMessageListener); - resolve(args[0]); - } - }); - }); - - // Connect to the target extension as an external context - // using the given custom sender info. - let legacyContext; - - extension.on("startup", function onStartup() { - extension.off("startup", onStartup); - legacyContext = new LegacyExtensionContext(extension); - extension.callOnClose({ - close: () => legacyContext.unload(), - }); - }); - - yield extension.startup(); - - let extensionInfo = yield waitForExtensionInfo; - - equal(legacyContext.envType, "legacy_extension", - "LegacyExtensionContext instance has the expected type"); - - ok(legacyContext.api, "Got the expected API object"); - ok(legacyContext.api.browser, "Got the expected browser property"); - - let waitMessage = new Promise(resolve => { - const {browser} = legacyContext.api; - browser.runtime.onMessage.addListener((singleMsg, msgSender) => { - resolve({singleMsg, msgSender}); - - // Send a reply to the sender. - return Promise.resolve("legacy_extension -> webextension reply"); - }); - }); - - extension.testMessage("do-send-message"); - - let {singleMsg, msgSender} = yield waitMessage; - equal(singleMsg, "webextension -> legacy_extension message", - "Got the expected message"); - ok(msgSender, "Got a message sender object"); - - equal(msgSender.id, extension.id, "The sender has the expected id property"); - equal(msgSender.url, extensionInfo.bgURL, "The sender has the expected url property"); - - // Wait confirmation that the reply has been received. - yield new Promise((resolve, reject) => { - extension.on("test-message", function testMessageListener(kind, msg, ...args) { - if (msg != "got-reply-message") { - reject(new Error(`Got an unexpected test-message: ${msg}`)); - } else { - extension.off("test-message", testMessageListener); - resolve(); - } - }); - }); - - let waitConnectPort = new Promise(resolve => { - let {browser} = legacyContext.api; - browser.runtime.onConnect.addListener(port => { - resolve(port); - }); - }); - - extension.testMessage("do-connect"); - - let port = yield waitConnectPort; - - ok(port, "Got the Port API object"); - ok(port.sender, "The port has a sender property"); - equal(port.sender.id, extension.id, - "The port sender has the expected id property"); - equal(port.sender.url, extensionInfo.bgURL, - "The port sender has the expected url property"); - - let waitPortMessage = new Promise(resolve => { - port.onMessage.addListener((msg) => { - resolve(msg); - }); - }); - - port.postMessage("legacy_extension -> webextension port message"); - - let msg = yield waitPortMessage; - - equal(msg, "webextension -> legacy_extension port message", - "LegacyExtensionContext received the expected message from the webextension"); - - let waitForDisconnect = new Promise(resolve => { - port.onDisconnect.addListener(resolve); - }); - - extension.testMessage("do-disconnect"); - - yield waitForDisconnect; - - do_print("Got the disconnect event on unload"); - - yield extension.shutdown(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_legacy_extension_embedding.js b/toolkit/components/webextensions/test/xpcshell/test_ext_legacy_extension_embedding.js deleted file mode 100644 index ea5d78524..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_legacy_extension_embedding.js +++ /dev/null @@ -1,188 +0,0 @@ -"use strict"; - -/* globals browser */ - -Cu.import("resource://gre/modules/LegacyExtensionsUtils.jsm"); - -// Import EmbeddedExtensionManager to be able to check that the -// tacked instances are cleared after the embedded extension shutdown. -const { - EmbeddedExtensionManager, -} = Cu.import("resource://gre/modules/LegacyExtensionsUtils.jsm", {}); - -/** - * This test case ensures that the LegacyExtensionsUtils.EmbeddedExtension: - * - load the embedded webextension resources from a "/webextension/" dir - * inside the XPI. - * - EmbeddedExtension.prototype.api returns an API object which exposes - * a working `runtime.onConnect` event object (e.g. the API can receive a port - * when the embedded webextension is started and it can exchange messages - * with the background page). - * - EmbeddedExtension.prototype.startup/shutdown methods manage the embedded - * webextension lifecycle as expected. - */ -add_task(function* test_embedded_webextension_utils() { - function backgroundScript() { - let port = browser.runtime.connect(); - - port.onMessage.addListener((msg) => { - if (msg == "legacy_extension -> webextension") { - port.postMessage("webextension -> legacy_extension"); - port.disconnect(); - } - }); - } - - const id = "@test.embedded.web.extension"; - - // Extensions.generateXPI is used here (and in the other hybrid addons tests in this same - // test dir) to be able to generate an xpi with the directory layout that we expect from - // an hybrid legacy+webextension addon (where all the embedded webextension resources are - // loaded from a 'webextension/' directory). - let fakeHybridAddonFile = Extension.generateZipFile({ - "webextension/manifest.json": { - applications: {gecko: {id}}, - name: "embedded webextension name", - manifest_version: 2, - version: "1.0", - background: { - scripts: ["bg.js"], - }, - }, - "webextension/bg.js": `new ${backgroundScript}`, - }); - - // Remove the generated xpi file and flush the its jar cache - // on cleanup. - do_register_cleanup(() => { - Services.obs.notifyObservers(fakeHybridAddonFile, "flush-cache-entry", null); - fakeHybridAddonFile.remove(false); - }); - - let fileURI = Services.io.newFileURI(fakeHybridAddonFile); - let resourceURI = Services.io.newURI(`jar:${fileURI.spec}!/`, null, null); - - let embeddedExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({ - id, resourceURI, - }); - - ok(embeddedExtension, "Got the embeddedExtension object"); - - equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 1, - "Got the expected number of tracked embedded extension instances"); - - do_print("waiting embeddedExtension.startup"); - let embeddedExtensionAPI = yield embeddedExtension.startup(); - ok(embeddedExtensionAPI, "Got the embeddedExtensionAPI object"); - - let waitConnectPort = new Promise(resolve => { - let {browser} = embeddedExtensionAPI; - browser.runtime.onConnect.addListener(port => { - resolve(port); - }); - }); - - let port = yield waitConnectPort; - - ok(port, "Got the Port API object"); - - let waitPortMessage = new Promise(resolve => { - port.onMessage.addListener((msg) => { - resolve(msg); - }); - }); - - port.postMessage("legacy_extension -> webextension"); - - let msg = yield waitPortMessage; - - equal(msg, "webextension -> legacy_extension", - "LegacyExtensionContext received the expected message from the webextension"); - - let waitForDisconnect = new Promise(resolve => { - port.onDisconnect.addListener(resolve); - }); - - do_print("Wait for the disconnect port event"); - yield waitForDisconnect; - do_print("Got the disconnect port event"); - - yield embeddedExtension.shutdown(); - - equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 0, - "EmbeddedExtension instances has been untracked from the EmbeddedExtensionManager"); -}); - -function* createManifestErrorTestCase(id, xpi, expectedError) { - // Remove the generated xpi file and flush the its jar cache - // on cleanup. - do_register_cleanup(() => { - Services.obs.notifyObservers(xpi, "flush-cache-entry", null); - xpi.remove(false); - }); - - let fileURI = Services.io.newFileURI(xpi); - let resourceURI = Services.io.newURI(`jar:${fileURI.spec}!/`, null, null); - - let embeddedExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({ - id, resourceURI, - }); - - yield Assert.rejects(embeddedExtension.startup(), expectedError, - "embedded extension startup rejected"); - - // Shutdown a "never-started" addon with an embedded webextension should not - // raise any exception, and if it does this test will fail. - yield embeddedExtension.shutdown(); -} - -add_task(function* test_startup_error_empty_manifest() { - const id = "empty-manifest@test.embedded.web.extension"; - const files = { - "webextension/manifest.json": ``, - }; - const expectedError = "(NS_BASE_STREAM_CLOSED)"; - - let fakeHybridAddonFile = Extension.generateZipFile(files); - - yield createManifestErrorTestCase(id, fakeHybridAddonFile, expectedError); -}); - -add_task(function* test_startup_error_invalid_json_manifest() { - const id = "invalid-json-manifest@test.embedded.web.extension"; - const files = { - "webextension/manifest.json": `{ "name": }`, - }; - const expectedError = "JSON.parse:"; - - let fakeHybridAddonFile = Extension.generateZipFile(files); - - yield createManifestErrorTestCase(id, fakeHybridAddonFile, expectedError); -}); - -add_task(function* test_startup_error_blocking_validation_errors() { - const id = "blocking-manifest-validation-error@test.embedded.web.extension"; - const files = { - "webextension/manifest.json": { - name: "embedded webextension name", - manifest_version: 2, - version: "1.0", - background: { - scripts: {}, - }, - }, - }; - - function expectedError(actual) { - if (actual.errors && actual.errors.length == 1 && - actual.errors[0].startsWith("Reading manifest:")) { - return true; - } - - return false; - } - - let fakeHybridAddonFile = Extension.generateZipFile(files); - - yield createManifestErrorTestCase(id, fakeHybridAddonFile, expectedError); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_localStorage.js b/toolkit/components/webextensions/test/xpcshell/test_ext_localStorage.js deleted file mode 100644 index 0f0b41085..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_localStorage.js +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -function backgroundScript() { - let hasRun = localStorage.getItem("has-run"); - let result; - if (!hasRun) { - localStorage.setItem("has-run", "yup"); - localStorage.setItem("test-item", "item1"); - result = "item1"; - } else { - let data = localStorage.getItem("test-item"); - if (data == "item1") { - localStorage.setItem("test-item", "item2"); - result = "item2"; - } else if (data == "item2") { - localStorage.removeItem("test-item"); - result = "deleted"; - } else if (!data) { - localStorage.clear(); - result = "cleared"; - } - } - browser.test.sendMessage("result", result); - browser.test.notifyPass("localStorage"); -} - -const ID = "test-webextension@mozilla.com"; -let extensionData = { - manifest: {applications: {gecko: {id: ID}}}, - background: backgroundScript, -}; - -add_task(function* test_localStorage() { - const RESULTS = ["item1", "item2", "deleted", "cleared", "item1"]; - - for (let expected of RESULTS) { - let extension = ExtensionTestUtils.loadExtension(extensionData); - - yield extension.startup(); - - let actual = yield extension.awaitMessage("result"); - - yield extension.awaitFinish("localStorage"); - yield extension.unload(); - - equal(actual, expected, "got expected localStorage data"); - } -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_management.js b/toolkit/components/webextensions/test/xpcshell/test_ext_management.js deleted file mode 100644 index b19554a57..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_management.js +++ /dev/null @@ -1,20 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_management_schema() { - function background() { - browser.test.assertTrue(browser.management, "browser.management API exists"); - browser.test.notifyPass("management-schema"); - } - - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - permissions: ["management"], - }, - background: `(${background})()`, - }); - yield extension.startup(); - yield extension.awaitFinish("management-schema"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_management_uninstall_self.js b/toolkit/components/webextensions/test/xpcshell/test_ext_management_uninstall_self.js deleted file mode 100644 index 7d80a9c23..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_management_uninstall_self.js +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -Cu.import("resource://gre/modules/AddonManager.jsm"); -Cu.import("resource://testing-common/AddonTestUtils.jsm"); -Cu.import("resource://testing-common/MockRegistrar.jsm"); - -const {promiseAddonByID} = AddonTestUtils; -const id = "uninstall_self_test@tests.mozilla.com"; - -const manifest = { - applications: { - gecko: { - id, - }, - }, - name: "test extension name", - version: "1.0", -}; - -const waitForUninstalled = () => new Promise(resolve => { - const listener = { - onUninstalled: (addon) => { - equal(addon.id, id, "The expected add-on has been uninstalled"); - AddonManager.getAddonByID(addon.id, checkedAddon => { - equal(checkedAddon, null, "Add-on no longer exists"); - AddonManager.removeAddonListener(listener); - resolve(); - }); - }, - }; - AddonManager.addAddonListener(listener); -}); - -let promptService = { - _response: null, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptService]), - confirmEx: function(...args) { - this._confirmExArgs = args; - return this._response; - }, -}; - -add_task(function* setup() { - let fakePromptService = MockRegistrar.register("@mozilla.org/embedcomp/prompt-service;1", promptService); - do_register_cleanup(() => { - MockRegistrar.unregister(fakePromptService); - }); - yield ExtensionTestUtils.startAddonManager(); -}); - -add_task(function* test_management_uninstall_no_prompt() { - function background() { - browser.test.onMessage.addListener(msg => { - browser.management.uninstallSelf(); - }); - } - - let extension = ExtensionTestUtils.loadExtension({ - manifest, - background, - useAddonManager: "temporary", - }); - - yield extension.startup(); - let addon = yield promiseAddonByID(id); - notEqual(addon, null, "Add-on is installed"); - extension.sendMessage("uninstall"); - yield waitForUninstalled(); - yield extension.markUnloaded(); - Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry", null); -}); - -add_task(function* test_management_uninstall_prompt_uninstall() { - promptService._response = 0; - - function background() { - browser.test.onMessage.addListener(msg => { - browser.management.uninstallSelf({showConfirmDialog: true}); - }); - } - - let extension = ExtensionTestUtils.loadExtension({ - manifest, - background, - useAddonManager: "temporary", - }); - - yield extension.startup(); - let addon = yield promiseAddonByID(id); - notEqual(addon, null, "Add-on is installed"); - extension.sendMessage("uninstall"); - yield waitForUninstalled(); - yield extension.markUnloaded(); - - // Test localization strings - equal(promptService._confirmExArgs[1], `Uninstall ${manifest.name}`); - equal(promptService._confirmExArgs[2], - `The extension “${manifest.name}†is requesting to be uninstalled. What would you like to do?`); - equal(promptService._confirmExArgs[4], "Uninstall"); - equal(promptService._confirmExArgs[5], "Keep Installed"); - Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry", null); -}); - -add_task(function* test_management_uninstall_prompt_keep() { - promptService._response = 1; - - function background() { - browser.test.onMessage.addListener(async msg => { - await browser.test.assertRejects( - browser.management.uninstallSelf({showConfirmDialog: true}), - "User cancelled uninstall of extension", - "Expected rejection when user declines uninstall"); - - browser.test.sendMessage("uninstall-rejected"); - }); - } - - let extension = ExtensionTestUtils.loadExtension({ - manifest, - background, - useAddonManager: "temporary", - }); - - yield extension.startup(); - let addon = yield promiseAddonByID(id); - notEqual(addon, null, "Add-on is installed"); - extension.sendMessage("uninstall"); - yield extension.awaitMessage("uninstall-rejected"); - addon = yield promiseAddonByID(id); - notEqual(addon, null, "Add-on remains installed"); - yield extension.unload(); - Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry", null); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_manifest_content_security_policy.js b/toolkit/components/webextensions/test/xpcshell/test_ext_manifest_content_security_policy.js deleted file mode 100644 index 2b0084980..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_manifest_content_security_policy.js +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - - -add_task(function* test_manifest_csp() { - let normalized = yield ExtensionTestUtils.normalizeManifest({ - "content_security_policy": "script-src 'self'; object-src 'none'", - }); - - equal(normalized.error, undefined, "Should not have an error"); - equal(normalized.errors.length, 0, "Should not have warnings"); - equal(normalized.value.content_security_policy, - "script-src 'self'; object-src 'none'", - "Should have the expected poilcy string"); - - - normalized = yield ExtensionTestUtils.normalizeManifest({ - "content_security_policy": "object-src 'none'", - }); - - equal(normalized.error, undefined, "Should not have an error"); - - Assert.deepEqual(normalized.errors, - ["Error processing content_security_policy: SyntaxError: Policy is missing a required \u2018script-src\u2019 directive"], - "Should have the expected warning"); - - equal(normalized.value.content_security_policy, null, - "Invalid policy string should be omitted"); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_manifest_incognito.js b/toolkit/components/webextensions/test/xpcshell/test_ext_manifest_incognito.js deleted file mode 100644 index 94649692e..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_manifest_incognito.js +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - - -add_task(function* test_manifest_incognito() { - let normalized = yield ExtensionTestUtils.normalizeManifest({ - "incognito": "spanning", - }); - - equal(normalized.error, undefined, "Should not have an error"); - equal(normalized.errors.length, 0, "Should not have warnings"); - equal(normalized.value.incognito, - "spanning", - "Should have the expected incognito string"); - - normalized = yield ExtensionTestUtils.normalizeManifest({ - "incognito": "split", - }); - - equal(normalized.error, undefined, "Should not have an error"); - Assert.deepEqual(normalized.errors, - ['Error processing incognito: Invalid enumeration value "split"'], - "Should have the expected warning"); - equal(normalized.value.incognito, null, - "Invalid incognito string should be omitted"); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_manifest_minimum_chrome_version.js b/toolkit/components/webextensions/test/xpcshell/test_ext_manifest_minimum_chrome_version.js deleted file mode 100644 index fad5661bb..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_manifest_minimum_chrome_version.js +++ /dev/null @@ -1,13 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - - -add_task(function* test_manifest_minimum_chrome_version() { - let normalized = yield ExtensionTestUtils.normalizeManifest({ - "minimum_chrome_version": "42", - }); - - equal(normalized.error, undefined, "Should not have an error"); - equal(normalized.errors.length, 0, "Should not have warnings"); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_native_messaging.js b/toolkit/components/webextensions/test/xpcshell/test_ext_native_messaging.js deleted file mode 100644 index 5a6b628f5..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_native_messaging.js +++ /dev/null @@ -1,514 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -/* globals chrome */ - -const PREF_MAX_READ = "webextensions.native-messaging.max-input-message-bytes"; -const PREF_MAX_WRITE = "webextensions.native-messaging.max-output-message-bytes"; - -const ECHO_BODY = String.raw` - import struct - import sys - - while True: - rawlen = sys.stdin.read(4) - if len(rawlen) == 0: - sys.exit(0) - msglen = struct.unpack('@I', rawlen)[0] - msg = sys.stdin.read(msglen) - - sys.stdout.write(struct.pack('@I', msglen)) - sys.stdout.write(msg) -`; - -const INFO_BODY = String.raw` - import json - import os - import struct - import sys - - msg = json.dumps({"args": sys.argv, "cwd": os.getcwd()}) - sys.stdout.write(struct.pack('@I', len(msg))) - sys.stdout.write(msg) - sys.exit(0) -`; - -const STDERR_LINES = ["hello stderr", "this should be a separate line"]; -let STDERR_MSG = STDERR_LINES.join("\\n"); - -const STDERR_BODY = String.raw` - import sys - sys.stderr.write("${STDERR_MSG}") -`; - -const SCRIPTS = [ - { - name: "echo", - description: "a native app that echoes back messages it receives", - script: ECHO_BODY.replace(/^ {2}/gm, ""), - }, - { - name: "info", - description: "a native app that gives some info about how it was started", - script: INFO_BODY.replace(/^ {2}/gm, ""), - }, - { - name: "stderr", - description: "a native app that writes to stderr and then exits", - script: STDERR_BODY.replace(/^ {2}/gm, ""), - }, -]; - -add_task(function* setup() { - yield setupHosts(SCRIPTS); -}); - -// Test the basic operation of native messaging with a simple -// script that echoes back whatever message is sent to it. -add_task(function* test_happy_path() { - function background() { - let port = browser.runtime.connectNative("echo"); - port.onMessage.addListener(msg => { - browser.test.sendMessage("message", msg); - }); - browser.test.onMessage.addListener((what, payload) => { - if (what == "send") { - if (payload._json) { - let json = payload._json; - payload.toJSON = () => json; - delete payload._json; - } - port.postMessage(payload); - } - }); - browser.test.sendMessage("ready"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - yield extension.awaitMessage("ready"); - const tests = [ - { - data: "this is a string", - what: "simple string", - }, - { - data: "Ðто юникода", - what: "unicode string", - }, - { - data: {test: "hello"}, - what: "simple object", - }, - { - data: { - what: "An object with a few properties", - number: 123, - bool: true, - nested: {what: "another object"}, - }, - what: "object with several properties", - }, - - { - data: { - ignoreme: true, - _json: {data: "i have a tojson method"}, - }, - expected: {data: "i have a tojson method"}, - what: "object with toJSON() method", - }, - ]; - for (let test of tests) { - extension.sendMessage("send", test.data); - let response = yield extension.awaitMessage("message"); - let expected = test.expected || test.data; - deepEqual(response, expected, `Echoed a message of type ${test.what}`); - } - - let procCount = yield getSubprocessCount(); - equal(procCount, 1, "subprocess is still running"); - let exitPromise = waitForSubprocessExit(); - yield extension.unload(); - yield exitPromise; -}); - -if (AppConstants.platform == "win") { - // "relative.echo" has a relative path in the host manifest. - add_task(function* test_relative_path() { - function background() { - let port = browser.runtime.connectNative("relative.echo"); - let MSG = "test relative echo path"; - port.onMessage.addListener(msg => { - browser.test.assertEq(MSG, msg, "Got expected message back"); - browser.test.sendMessage("done"); - }); - port.postMessage(MSG); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - yield extension.awaitMessage("done"); - - let procCount = yield getSubprocessCount(); - equal(procCount, 1, "subprocess is still running"); - let exitPromise = waitForSubprocessExit(); - yield extension.unload(); - yield exitPromise; - }); -} - -// Test sendNativeMessage() -add_task(function* test_sendNativeMessage() { - async function background() { - let MSG = {test: "hello world"}; - - // Check error handling - await browser.test.assertRejects( - browser.runtime.sendNativeMessage("nonexistent", MSG), - /Attempt to postMessage on disconnected port/, - "sendNativeMessage() to a nonexistent app failed"); - - // Check regular message exchange - let reply = await browser.runtime.sendNativeMessage("echo", MSG); - - let expected = JSON.stringify(MSG); - let received = JSON.stringify(reply); - browser.test.assertEq(expected, received, "Received echoed native message"); - - browser.test.sendMessage("finished"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - yield extension.awaitMessage("finished"); - - // With sendNativeMessage(), the subprocess should be disconnected - // after exchanging a single message. - yield waitForSubprocessExit(); - - yield extension.unload(); -}); - -// Test calling Port.disconnect() -add_task(function* test_disconnect() { - function background() { - let port = browser.runtime.connectNative("echo"); - port.onMessage.addListener((msg, msgPort) => { - browser.test.assertEq(port, msgPort, "onMessage handler should receive the port as the second argument"); - browser.test.sendMessage("message", msg); - }); - port.onDisconnect.addListener(msgPort => { - browser.test.fail("onDisconnect should not be called for disconnect()"); - }); - browser.test.onMessage.addListener((what, payload) => { - if (what == "send") { - if (payload._json) { - let json = payload._json; - payload.toJSON = () => json; - delete payload._json; - } - port.postMessage(payload); - } else if (what == "disconnect") { - try { - port.disconnect(); - browser.test.sendMessage("disconnect-result", {success: true}); - } catch (err) { - browser.test.sendMessage("disconnect-result", { - success: false, - errmsg: err.message, - }); - } - } - }); - browser.test.sendMessage("ready"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - yield extension.awaitMessage("ready"); - - extension.sendMessage("send", "test"); - let response = yield extension.awaitMessage("message"); - equal(response, "test", "Echoed a string"); - - let procCount = yield getSubprocessCount(); - equal(procCount, 1, "subprocess is running"); - - extension.sendMessage("disconnect"); - response = yield extension.awaitMessage("disconnect-result"); - equal(response.success, true, "disconnect succeeded"); - - do_print("waiting for subprocess to exit"); - yield waitForSubprocessExit(); - procCount = yield getSubprocessCount(); - equal(procCount, 0, "subprocess is no longer running"); - - extension.sendMessage("disconnect"); - response = yield extension.awaitMessage("disconnect-result"); - equal(response.success, true, "second call to disconnect silently ignored"); - - yield extension.unload(); -}); - -// Test the limit on message size for writing -add_task(function* test_write_limit() { - Services.prefs.setIntPref(PREF_MAX_WRITE, 10); - function clearPref() { - Services.prefs.clearUserPref(PREF_MAX_WRITE); - } - do_register_cleanup(clearPref); - - function background() { - const PAYLOAD = "0123456789A"; - let port = browser.runtime.connectNative("echo"); - try { - port.postMessage(PAYLOAD); - browser.test.sendMessage("result", null); - } catch (ex) { - browser.test.sendMessage("result", ex.message); - } - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - - let errmsg = yield extension.awaitMessage("result"); - notEqual(errmsg, null, "native postMessage() failed for overly large message"); - - yield extension.unload(); - yield waitForSubprocessExit(); - - clearPref(); -}); - -// Test the limit on message size for reading -add_task(function* test_read_limit() { - Services.prefs.setIntPref(PREF_MAX_READ, 10); - function clearPref() { - Services.prefs.clearUserPref(PREF_MAX_READ); - } - do_register_cleanup(clearPref); - - function background() { - const PAYLOAD = "0123456789A"; - let port = browser.runtime.connectNative("echo"); - port.onDisconnect.addListener(msgPort => { - browser.test.assertEq(port, msgPort, "onDisconnect handler should receive the port as the first argument"); - browser.test.assertEq("Native application tried to send a message of 13 bytes, which exceeds the limit of 10 bytes.", port.error && port.error.message); - browser.test.sendMessage("result", "disconnected"); - }); - port.onMessage.addListener(msg => { - browser.test.sendMessage("result", "message"); - }); - port.postMessage(PAYLOAD); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - - let result = yield extension.awaitMessage("result"); - equal(result, "disconnected", "native port disconnected on receiving large message"); - - yield extension.unload(); - yield waitForSubprocessExit(); - - clearPref(); -}); - -// Test that an extension without the nativeMessaging permission cannot -// use native messaging. -add_task(function* test_ext_permission() { - function background() { - browser.test.assertFalse("connectNative" in chrome.runtime, "chrome.runtime.connectNative does not exist without nativeMessaging permission"); - browser.test.assertFalse("connectNative" in browser.runtime, "browser.runtime.connectNative does not exist without nativeMessaging permission"); - browser.test.assertFalse("sendNativeMessage" in chrome.runtime, "chrome.runtime.sendNativeMessage does not exist without nativeMessaging permission"); - browser.test.assertFalse("sendNativeMessage" in browser.runtime, "browser.runtime.sendNativeMessage does not exist without nativeMessaging permission"); - browser.test.sendMessage("finished"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: {}, - }); - - yield extension.startup(); - yield extension.awaitMessage("finished"); - yield extension.unload(); -}); - -// Test that an extension that is not listed in allowed_extensions for -// a native application cannot use that application. -add_task(function* test_app_permission() { - function background() { - let port = browser.runtime.connectNative("echo"); - port.onDisconnect.addListener(msgPort => { - browser.test.assertEq(port, msgPort, "onDisconnect handler should receive the port as the first argument"); - browser.test.assertEq("This extension does not have permission to use native application echo (or the application is not installed)", port.error && port.error.message); - browser.test.sendMessage("result", "disconnected"); - }); - port.onMessage.addListener(msg => { - browser.test.sendMessage("result", "message"); - }); - port.postMessage({test: "test"}); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - permissions: ["nativeMessaging"], - }, - }, "somethingelse@tests.mozilla.org"); - - yield extension.startup(); - - let result = yield extension.awaitMessage("result"); - equal(result, "disconnected", "connectNative() failed without native app permission"); - - yield extension.unload(); - - let procCount = yield getSubprocessCount(); - equal(procCount, 0, "No child process was started"); -}); - -// Test that the command-line arguments and working directory for the -// native application are as expected. -add_task(function* test_child_process() { - function background() { - let port = browser.runtime.connectNative("info"); - port.onMessage.addListener(msg => { - browser.test.sendMessage("result", msg); - }); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - - let msg = yield extension.awaitMessage("result"); - equal(msg.args.length, 2, "Received one command line argument"); - equal(msg.args[1], getPath("info.json"), "Command line argument is the path to the native host manifest"); - equal(msg.cwd.replace(/^\/private\//, "/"), tmpDir.path, - "Working directory is the directory containing the native appliation"); - - let exitPromise = waitForSubprocessExit(); - yield extension.unload(); - yield exitPromise; -}); - -add_task(function* test_stderr() { - function background() { - let port = browser.runtime.connectNative("stderr"); - port.onDisconnect.addListener(msgPort => { - browser.test.assertEq(port, msgPort, "onDisconnect handler should receive the port as the first argument"); - browser.test.assertEq(null, port.error, "Normal application exit is not an error"); - browser.test.sendMessage("finished"); - }); - } - - let {messages} = yield promiseConsoleOutput(function* () { - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - yield extension.awaitMessage("finished"); - yield extension.unload(); - - yield waitForSubprocessExit(); - }); - - let lines = STDERR_LINES.map(line => messages.findIndex(msg => msg.message.includes(line))); - notEqual(lines[0], -1, "Saw first line of stderr output on the console"); - notEqual(lines[1], -1, "Saw second line of stderr output on the console"); - notEqual(lines[0], lines[1], "Stderr output lines are separated in the console"); -}); - -// Test that calling connectNative() multiple times works -// (bug 1313980 was a previous regression in this area) -add_task(function* test_multiple_connects() { - async function background() { - function once() { - return new Promise(resolve => { - let MSG = "hello"; - let port = browser.runtime.connectNative("echo"); - - port.onMessage.addListener(msg => { - browser.test.assertEq(MSG, msg, "Got expected message back"); - port.disconnect(); - resolve(); - }); - port.postMessage(MSG); - }); - } - - await once(); - await once(); - browser.test.notifyPass("multiple-connect"); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("multiple-connect"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_native_messaging_perf.js b/toolkit/components/webextensions/test/xpcshell/test_ext_native_messaging_perf.js deleted file mode 100644 index 693f67dde..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_native_messaging_perf.js +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -XPCOMUtils.defineLazyModuleGetter(this, "MockRegistry", - "resource://testing-common/MockRegistry.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "OS", - "resource://gre/modules/osfile.jsm"); - -Cu.import("resource://gre/modules/Subprocess.jsm"); - -const MAX_ROUND_TRIP_TIME_MS = AppConstants.DEBUG || AppConstants.ASAN ? 36 : 18; -const MAX_RETRIES = 5; - - -const ECHO_BODY = String.raw` - import struct - import sys - - while True: - rawlen = sys.stdin.read(4) - if len(rawlen) == 0: - sys.exit(0) - - msglen = struct.unpack('@I', rawlen)[0] - msg = sys.stdin.read(msglen) - - sys.stdout.write(struct.pack('@I', msglen)) - sys.stdout.write(msg) -`; - -const SCRIPTS = [ - { - name: "echo", - description: "A native app that echoes back messages it receives", - script: ECHO_BODY.replace(/^ {2}/gm, ""), - }, -]; - -add_task(function* setup() { - yield setupHosts(SCRIPTS); -}); - -add_task(function* test_round_trip_perf() { - let extension = ExtensionTestUtils.loadExtension({ - background() { - browser.test.onMessage.addListener(msg => { - if (msg != "run-tests") { - return; - } - - let port = browser.runtime.connectNative("echo"); - - function next() { - port.postMessage({ - "Lorem": { - "ipsum": { - "dolor": [ - "sit amet", - "consectetur adipiscing elit", - "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - ], - "Ut enim": [ - "ad minim veniam", - "quis nostrud exercitation ullamco", - "laboris nisi ut aliquip ex ea commodo consequat.", - ], - "Duis": [ - "aute irure dolor in reprehenderit in", - "voluptate velit esse cillum dolore eu", - "fugiat nulla pariatur.", - ], - "Excepteur": [ - "sint occaecat cupidatat non proident", - "sunt in culpa qui officia deserunt", - "mollit anim id est laborum.", - ], - }, - }, - }); - } - - const COUNT = 1000; - let now; - function finish() { - let roundTripTime = (Date.now() - now) / COUNT; - - port.disconnect(); - browser.test.sendMessage("result", roundTripTime); - } - - let count = 0; - port.onMessage.addListener(() => { - if (count == 0) { - // Skip the first round, since it includes the time it takes - // the app to start up. - now = Date.now(); - } - - if (count++ <= COUNT) { - next(); - } else { - finish(); - } - }); - - next(); - }); - }, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - - let roundTripTime = Infinity; - for (let i = 0; i < MAX_RETRIES && roundTripTime > MAX_ROUND_TRIP_TIME_MS; i++) { - extension.sendMessage("run-tests"); - roundTripTime = yield extension.awaitMessage("result"); - } - - yield extension.unload(); - - ok(roundTripTime <= MAX_ROUND_TRIP_TIME_MS, - `Expected round trip time (${roundTripTime}ms) to be less than ${MAX_ROUND_TRIP_TIME_MS}ms`); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_native_messaging_unresponsive.js b/toolkit/components/webextensions/test/xpcshell/test_ext_native_messaging_unresponsive.js deleted file mode 100644 index a75a1d49d..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_native_messaging_unresponsive.js +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -const WONTDIE_BODY = String.raw` - import signal - import struct - import sys - import time - - signal.signal(signal.SIGTERM, signal.SIG_IGN) - - def spin(): - while True: - try: - signal.pause() - except AttributeError: - time.sleep(5) - - while True: - rawlen = sys.stdin.read(4) - if len(rawlen) == 0: - spin() - - msglen = struct.unpack('@I', rawlen)[0] - msg = sys.stdin.read(msglen) - - sys.stdout.write(struct.pack('@I', msglen)) - sys.stdout.write(msg) -`; - -const SCRIPTS = [ - { - name: "wontdie", - description: "a native app that does not exit when stdin closes or on SIGTERM", - script: WONTDIE_BODY.replace(/^ {2}/gm, ""), - }, -]; - -add_task(function* setup() { - yield setupHosts(SCRIPTS); -}); - - -// Test that an unresponsive native application still gets killed eventually -add_task(function* test_unresponsive_native_app() { - // XXX expose GRACEFUL_SHUTDOWN_TIME as a pref and reduce it - // just for this test? - - function background() { - let port = browser.runtime.connectNative("wontdie"); - - const MSG = "echo me"; - // bounce a message to make sure the process actually starts - port.onMessage.addListener(msg => { - browser.test.assertEq(msg, MSG, "Received echoed message"); - browser.test.sendMessage("ready"); - }); - port.postMessage(MSG); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - manifest: { - applications: {gecko: {id: ID}}, - permissions: ["nativeMessaging"], - }, - }); - - yield extension.startup(); - yield extension.awaitMessage("ready"); - - let procCount = yield getSubprocessCount(); - equal(procCount, 1, "subprocess is running"); - - let exitPromise = waitForSubprocessExit(); - yield extension.unload(); - yield exitPromise; - - procCount = yield getSubprocessCount(); - equal(procCount, 0, "subprocess was succesfully killed"); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_onmessage_removelistener.js b/toolkit/components/webextensions/test/xpcshell/test_ext_onmessage_removelistener.js deleted file mode 100644 index 6f8b553fc..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_onmessage_removelistener.js +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -function backgroundScript() { - function listener() { - browser.test.notifyFail("listener should not be invoked"); - } - - browser.runtime.onMessage.addListener(listener); - browser.runtime.onMessage.removeListener(listener); - browser.runtime.sendMessage("hello"); - - // Make sure that, if we somehow fail to remove the listener, then we'll run - // the listener before the test is marked as passing. - setTimeout(function() { - browser.test.notifyPass("onmessage_removelistener"); - }, 0); -} - -let extensionData = { - background: backgroundScript, -}; - -add_task(function* test_contentscript() { - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - yield extension.awaitFinish("onmessage_removelistener"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js b/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js deleted file mode 100644 index 2a1342cde..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js +++ /dev/null @@ -1,23 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_connect_without_listener() { - function background() { - let port = browser.runtime.connect(); - port.onDisconnect.addListener(() => { - browser.test.assertEq("Could not establish connection. Receiving end does not exist.", port.error && port.error.message); - browser.test.notifyPass("port.onDisconnect was called"); - }); - } - let extensionData = { - background, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - - yield extension.awaitFinish("port.onDisconnect was called"); - - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_getBrowserInfo.js b/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_getBrowserInfo.js deleted file mode 100644 index a280206fa..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_getBrowserInfo.js +++ /dev/null @@ -1,26 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -add_task(function* setup() { - ExtensionTestUtils.mockAppInfo(); -}); - -add_task(function* test_getBrowserInfo() { - async function background() { - let info = await browser.runtime.getBrowserInfo(); - - browser.test.assertEq(info.name, "XPCShell", "name is valid"); - browser.test.assertEq(info.vendor, "Mozilla", "vendor is Mozilla"); - browser.test.assertEq(info.version, "48", "version is correct"); - browser.test.assertEq(info.buildID, "20160315", "buildID is correct"); - - browser.test.notifyPass("runtime.getBrowserInfo"); - } - - const extension = ExtensionTestUtils.loadExtension({background}); - yield extension.startup(); - yield extension.awaitFinish("runtime.getBrowserInfo"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js b/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js deleted file mode 100644 index 29bad0c10..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -function backgroundScript() { - browser.runtime.getPlatformInfo(info => { - let validOSs = ["mac", "win", "android", "cros", "linux", "openbsd"]; - let validArchs = ["arm", "x86-32", "x86-64"]; - - browser.test.assertTrue(validOSs.indexOf(info.os) != -1, "OS is valid"); - browser.test.assertTrue(validArchs.indexOf(info.arch) != -1, "Architecture is valid"); - browser.test.notifyPass("runtime.getPlatformInfo"); - }); -} - -let extensionData = { - background: backgroundScript, -}; - -add_task(function* test_contentscript() { - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - yield extension.awaitFinish("runtime.getPlatformInfo"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js b/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js deleted file mode 100644 index fa6461412..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js +++ /dev/null @@ -1,337 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -XPCOMUtils.defineLazyGetter(this, "Management", () => { - const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {}); - return Management; -}); - -const { - createAppInfo, - createTempWebExtensionFile, - promiseAddonByID, - promiseAddonEvent, - promiseCompleteAllInstalls, - promiseFindAddonUpdates, - promiseRestartManager, - promiseShutdownManager, - promiseStartupManager, -} = AddonTestUtils; - -AddonTestUtils.init(this); - -// Allow for unsigned addons. -AddonTestUtils.overrideCertDB(); - -createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42"); - -function awaitEvent(eventName) { - return new Promise(resolve => { - let listener = (_eventName, ...args) => { - if (_eventName === eventName) { - Management.off(eventName, listener); - resolve(...args); - } - }; - - Management.on(eventName, listener); - }); -} - -function background() { - let onInstalledDetails = null; - let onStartupFired = false; - - browser.runtime.onInstalled.addListener(details => { - onInstalledDetails = details; - }); - - browser.runtime.onStartup.addListener(() => { - onStartupFired = true; - }); - - browser.test.onMessage.addListener(message => { - if (message === "get-on-installed-details") { - onInstalledDetails = onInstalledDetails || {fired: false}; - browser.test.sendMessage("on-installed-details", onInstalledDetails); - } else if (message === "did-on-startup-fire") { - browser.test.sendMessage("on-startup-fired", onStartupFired); - } else if (message === "reload-extension") { - browser.runtime.reload(); - } - }); - - browser.runtime.onUpdateAvailable.addListener(details => { - browser.test.sendMessage("reloading"); - browser.runtime.reload(); - }); -} - -function* expectEvents(extension, {onStartupFired, onInstalledFired, onInstalledReason}) { - extension.sendMessage("get-on-installed-details"); - let details = yield extension.awaitMessage("on-installed-details"); - if (onInstalledFired) { - equal(details.reason, onInstalledReason, "runtime.onInstalled fired with the correct reason"); - } else { - equal(details.fired, onInstalledFired, "runtime.onInstalled should not have fired"); - } - - extension.sendMessage("did-on-startup-fire"); - let fired = yield extension.awaitMessage("on-startup-fired"); - equal(fired, onStartupFired, `Expected runtime.onStartup to ${onStartupFired ? "" : "not "} fire`); -} - -add_task(function* test_should_fire_on_addon_update() { - const EXTENSION_ID = "test_runtime_on_installed_addon_update@tests.mozilla.org"; - - const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity"; - - // The test extension uses an insecure update url. - Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false); - - const testServer = createHttpServer(); - const port = testServer.identity.primaryPort; - - let extension = ExtensionTestUtils.loadExtension({ - useAddonManager: "permanent", - manifest: { - "version": "1.0", - "applications": { - "gecko": { - "id": EXTENSION_ID, - "update_url": `http://localhost:${port}/test_update.json`, - }, - }, - }, - background, - }); - - testServer.registerPathHandler("/test_update.json", (request, response) => { - response.write(`{ - "addons": { - "${EXTENSION_ID}": { - "updates": [ - { - "version": "2.0", - "update_link": "http://localhost:${port}/addons/test_runtime_on_installed-2.0.xpi" - } - ] - } - } - }`); - }); - - let webExtensionFile = createTempWebExtensionFile({ - manifest: { - version: "2.0", - applications: { - gecko: { - id: EXTENSION_ID, - }, - }, - }, - background, - }); - - testServer.registerFile("/addons/test_runtime_on_installed-2.0.xpi", webExtensionFile); - - yield promiseStartupManager(); - - yield extension.startup(); - - yield expectEvents(extension, { - onStartupFired: false, - onInstalledFired: true, - onInstalledReason: "install", - }); - - let addon = yield promiseAddonByID(EXTENSION_ID); - equal(addon.version, "1.0", "The installed addon has the correct version"); - - let update = yield promiseFindAddonUpdates(addon); - let install = update.updateAvailable; - - let promiseInstalled = promiseAddonEvent("onInstalled"); - yield promiseCompleteAllInstalls([install]); - - yield extension.awaitMessage("reloading"); - - let startupPromise = awaitEvent("ready"); - - let [updated_addon] = yield promiseInstalled; - equal(updated_addon.version, "2.0", "The updated addon has the correct version"); - - extension.extension = yield startupPromise; - extension.attachListeners(); - - yield expectEvents(extension, { - onStartupFired: false, - onInstalledFired: true, - onInstalledReason: "update", - }); - - yield extension.unload(); - - yield updated_addon.uninstall(); - yield promiseShutdownManager(); -}); - -add_task(function* test_should_fire_on_browser_update() { - const EXTENSION_ID = "test_runtime_on_installed_browser_update@tests.mozilla.org"; - - yield promiseStartupManager(); - - let extension = ExtensionTestUtils.loadExtension({ - useAddonManager: "permanent", - manifest: { - "version": "1.0", - "applications": { - "gecko": { - "id": EXTENSION_ID, - }, - }, - }, - background, - }); - - yield extension.startup(); - - yield expectEvents(extension, { - onStartupFired: false, - onInstalledFired: true, - onInstalledReason: "install", - }); - - let startupPromise = awaitEvent("ready"); - yield promiseRestartManager("1"); - extension.extension = yield startupPromise; - extension.attachListeners(); - - yield expectEvents(extension, { - onStartupFired: true, - onInstalledFired: false, - }); - - // Update the browser. - startupPromise = awaitEvent("ready"); - yield promiseRestartManager("2"); - extension.extension = yield startupPromise; - extension.attachListeners(); - - yield expectEvents(extension, { - onStartupFired: true, - onInstalledFired: true, - onInstalledReason: "browser_update", - }); - - // Restart the browser. - startupPromise = awaitEvent("ready"); - yield promiseRestartManager("2"); - extension.extension = yield startupPromise; - extension.attachListeners(); - - yield expectEvents(extension, { - onStartupFired: true, - onInstalledFired: false, - }); - - // Update the browser again. - startupPromise = awaitEvent("ready"); - yield promiseRestartManager("3"); - extension.extension = yield startupPromise; - extension.attachListeners(); - - yield expectEvents(extension, { - onStartupFired: true, - onInstalledFired: true, - onInstalledReason: "browser_update", - }); - - yield extension.unload(); - - yield promiseShutdownManager(); -}); - -add_task(function* test_should_not_fire_on_reload() { - const EXTENSION_ID = "test_runtime_on_installed_reload@tests.mozilla.org"; - - yield promiseStartupManager(); - - let extension = ExtensionTestUtils.loadExtension({ - useAddonManager: "permanent", - manifest: { - "version": "1.0", - "applications": { - "gecko": { - "id": EXTENSION_ID, - }, - }, - }, - background, - }); - - yield extension.startup(); - - yield expectEvents(extension, { - onStartupFired: false, - onInstalledFired: true, - onInstalledReason: "install", - }); - - let startupPromise = awaitEvent("ready"); - extension.sendMessage("reload-extension"); - extension.extension = yield startupPromise; - extension.attachListeners(); - - yield expectEvents(extension, { - onStartupFired: false, - onInstalledFired: false, - }); - - yield extension.unload(); - yield promiseShutdownManager(); -}); - -add_task(function* test_should_not_fire_on_restart() { - const EXTENSION_ID = "test_runtime_on_installed_restart@tests.mozilla.org"; - - yield promiseStartupManager(); - - let extension = ExtensionTestUtils.loadExtension({ - useAddonManager: "permanent", - manifest: { - "version": "1.0", - "applications": { - "gecko": { - "id": EXTENSION_ID, - }, - }, - }, - background, - }); - - yield extension.startup(); - - yield expectEvents(extension, { - onStartupFired: false, - onInstalledFired: true, - onInstalledReason: "install", - }); - - let addon = yield promiseAddonByID(EXTENSION_ID); - addon.userDisabled = true; - - let startupPromise = awaitEvent("ready"); - addon.userDisabled = false; - extension.extension = yield startupPromise; - extension.attachListeners(); - - yield expectEvents(extension, { - onStartupFired: false, - onInstalledFired: false, - }); - - yield extension.markUnloaded(); - yield promiseShutdownManager(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage.js b/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage.js deleted file mode 100644 index fec8e13dd..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage.js +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* tabsSendMessageReply() { - function background() { - browser.runtime.onMessage.addListener((msg, sender, respond) => { - if (msg == "respond-now") { - respond(msg); - } else if (msg == "respond-soon") { - setTimeout(() => { respond(msg); }, 0); - return true; - } else if (msg == "respond-promise") { - return Promise.resolve(msg); - } else if (msg == "respond-never") { - return; - } else if (msg == "respond-error") { - return Promise.reject(new Error(msg)); - } else if (msg == "throw-error") { - throw new Error(msg); - } - }); - - browser.runtime.onMessage.addListener((msg, sender, respond) => { - if (msg == "respond-now") { - respond("hello"); - } else if (msg == "respond-now-2") { - respond(msg); - } - }); - - let childFrame = document.createElement("iframe"); - childFrame.src = "extensionpage.html"; - document.body.appendChild(childFrame); - } - - function senderScript() { - Promise.all([ - browser.runtime.sendMessage("respond-now"), - browser.runtime.sendMessage("respond-now-2"), - new Promise(resolve => browser.runtime.sendMessage("respond-soon", resolve)), - browser.runtime.sendMessage("respond-promise"), - browser.runtime.sendMessage("respond-never"), - new Promise(resolve => { - browser.runtime.sendMessage("respond-never", response => { resolve(response); }); - }), - - browser.runtime.sendMessage("respond-error").catch(error => Promise.resolve({error})), - browser.runtime.sendMessage("throw-error").catch(error => Promise.resolve({error})), - ]).then(([respondNow, respondNow2, respondSoon, respondPromise, respondNever, respondNever2, respondError, throwError]) => { - browser.test.assertEq("respond-now", respondNow, "Got the expected immediate response"); - browser.test.assertEq("respond-now-2", respondNow2, "Got the expected immediate response from the second listener"); - browser.test.assertEq("respond-soon", respondSoon, "Got the expected delayed response"); - browser.test.assertEq("respond-promise", respondPromise, "Got the expected promise response"); - browser.test.assertEq(undefined, respondNever, "Got the expected no-response resolution"); - browser.test.assertEq(undefined, respondNever2, "Got the expected no-response resolution"); - - browser.test.assertEq("respond-error", respondError.error.message, "Got the expected error response"); - browser.test.assertEq("throw-error", throwError.error.message, "Got the expected thrown error response"); - - browser.test.notifyPass("sendMessage"); - }).catch(e => { - browser.test.fail(`Error: ${e} :: ${e.stack}`); - browser.test.notifyFail("sendMessage"); - }); - } - - let extension = ExtensionTestUtils.loadExtension({ - background, - files: { - "senderScript.js": senderScript, - "extensionpage.html": `<!DOCTYPE html><meta charset="utf-8"><script src="senderScript.js"></script>`, - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("sendMessage"); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage_errors.js b/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage_errors.js deleted file mode 100644 index f1a8d5a36..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage_errors.js +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_sendMessage_error() { - async function background() { - let circ = {}; - circ.circ = circ; - let testCases = [ - // [arguments, expected error string], - [[], "runtime.sendMessage's message argument is missing"], - [[null, null, null, null], "runtime.sendMessage's last argument is not a function"], - [[null, null, 1], "runtime.sendMessage's options argument is invalid"], - [[1, null, null], "runtime.sendMessage's extensionId argument is invalid"], - [[null, null, null, null, null], "runtime.sendMessage received too many arguments"], - - // Even when the parameters are accepted, we still expect an error - // because there is no onMessage listener. - [[null, null, null], "Could not establish connection. Receiving end does not exist."], - - // Structural cloning doesn't work with DOM but we fall back - // JSON serialization, so we don't expect another error. - [[null, location, null], "Could not establish connection. Receiving end does not exist."], - - // Structured cloning supports cyclic self-references. - [[null, [circ, location], null], "cyclic object value"], - // JSON serialization does not support cyclic references. - [[null, circ, null], "Could not establish connection. Receiving end does not exist."], - // (the last two tests shows whether sendMessage is implemented as structured cloning). - ]; - - // Repeat all tests with the undefined value instead of null. - for (let [args, expectedError] of testCases.slice()) { - args = args.map(arg => arg === null ? undefined : arg); - testCases.push([args, expectedError]); - } - - for (let [args, expectedError] of testCases) { - let description = `runtime.sendMessage(${args.map(String).join(", ")})`; - - await browser.test.assertRejects( - browser.runtime.sendMessage(...args), - expectedError, - `expected error message for ${description}`); - } - - browser.test.notifyPass("sendMessage parameter validation"); - } - let extensionData = { - background, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - - yield extension.awaitFinish("sendMessage parameter validation"); - - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js b/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js deleted file mode 100644 index f906333d2..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_sendMessage_without_listener() { - async function background() { - await browser.test.assertRejects( - browser.runtime.sendMessage("msg"), - "Could not establish connection. Receiving end does not exist.", - "sendMessage callback was invoked"); - - browser.test.notifyPass("sendMessage callback was invoked"); - } - let extensionData = { - background, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - - yield extension.awaitFinish("sendMessage callback was invoked"); - - yield extension.unload(); -}); - -add_task(function* test_chrome_sendMessage_without_listener() { - function background() { - /* 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"); - browser.test.assertEq(undefined, retval, "return value of chrome.runtime.sendMessage without callback"); - - 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 extensionData = { - background, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - - yield extension.awaitFinish("finished chrome.runtime.sendMessage"); - - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage_self.js b/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage_self.js deleted file mode 100644 index e4f5e951f..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_runtime_sendMessage_self.js +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ - -"use strict"; - -add_task(function* test_sendMessage_to_self_should_not_trigger_onMessage() { - async function background() { - browser.runtime.onMessage.addListener(msg => { - browser.test.assertEq("msg from child", msg); - browser.test.notifyPass("sendMessage did not call same-frame onMessage"); - }); - - browser.test.onMessage.addListener(msg => { - browser.test.assertEq("sendMessage with a listener in another frame", msg); - browser.runtime.sendMessage("should only reach another frame"); - }); - - await browser.test.assertRejects( - browser.runtime.sendMessage("should not trigger same-frame onMessage"), - "Could not establish connection. Receiving end does not exist."); - - let anotherFrame = document.createElement("iframe"); - anotherFrame.src = browser.extension.getURL("extensionpage.html"); - document.body.appendChild(anotherFrame); - } - - function lastScript() { - browser.runtime.onMessage.addListener(msg => { - browser.test.assertEq("should only reach another frame", msg); - browser.runtime.sendMessage("msg from child"); - }); - browser.test.sendMessage("sendMessage callback called"); - } - - let extensionData = { - background, - files: { - "lastScript.js": lastScript, - "extensionpage.html": `<!DOCTYPE html><meta charset="utf-8"><script src="lastScript.js"></script>`, - }, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - - yield extension.awaitMessage("sendMessage callback called"); - extension.sendMessage("sendMessage with a listener in another frame"); - yield extension.awaitFinish("sendMessage did not call same-frame onMessage"); - - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_schemas.js b/toolkit/components/webextensions/test/xpcshell/test_ext_schemas.js deleted file mode 100644 index d838be5b5..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_schemas.js +++ /dev/null @@ -1,1427 +0,0 @@ -"use strict"; - -Components.utils.import("resource://gre/modules/Schemas.jsm"); -Components.utils.import("resource://gre/modules/BrowserUtils.jsm"); -Components.utils.import("resource://gre/modules/ExtensionCommon.jsm"); - -let {LocalAPIImplementation, SchemaAPIInterface} = ExtensionCommon; - -let json = [ - {namespace: "testing", - - properties: { - PROP1: {value: 20}, - prop2: {type: "string"}, - prop3: { - $ref: "submodule", - }, - prop4: { - $ref: "submodule", - unsupported: true, - }, - }, - - types: [ - { - id: "type1", - type: "string", - "enum": ["value1", "value2", "value3"], - }, - - { - id: "type2", - type: "object", - properties: { - prop1: {type: "integer"}, - prop2: {type: "array", items: {"$ref": "type1"}}, - }, - }, - - { - id: "basetype1", - type: "object", - properties: { - prop1: {type: "string"}, - }, - }, - - { - id: "basetype2", - choices: [ - {type: "integer"}, - ], - }, - - { - $extend: "basetype1", - properties: { - prop2: {type: "string"}, - }, - }, - - { - $extend: "basetype2", - choices: [ - {type: "string"}, - ], - }, - - { - id: "submodule", - type: "object", - functions: [ - { - name: "sub_foo", - type: "function", - parameters: [], - returns: "integer", - }, - ], - }, - ], - - functions: [ - { - name: "foo", - type: "function", - parameters: [ - {name: "arg1", type: "integer", optional: true, default: 99}, - {name: "arg2", type: "boolean", optional: true}, - ], - }, - - { - name: "bar", - type: "function", - parameters: [ - {name: "arg1", type: "integer", optional: true}, - {name: "arg2", type: "boolean"}, - ], - }, - - { - name: "baz", - type: "function", - parameters: [ - {name: "arg1", type: "object", properties: { - prop1: {type: "string"}, - prop2: {type: "integer", optional: true}, - prop3: {type: "integer", unsupported: true}, - }}, - ], - }, - - { - name: "qux", - type: "function", - parameters: [ - {name: "arg1", "$ref": "type1"}, - ], - }, - - { - name: "quack", - type: "function", - parameters: [ - {name: "arg1", "$ref": "type2"}, - ], - }, - - { - name: "quora", - type: "function", - parameters: [ - {name: "arg1", type: "function"}, - ], - }, - - { - name: "quileute", - type: "function", - parameters: [ - {name: "arg1", type: "integer", optional: true}, - {name: "arg2", type: "integer"}, - ], - }, - - { - name: "queets", - type: "function", - unsupported: true, - parameters: [], - }, - - { - name: "quintuplets", - type: "function", - parameters: [ - {name: "obj", type: "object", properties: [], additionalProperties: {type: "integer"}}, - ], - }, - - { - name: "quasar", - type: "function", - parameters: [ - {name: "abc", type: "object", properties: { - func: {type: "function", parameters: [ - {name: "x", type: "integer"}, - ]}, - }}, - ], - }, - - { - name: "quosimodo", - type: "function", - parameters: [ - {name: "xyz", type: "object", additionalProperties: {type: "any"}}, - ], - }, - - { - name: "patternprop", - type: "function", - parameters: [ - { - name: "obj", - type: "object", - properties: {"prop1": {type: "string", pattern: "^\\d+$"}}, - patternProperties: { - "(?i)^prop\\d+$": {type: "string"}, - "^foo\\d+$": {type: "string"}, - }, - }, - ], - }, - - { - name: "pattern", - type: "function", - parameters: [ - {name: "arg", type: "string", pattern: "(?i)^[0-9a-f]+$"}, - ], - }, - - { - name: "format", - type: "function", - parameters: [ - { - name: "arg", - type: "object", - properties: { - url: {type: "string", "format": "url", "optional": true}, - relativeUrl: {type: "string", "format": "relativeUrl", "optional": true}, - strictRelativeUrl: {type: "string", "format": "strictRelativeUrl", "optional": true}, - }, - }, - ], - }, - - { - name: "formatDate", - type: "function", - parameters: [ - { - name: "arg", - type: "object", - properties: { - date: {type: "string", format: "date", optional: true}, - }, - }, - ], - }, - - { - name: "deep", - type: "function", - parameters: [ - { - name: "arg", - type: "object", - properties: { - foo: { - type: "object", - properties: { - bar: { - type: "array", - items: { - type: "object", - properties: { - baz: { - type: "object", - properties: { - required: {type: "integer"}, - optional: {type: "string", optional: true}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - ], - }, - - { - name: "errors", - type: "function", - parameters: [ - { - name: "arg", - type: "object", - properties: { - warn: { - type: "string", - pattern: "^\\d+$", - optional: true, - onError: "warn", - }, - ignore: { - type: "string", - pattern: "^\\d+$", - optional: true, - onError: "ignore", - }, - default: { - type: "string", - pattern: "^\\d+$", - optional: true, - }, - }, - }, - ], - }, - - { - name: "localize", - type: "function", - parameters: [ - { - name: "arg", - type: "object", - properties: { - foo: {type: "string", "preprocess": "localize", "optional": true}, - bar: {type: "string", "optional": true}, - url: {type: "string", "preprocess": "localize", "format": "url", "optional": true}, - }, - }, - ], - }, - - { - name: "extended1", - type: "function", - parameters: [ - {name: "val", $ref: "basetype1"}, - ], - }, - - { - name: "extended2", - type: "function", - parameters: [ - {name: "val", $ref: "basetype2"}, - ], - }, - ], - - events: [ - { - name: "onFoo", - type: "function", - }, - - { - name: "onBar", - type: "function", - extraParameters: [{ - name: "filter", - type: "integer", - optional: true, - default: 1, - }], - }, - ], - }, - { - namespace: "foreign", - properties: { - foreignRef: {$ref: "testing.submodule"}, - }, - }, - { - namespace: "inject", - properties: { - PROP1: {value: "should inject"}, - }, - }, - { - namespace: "do-not-inject", - properties: { - PROP1: {value: "should not inject"}, - }, - }, -]; - -let tallied = null; - -function tally(kind, ns, name, args) { - tallied = [kind, ns, name, args]; -} - -function verify(...args) { - do_check_eq(JSON.stringify(tallied), JSON.stringify(args)); - tallied = null; -} - -let talliedErrors = []; - -function checkErrors(errors) { - do_check_eq(talliedErrors.length, errors.length, "Got expected number of errors"); - for (let [i, error] of errors.entries()) { - do_check_true(i in talliedErrors && talliedErrors[i].includes(error), - `${JSON.stringify(error)} is a substring of error ${JSON.stringify(talliedErrors[i])}`); - } - - talliedErrors.length = 0; -} - -let permissions = new Set(); - -class TallyingAPIImplementation extends SchemaAPIInterface { - constructor(namespace, name) { - super(); - this.namespace = namespace; - this.name = name; - } - - callFunction(args) { - tally("call", this.namespace, this.name, args); - } - - callFunctionNoReturn(args) { - tally("call", this.namespace, this.name, args); - } - - getProperty() { - tally("get", this.namespace, this.name); - } - - setProperty(value) { - tally("set", this.namespace, this.name, value); - } - - addListener(listener, args) { - tally("addListener", this.namespace, this.name, [listener, args]); - } - - removeListener(listener) { - tally("removeListener", this.namespace, this.name, [listener]); - } - - hasListener(listener) { - tally("hasListener", this.namespace, this.name, [listener]); - } -} - -let wrapper = { - url: "moz-extension://b66e3509-cdb3-44f6-8eb8-c8b39b3a1d27/", - - checkLoadURL(url) { - return !url.startsWith("chrome:"); - }, - - preprocessors: { - localize(value, context) { - return value.replace(/__MSG_(.*?)__/g, (m0, m1) => `${m1.toUpperCase()}`); - }, - }, - - logError(message) { - talliedErrors.push(message); - }, - - hasPermission(permission) { - return permissions.has(permission); - }, - - shouldInject(ns) { - return ns != "do-not-inject"; - }, - - getImplementation(namespace, name) { - return new TallyingAPIImplementation(namespace, name); - }, -}; - -add_task(function* () { - let url = "data:," + JSON.stringify(json); - yield Schemas.load(url); - - let root = {}; - tallied = null; - Schemas.inject(root, wrapper); - do_check_eq(tallied, null); - - do_check_eq(root.testing.PROP1, 20, "simple value property"); - do_check_eq(root.testing.type1.VALUE1, "value1", "enum type"); - do_check_eq(root.testing.type1.VALUE2, "value2", "enum type"); - - do_check_eq("inject" in root, true, "namespace 'inject' should be injected"); - do_check_eq("do-not-inject" in root, false, "namespace 'do-not-inject' should not be injected"); - - root.testing.foo(11, true); - verify("call", "testing", "foo", [11, true]); - - root.testing.foo(true); - verify("call", "testing", "foo", [99, true]); - - root.testing.foo(null, true); - verify("call", "testing", "foo", [99, true]); - - root.testing.foo(undefined, true); - verify("call", "testing", "foo", [99, true]); - - root.testing.foo(11); - verify("call", "testing", "foo", [11, null]); - - Assert.throws(() => root.testing.bar(11), - /Incorrect argument types/, - "should throw without required arg"); - - Assert.throws(() => root.testing.bar(11, true, 10), - /Incorrect argument types/, - "should throw with too many arguments"); - - root.testing.bar(true); - verify("call", "testing", "bar", [null, true]); - - root.testing.baz({prop1: "hello", prop2: 22}); - verify("call", "testing", "baz", [{prop1: "hello", prop2: 22}]); - - root.testing.baz({prop1: "hello"}); - verify("call", "testing", "baz", [{prop1: "hello", prop2: null}]); - - root.testing.baz({prop1: "hello", prop2: null}); - verify("call", "testing", "baz", [{prop1: "hello", prop2: null}]); - - Assert.throws(() => root.testing.baz({prop2: 12}), - /Property "prop1" is required/, - "should throw without required property"); - - Assert.throws(() => root.testing.baz({prop1: "hi", prop3: 12}), - /Property "prop3" is unsupported by Firefox/, - "should throw with unsupported property"); - - Assert.throws(() => root.testing.baz({prop1: "hi", prop4: 12}), - /Unexpected property "prop4"/, - "should throw with unexpected property"); - - Assert.throws(() => root.testing.baz({prop1: 12}), - /Expected string instead of 12/, - "should throw with wrong type"); - - root.testing.qux("value2"); - verify("call", "testing", "qux", ["value2"]); - - Assert.throws(() => root.testing.qux("value4"), - /Invalid enumeration value "value4"/, - "should throw for invalid enum value"); - - root.testing.quack({prop1: 12, prop2: ["value1", "value3"]}); - verify("call", "testing", "quack", [{prop1: 12, prop2: ["value1", "value3"]}]); - - Assert.throws(() => root.testing.quack({prop1: 12, prop2: ["value1", "value3", "value4"]}), - /Invalid enumeration value "value4"/, - "should throw for invalid array type"); - - function f() {} - root.testing.quora(f); - do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["call", "testing", "quora"])); - do_check_eq(tallied[3][0], f); - tallied = null; - - let g = () => 0; - root.testing.quora(g); - do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["call", "testing", "quora"])); - do_check_eq(tallied[3][0], g); - tallied = null; - - root.testing.quileute(10); - verify("call", "testing", "quileute", [null, 10]); - - Assert.throws(() => root.testing.queets(), - /queets is not a function/, - "should throw for unsupported functions"); - - root.testing.quintuplets({a: 10, b: 20, c: 30}); - verify("call", "testing", "quintuplets", [{a: 10, b: 20, c: 30}]); - - Assert.throws(() => root.testing.quintuplets({a: 10, b: 20, c: 30, d: "hi"}), - /Expected integer instead of "hi"/, - "should throw for wrong additionalProperties type"); - - root.testing.quasar({func: f}); - do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["call", "testing", "quasar"])); - do_check_eq(tallied[3][0].func, f); - tallied = null; - - root.testing.quosimodo({a: 10, b: 20, c: 30}); - verify("call", "testing", "quosimodo", [{a: 10, b: 20, c: 30}]); - tallied = null; - - Assert.throws(() => root.testing.quosimodo(10), - /Incorrect argument types/, - "should throw for wrong type"); - - root.testing.patternprop({prop1: "12", prop2: "42", Prop3: "43", foo1: "x"}); - verify("call", "testing", "patternprop", [{prop1: "12", prop2: "42", Prop3: "43", foo1: "x"}]); - tallied = null; - - root.testing.patternprop({prop1: "12"}); - verify("call", "testing", "patternprop", [{prop1: "12"}]); - tallied = null; - - Assert.throws(() => root.testing.patternprop({prop1: "12", foo1: null}), - /Expected string instead of null/, - "should throw for wrong property type"); - - Assert.throws(() => root.testing.patternprop({prop1: "xx", prop2: "yy"}), - /String "xx" must match \/\^\\d\+\$\//, - "should throw for wrong property type"); - - Assert.throws(() => root.testing.patternprop({prop1: "12", prop2: 42}), - /Expected string instead of 42/, - "should throw for wrong property type"); - - Assert.throws(() => root.testing.patternprop({prop1: "12", prop2: null}), - /Expected string instead of null/, - "should throw for wrong property type"); - - Assert.throws(() => root.testing.patternprop({prop1: "12", propx: "42"}), - /Unexpected property "propx"/, - "should throw for unexpected property"); - - Assert.throws(() => root.testing.patternprop({prop1: "12", Foo1: "x"}), - /Unexpected property "Foo1"/, - "should throw for unexpected property"); - - root.testing.pattern("DEADbeef"); - verify("call", "testing", "pattern", ["DEADbeef"]); - tallied = null; - - Assert.throws(() => root.testing.pattern("DEADcow"), - /String "DEADcow" must match \/\^\[0-9a-f\]\+\$\/i/, - "should throw for non-match"); - - root.testing.format({url: "http://foo/bar", - relativeUrl: "http://foo/bar"}); - verify("call", "testing", "format", [{url: "http://foo/bar", - relativeUrl: "http://foo/bar", - strictRelativeUrl: null}]); - tallied = null; - - root.testing.format({relativeUrl: "foo.html", strictRelativeUrl: "foo.html"}); - verify("call", "testing", "format", [{url: null, - relativeUrl: `${wrapper.url}foo.html`, - strictRelativeUrl: `${wrapper.url}foo.html`}]); - tallied = null; - - for (let format of ["url", "relativeUrl"]) { - Assert.throws(() => root.testing.format({[format]: "chrome://foo/content/"}), - /Access denied/, - "should throw for access denied"); - } - - for (let urlString of ["//foo.html", "http://foo/bar.html"]) { - Assert.throws(() => root.testing.format({strictRelativeUrl: urlString}), - /must be a relative URL/, - "should throw for non-relative URL"); - } - - const dates = [ - "2016-03-04", - "2016-03-04T08:00:00Z", - "2016-03-04T08:00:00.000Z", - "2016-03-04T08:00:00-08:00", - "2016-03-04T08:00:00.000-08:00", - "2016-03-04T08:00:00+08:00", - "2016-03-04T08:00:00.000+08:00", - "2016-03-04T08:00:00+0800", - "2016-03-04T08:00:00-0800", - ]; - dates.forEach(str => { - root.testing.formatDate({date: str}); - verify("call", "testing", "formatDate", [{date: str}]); - }); - - // Make sure that a trivial change to a valid date invalidates it. - dates.forEach(str => { - Assert.throws(() => root.testing.formatDate({date: "0" + str}), - /Invalid date string/, - "should throw for invalid iso date string"); - Assert.throws(() => root.testing.formatDate({date: str + "0"}), - /Invalid date string/, - "should throw for invalid iso date string"); - }); - - const badDates = [ - "I do not look anything like a date string", - "2016-99-99", - "2016-03-04T25:00:00Z", - ]; - badDates.forEach(str => { - Assert.throws(() => root.testing.formatDate({date: str}), - /Invalid date string/, - "should throw for invalid iso date string"); - }); - - root.testing.deep({foo: {bar: [{baz: {required: 12, optional: "42"}}]}}); - verify("call", "testing", "deep", [{foo: {bar: [{baz: {required: 12, optional: "42"}}]}}]); - tallied = null; - - Assert.throws(() => root.testing.deep({foo: {bar: [{baz: {optional: "42"}}]}}), - /Type error for parameter arg \(Error processing foo\.bar\.0\.baz: Property "required" is required\) for testing\.deep/, - "should throw with the correct object path"); - - Assert.throws(() => root.testing.deep({foo: {bar: [{baz: {required: 12, optional: 42}}]}}), - /Type error for parameter arg \(Error processing foo\.bar\.0\.baz\.optional: Expected string instead of 42\) for testing\.deep/, - "should throw with the correct object path"); - - - talliedErrors.length = 0; - - root.testing.errors({warn: "0123", ignore: "0123", default: "0123"}); - verify("call", "testing", "errors", [{warn: "0123", ignore: "0123", default: "0123"}]); - checkErrors([]); - - root.testing.errors({warn: "0123", ignore: "x123", default: "0123"}); - verify("call", "testing", "errors", [{warn: "0123", ignore: null, default: "0123"}]); - checkErrors([]); - - root.testing.errors({warn: "x123", ignore: "0123", default: "0123"}); - verify("call", "testing", "errors", [{warn: null, ignore: "0123", default: "0123"}]); - checkErrors([ - 'String "x123" must match /^\\d+$/', - ]); - - - root.testing.onFoo.addListener(f); - do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["addListener", "testing", "onFoo"])); - do_check_eq(tallied[3][0], f); - do_check_eq(JSON.stringify(tallied[3][1]), JSON.stringify([])); - tallied = null; - - root.testing.onFoo.removeListener(f); - do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["removeListener", "testing", "onFoo"])); - do_check_eq(tallied[3][0], f); - tallied = null; - - root.testing.onFoo.hasListener(f); - do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["hasListener", "testing", "onFoo"])); - do_check_eq(tallied[3][0], f); - tallied = null; - - Assert.throws(() => root.testing.onFoo.addListener(10), - /Invalid listener/, - "addListener with non-function should throw"); - - root.testing.onBar.addListener(f, 10); - do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["addListener", "testing", "onBar"])); - do_check_eq(tallied[3][0], f); - do_check_eq(JSON.stringify(tallied[3][1]), JSON.stringify([10])); - tallied = null; - - root.testing.onBar.addListener(f); - do_check_eq(JSON.stringify(tallied.slice(0, -1)), JSON.stringify(["addListener", "testing", "onBar"])); - do_check_eq(tallied[3][0], f); - do_check_eq(JSON.stringify(tallied[3][1]), JSON.stringify([1])); - tallied = null; - - Assert.throws(() => root.testing.onBar.addListener(f, "hi"), - /Incorrect argument types/, - "addListener with wrong extra parameter should throw"); - - let target = {prop1: 12, prop2: ["value1", "value3"]}; - let proxy = new Proxy(target, {}); - Assert.throws(() => root.testing.quack(proxy), - /Expected a plain JavaScript object, got a Proxy/, - "should throw when passing a Proxy"); - - if (Symbol.toStringTag) { - let stringTarget = {prop1: 12, prop2: ["value1", "value3"]}; - stringTarget[Symbol.toStringTag] = () => "[object Object]"; - let stringProxy = new Proxy(stringTarget, {}); - Assert.throws(() => root.testing.quack(stringProxy), - /Expected a plain JavaScript object, got a Proxy/, - "should throw when passing a Proxy"); - } - - - root.testing.localize({foo: "__MSG_foo__", bar: "__MSG_foo__", url: "__MSG_http://example.com/__"}); - verify("call", "testing", "localize", [{foo: "FOO", bar: "__MSG_foo__", url: "http://example.com/"}]); - tallied = null; - - - Assert.throws(() => root.testing.localize({url: "__MSG_/foo/bar__"}), - /\/FOO\/BAR is not a valid URL\./, - "should throw for invalid URL"); - - - root.testing.extended1({prop1: "foo", prop2: "bar"}); - verify("call", "testing", "extended1", [{prop1: "foo", prop2: "bar"}]); - tallied = null; - - Assert.throws(() => root.testing.extended1({prop1: "foo", prop2: 12}), - /Expected string instead of 12/, - "should throw for wrong property type"); - - Assert.throws(() => root.testing.extended1({prop1: "foo"}), - /Property "prop2" is required/, - "should throw for missing property"); - - Assert.throws(() => root.testing.extended1({prop1: "foo", prop2: "bar", prop3: "xxx"}), - /Unexpected property "prop3"/, - "should throw for extra property"); - - - root.testing.extended2("foo"); - verify("call", "testing", "extended2", ["foo"]); - tallied = null; - - root.testing.extended2(12); - verify("call", "testing", "extended2", [12]); - tallied = null; - - Assert.throws(() => root.testing.extended2(true), - /Incorrect argument types/, - "should throw for wrong argument type"); - - root.testing.prop3.sub_foo(); - verify("call", "testing.prop3", "sub_foo", []); - tallied = null; - - Assert.throws(() => root.testing.prop4.sub_foo(), - /root.testing.prop4 is undefined/, - "should throw for unsupported submodule"); - - root.foreign.foreignRef.sub_foo(); - verify("call", "foreign.foreignRef", "sub_foo", []); - tallied = null; -}); - -let deprecatedJson = [ - {namespace: "deprecated", - - properties: { - accessor: { - type: "string", - writable: true, - deprecated: "This is not the property you are looking for", - }, - }, - - types: [ - { - "id": "Type", - "type": "string", - }, - ], - - functions: [ - { - name: "property", - type: "function", - parameters: [ - { - name: "arg", - type: "object", - properties: { - foo: { - type: "string", - }, - }, - additionalProperties: { - type: "any", - deprecated: "Unknown property", - }, - }, - ], - }, - - { - name: "value", - type: "function", - parameters: [ - { - name: "arg", - choices: [ - { - type: "integer", - }, - { - type: "string", - deprecated: "Please use an integer, not ${value}", - }, - ], - }, - ], - }, - - { - name: "choices", - type: "function", - parameters: [ - { - name: "arg", - deprecated: "You have no choices", - choices: [ - { - type: "integer", - }, - ], - }, - ], - }, - - { - name: "ref", - type: "function", - parameters: [ - { - name: "arg", - choices: [ - { - $ref: "Type", - deprecated: "Deprecated alias", - }, - ], - }, - ], - }, - - { - name: "method", - type: "function", - deprecated: "Do not call this method", - parameters: [ - ], - }, - ], - - events: [ - { - name: "onDeprecated", - type: "function", - deprecated: "This event does not work", - }, - ], - }, -]; - -add_task(function* testDeprecation() { - let url = "data:," + JSON.stringify(deprecatedJson); - yield Schemas.load(url); - - let root = {}; - Schemas.inject(root, wrapper); - - talliedErrors.length = 0; - - - root.deprecated.property({foo: "bar", xxx: "any", yyy: "property"}); - verify("call", "deprecated", "property", [{foo: "bar", xxx: "any", yyy: "property"}]); - checkErrors([ - "Error processing xxx: Unknown property", - "Error processing yyy: Unknown property", - ]); - - root.deprecated.value(12); - verify("call", "deprecated", "value", [12]); - checkErrors([]); - - root.deprecated.value("12"); - verify("call", "deprecated", "value", ["12"]); - checkErrors(["Please use an integer, not \"12\""]); - - root.deprecated.choices(12); - verify("call", "deprecated", "choices", [12]); - checkErrors(["You have no choices"]); - - root.deprecated.ref("12"); - verify("call", "deprecated", "ref", ["12"]); - checkErrors(["Deprecated alias"]); - - root.deprecated.method(); - verify("call", "deprecated", "method", []); - checkErrors(["Do not call this method"]); - - - void root.deprecated.accessor; - verify("get", "deprecated", "accessor", null); - checkErrors(["This is not the property you are looking for"]); - - root.deprecated.accessor = "x"; - verify("set", "deprecated", "accessor", "x"); - checkErrors(["This is not the property you are looking for"]); - - - root.deprecated.onDeprecated.addListener(() => {}); - checkErrors(["This event does not work"]); - - root.deprecated.onDeprecated.removeListener(() => {}); - checkErrors(["This event does not work"]); - - root.deprecated.onDeprecated.hasListener(() => {}); - checkErrors(["This event does not work"]); -}); - - -let choicesJson = [ - {namespace: "choices", - - types: [ - ], - - functions: [ - { - name: "meh", - type: "function", - parameters: [ - { - name: "arg", - choices: [ - { - type: "string", - enum: ["foo", "bar", "baz"], - }, - { - type: "string", - pattern: "florg.*meh", - }, - { - type: "integer", - minimum: 12, - maximum: 42, - }, - ], - }, - ], - }, - - { - name: "foo", - type: "function", - parameters: [ - { - name: "arg", - choices: [ - { - type: "object", - properties: { - blurg: { - type: "string", - unsupported: true, - optional: true, - }, - }, - additionalProperties: { - type: "string", - }, - }, - { - type: "string", - }, - { - type: "array", - minItems: 2, - maxItems: 3, - items: { - type: "integer", - }, - }, - ], - }, - ], - }, - - { - name: "bar", - type: "function", - parameters: [ - { - name: "arg", - choices: [ - { - type: "object", - properties: { - baz: { - type: "string", - }, - }, - }, - { - type: "array", - items: { - type: "integer", - }, - }, - ], - }, - ], - }, - ]}, -]; - -add_task(function* testChoices() { - let url = "data:," + JSON.stringify(choicesJson); - yield Schemas.load(url); - - let root = {}; - Schemas.inject(root, wrapper); - - talliedErrors.length = 0; - - Assert.throws(() => root.choices.meh("frog"), - /Value must either: be one of \["foo", "bar", "baz"\], match the pattern \/florg\.\*meh\/, or be an integer value/); - - Assert.throws(() => root.choices.meh(4), - /be a string value, or be at least 12/); - - Assert.throws(() => root.choices.meh(43), - /be a string value, or be no greater than 42/); - - - Assert.throws(() => root.choices.foo([]), - /be an object value, be a string value, or have at least 2 items/); - - Assert.throws(() => root.choices.foo([1, 2, 3, 4]), - /be an object value, be a string value, or have at most 3 items/); - - Assert.throws(() => root.choices.foo({foo: 12}), - /.foo must be a string value, be a string value, or be an array value/); - - Assert.throws(() => root.choices.foo({blurg: "foo"}), - /not contain an unsupported "blurg" property, be a string value, or be an array value/); - - - Assert.throws(() => root.choices.bar({}), - /contain the required "baz" property, or be an array value/); - - Assert.throws(() => root.choices.bar({baz: "x", quux: "y"}), - /not contain an unexpected "quux" property, or be an array value/); - - Assert.throws(() => root.choices.bar({baz: "x", quux: "y", foo: "z"}), - /not contain the unexpected properties \[foo, quux\], or be an array value/); -}); - - -let permissionsJson = [ - {namespace: "noPerms", - - types: [], - - functions: [ - { - name: "noPerms", - type: "function", - parameters: [], - }, - - { - name: "fooPerm", - type: "function", - permissions: ["foo"], - parameters: [], - }, - ]}, - - {namespace: "fooPerm", - - permissions: ["foo"], - - types: [], - - functions: [ - { - name: "noPerms", - type: "function", - parameters: [], - }, - - { - name: "fooBarPerm", - type: "function", - permissions: ["foo.bar"], - parameters: [], - }, - ]}, -]; - -add_task(function* testPermissions() { - let url = "data:," + JSON.stringify(permissionsJson); - yield Schemas.load(url); - - let root = {}; - Schemas.inject(root, wrapper); - - equal(typeof root.noPerms, "object", "noPerms namespace should exist"); - equal(typeof root.noPerms.noPerms, "function", "noPerms.noPerms method should exist"); - - ok(!("fooPerm" in root.noPerms), "noPerms.fooPerm should not method exist"); - - ok(!("fooPerm" in root), "fooPerm namespace should not exist"); - - - do_print('Add "foo" permission'); - permissions.add("foo"); - - root = {}; - Schemas.inject(root, wrapper); - - equal(typeof root.noPerms, "object", "noPerms namespace should exist"); - equal(typeof root.noPerms.noPerms, "function", "noPerms.noPerms method should exist"); - equal(typeof root.noPerms.fooPerm, "function", "noPerms.fooPerm method should exist"); - - equal(typeof root.fooPerm, "object", "fooPerm namespace should exist"); - equal(typeof root.fooPerm.noPerms, "function", "noPerms.noPerms method should exist"); - - ok(!("fooBarPerm" in root.fooPerm), "fooPerm.fooBarPerm method should not exist"); - - - do_print('Add "foo.bar" permission'); - permissions.add("foo.bar"); - - root = {}; - Schemas.inject(root, wrapper); - - equal(typeof root.noPerms, "object", "noPerms namespace should exist"); - equal(typeof root.noPerms.noPerms, "function", "noPerms.noPerms method should exist"); - equal(typeof root.noPerms.fooPerm, "function", "noPerms.fooPerm method should exist"); - - equal(typeof root.fooPerm, "object", "fooPerm namespace should exist"); - equal(typeof root.fooPerm.noPerms, "function", "noPerms.noPerms method should exist"); - equal(typeof root.fooPerm.fooBarPerm, "function", "noPerms.fooBarPerm method should exist"); -}); - -let nestedNamespaceJson = [ - { - "namespace": "nested.namespace", - "types": [ - { - "id": "CustomType", - "type": "object", - "events": [ - { - "name": "onEvent", - }, - ], - "properties": { - "url": { - "type": "string", - }, - }, - "functions": [ - { - "name": "functionOnCustomType", - "type": "function", - "parameters": [ - { - "name": "title", - "type": "string", - }, - ], - }, - ], - }, - ], - "properties": { - "instanceOfCustomType": { - "$ref": "CustomType", - }, - }, - "functions": [ - { - "name": "create", - "type": "function", - "parameters": [ - { - "name": "title", - "type": "string", - }, - ], - }, - ], - }, -]; - -add_task(function* testNestedNamespace() { - let url = "data:," + JSON.stringify(nestedNamespaceJson); - - yield Schemas.load(url); - - let root = {}; - Schemas.inject(root, wrapper); - - talliedErrors.length = 0; - - ok(root.nested, "The root object contains the first namespace level"); - ok(root.nested.namespace, "The first level object contains the second namespace level"); - - ok(root.nested.namespace.create, "Got the expected function in the nested namespace"); - do_check_eq(typeof root.nested.namespace.create, "function", - "The property is a function as expected"); - - let {instanceOfCustomType} = root.nested.namespace; - - ok(instanceOfCustomType, - "Got the expected instance of the CustomType defined in the schema"); - ok(instanceOfCustomType.functionOnCustomType, - "Got the expected method in the CustomType instance"); - - // TODO: test support events and properties in a SubModuleType defined in the schema, - // once implemented, e.g.: - // - // ok(instanceOfCustomType.url, - // "Got the expected property defined in the CustomType instance) - // - // ok(instanceOfCustomType.onEvent && - // instanceOfCustomType.onEvent.addListener && - // typeof instanceOfCustomType.onEvent.addListener == "function", - // "Got the expected event defined in the CustomType instance"); -}); - -add_task(function* testLocalAPIImplementation() { - let countGet2 = 0; - let countProp3 = 0; - let countProp3SubFoo = 0; - - let testingApiObj = { - get PROP1() { - // PROP1 is a schema-defined constant. - throw new Error("Unexpected get PROP1"); - }, - get prop2() { - ++countGet2; - return "prop2 val"; - }, - get prop3() { - throw new Error("Unexpected get prop3"); - }, - set prop3(v) { - // prop3 is a submodule, defined as a function, so the API should not pass - // through assignment to prop3. - throw new Error("Unexpected set prop3"); - }, - }; - let submoduleApiObj = { - get sub_foo() { - ++countProp3; - return () => { - return ++countProp3SubFoo; - }; - }, - }; - - let localWrapper = { - shouldInject(ns) { - return ns == "testing" || ns == "testing.prop3"; - }, - getImplementation(ns, name) { - do_check_true(ns == "testing" || ns == "testing.prop3"); - if (ns == "testing.prop3" && name == "sub_foo") { - // It is fine to use `null` here because we don't call async functions. - return new LocalAPIImplementation(submoduleApiObj, name, null); - } - // It is fine to use `null` here because we don't call async functions. - return new LocalAPIImplementation(testingApiObj, name, null); - }, - }; - - let root = {}; - Schemas.inject(root, localWrapper); - do_check_eq(countGet2, 0); - do_check_eq(countProp3, 0); - do_check_eq(countProp3SubFoo, 0); - - do_check_eq(root.testing.PROP1, 20); - - do_check_eq(root.testing.prop2, "prop2 val"); - do_check_eq(countGet2, 1); - - do_check_eq(root.testing.prop2, "prop2 val"); - do_check_eq(countGet2, 2); - - do_print(JSON.stringify(root.testing)); - do_check_eq(root.testing.prop3.sub_foo(), 1); - do_check_eq(countProp3, 1); - do_check_eq(countProp3SubFoo, 1); - - do_check_eq(root.testing.prop3.sub_foo(), 2); - do_check_eq(countProp3, 2); - do_check_eq(countProp3SubFoo, 2); - - root.testing.prop3.sub_foo = () => { return "overwritten"; }; - do_check_eq(root.testing.prop3.sub_foo(), "overwritten"); - - root.testing.prop3 = {sub_foo() { return "overwritten again"; }}; - do_check_eq(root.testing.prop3.sub_foo(), "overwritten again"); - do_check_eq(countProp3SubFoo, 2); -}); - - -let defaultsJson = [ - {namespace: "defaultsJson", - - types: [], - - functions: [ - { - name: "defaultFoo", - type: "function", - parameters: [ - {name: "arg", type: "object", optional: true, properties: { - prop1: {type: "integer", optional: true}, - }, default: {prop1: 1}}, - ], - returns: { - type: "object", - }, - }, - ]}, -]; - -add_task(function* testDefaults() { - let url = "data:," + JSON.stringify(defaultsJson); - yield Schemas.load(url); - - let testingApiObj = { - defaultFoo: function(arg) { - if (Object.keys(arg) != "prop1") { - throw new Error(`Received the expected default object, default: ${JSON.stringify(arg)}`); - } - arg.newProp = 1; - return arg; - }, - }; - - let localWrapper = { - shouldInject(ns) { - return true; - }, - getImplementation(ns, name) { - return new LocalAPIImplementation(testingApiObj, name, null); - }, - }; - - let root = {}; - Schemas.inject(root, localWrapper); - - deepEqual(root.defaultsJson.defaultFoo(), {prop1: 1, newProp: 1}); - deepEqual(root.defaultsJson.defaultFoo({prop1: 2}), {prop1: 2, newProp: 1}); - deepEqual(root.defaultsJson.defaultFoo(), {prop1: 1, newProp: 1}); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_schemas_allowed_contexts.js b/toolkit/components/webextensions/test/xpcshell/test_ext_schemas_allowed_contexts.js deleted file mode 100644 index 606459764..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_schemas_allowed_contexts.js +++ /dev/null @@ -1,147 +0,0 @@ -"use strict"; - -Components.utils.import("resource://gre/modules/Schemas.jsm"); - -let schemaJson = [ - { - namespace: "noAllowedContexts", - properties: { - prop1: {type: "object"}, - prop2: {type: "object", allowedContexts: ["test_zero", "test_one"]}, - prop3: {type: "number", value: 1}, - prop4: {type: "number", value: 1, allowedContexts: ["numeric_one"]}, - }, - }, - { - namespace: "defaultContexts", - defaultContexts: ["test_two"], - properties: { - prop1: {type: "object"}, - prop2: {type: "object", allowedContexts: ["test_three"]}, - prop3: {type: "number", value: 1}, - prop4: {type: "number", value: 1, allowedContexts: ["numeric_two"]}, - }, - }, - { - namespace: "withAllowedContexts", - allowedContexts: ["test_four"], - properties: { - prop1: {type: "object"}, - prop2: {type: "object", allowedContexts: ["test_five"]}, - prop3: {type: "number", value: 1}, - prop4: {type: "number", value: 1, allowedContexts: ["numeric_three"]}, - }, - }, - { - namespace: "withAllowedContextsAndDefault", - allowedContexts: ["test_six"], - defaultContexts: ["test_seven"], - properties: { - prop1: {type: "object"}, - prop2: {type: "object", allowedContexts: ["test_eight"]}, - prop3: {type: "number", value: 1}, - prop4: {type: "number", value: 1, allowedContexts: ["numeric_four"]}, - }, - }, - { - namespace: "with_submodule", - defaultContexts: ["test_nine"], - types: [{ - id: "subtype", - type: "object", - functions: [{ - name: "noAllowedContexts", - type: "function", - parameters: [], - }, { - name: "allowedContexts", - allowedContexts: ["test_ten"], - type: "function", - parameters: [], - }], - }], - properties: { - prop1: {$ref: "subtype"}, - prop2: {$ref: "subtype", allowedContexts: ["test_eleven"]}, - }, - }, -]; -add_task(function* testRestrictions() { - let url = "data:," + JSON.stringify(schemaJson); - yield Schemas.load(url); - let results = {}; - let localWrapper = { - shouldInject(ns, name, allowedContexts) { - name = name === null ? ns : ns + "." + name; - results[name] = allowedContexts.join(","); - return true; - }, - getImplementation() { - // The actual implementation is not significant for this test. - // Let's take this opportunity to see if schema generation is free of - // exceptions even when somehow getImplementation does not return an - // implementation. - }, - }; - - let root = {}; - Schemas.inject(root, localWrapper); - - function verify(path, expected) { - let obj = root; - for (let thing of path.split(".")) { - try { - obj = obj[thing]; - } catch (e) { - // Blech. - } - } - - let result = results[path]; - equal(result, expected); - } - - verify("noAllowedContexts", ""); - verify("noAllowedContexts.prop1", ""); - verify("noAllowedContexts.prop2", "test_zero,test_one"); - verify("noAllowedContexts.prop3", ""); - verify("noAllowedContexts.prop4", "numeric_one"); - - verify("defaultContexts", ""); - verify("defaultContexts.prop1", "test_two"); - verify("defaultContexts.prop2", "test_three"); - verify("defaultContexts.prop3", "test_two"); - verify("defaultContexts.prop4", "numeric_two"); - - verify("withAllowedContexts", "test_four"); - verify("withAllowedContexts.prop1", ""); - verify("withAllowedContexts.prop2", "test_five"); - verify("withAllowedContexts.prop3", ""); - verify("withAllowedContexts.prop4", "numeric_three"); - - verify("withAllowedContextsAndDefault", "test_six"); - verify("withAllowedContextsAndDefault.prop1", "test_seven"); - verify("withAllowedContextsAndDefault.prop2", "test_eight"); - verify("withAllowedContextsAndDefault.prop3", "test_seven"); - verify("withAllowedContextsAndDefault.prop4", "numeric_four"); - - verify("with_submodule", ""); - verify("with_submodule.prop1", "test_nine"); - verify("with_submodule.prop1.noAllowedContexts", "test_nine"); - verify("with_submodule.prop1.allowedContexts", "test_ten"); - verify("with_submodule.prop2", "test_eleven"); - // Note: test_nine inherits allowed contexts from the namespace, not from - // submodule. There is no "defaultContexts" for submodule types to not - // complicate things. - verify("with_submodule.prop1.noAllowedContexts", "test_nine"); - verify("with_submodule.prop1.allowedContexts", "test_ten"); - - // This is a constant, so it does not matter that getImplementation does not - // return an implementation since the API injector should take care of it. - equal(root.noAllowedContexts.prop3, 1); - - Assert.throws(() => root.noAllowedContexts.prop1, - /undefined/, - "Should throw when the implementation is absent."); -}); - diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_schemas_api_injection.js b/toolkit/components/webextensions/test/xpcshell/test_ext_schemas_api_injection.js deleted file mode 100644 index 36d88d722..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_schemas_api_injection.js +++ /dev/null @@ -1,102 +0,0 @@ -"use strict"; - -Components.utils.import("resource://gre/modules/ExtensionCommon.jsm"); -Components.utils.import("resource://gre/modules/Schemas.jsm"); - -let { - BaseContext, - SchemaAPIManager, -} = ExtensionCommon; - -let nestedNamespaceJson = [ - { - "namespace": "backgroundAPI.testnamespace", - "functions": [ - { - "name": "create", - "type": "function", - "parameters": [ - { - "name": "title", - "type": "string", - }, - ], - "returns": { - "type": "string", - }, - }, - ], - }, - { - "namespace": "noBackgroundAPI.testnamespace", - "functions": [ - { - "name": "create", - "type": "function", - "parameters": [ - { - "name": "title", - "type": "string", - }, - ], - }, - ], - }, -]; - -let global = this; -class StubContext extends BaseContext { - constructor() { - let fakeExtension = {id: "test@web.extension"}; - super("addon_child", fakeExtension); - this.sandbox = Cu.Sandbox(global); - this.viewType = "background"; - } - - get cloneScope() { - return this.sandbox; - } -} - -add_task(function* testSchemaAPIInjection() { - let url = "data:," + JSON.stringify(nestedNamespaceJson); - - // Load the schema of the fake APIs. - yield Schemas.load(url); - - let apiManager = new SchemaAPIManager("addon"); - - // Register an API that will skip the background page. - apiManager.registerSchemaAPI("noBackgroundAPI.testnamespace", "addon_child", context => { - // This API should not be available in this context, return null so that - // the schema wrapper is removed as well. - return null; - }); - - // Register an API that will skip any but the background page. - apiManager.registerSchemaAPI("backgroundAPI.testnamespace", "addon_child", context => { - if (context.viewType === "background") { - return { - backgroundAPI: { - testnamespace: { - create(title) { - return title; - }, - }, - }, - }; - } - - // This API should not be available in this context, return null so that - // the schema wrapper is removed as well. - return null; - }); - - let context = new StubContext(); - let browserObj = {}; - apiManager.generateAPIs(context, browserObj); - - do_check_eq(browserObj.noBackgroundAPI, undefined); - const res = browserObj.backgroundAPI.testnamespace.create("param-value"); - do_check_eq(res, "param-value"); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_schemas_async.js b/toolkit/components/webextensions/test/xpcshell/test_ext_schemas_async.js deleted file mode 100644 index 6397d1f96..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_schemas_async.js +++ /dev/null @@ -1,232 +0,0 @@ -"use strict"; - -Components.utils.import("resource://gre/modules/ExtensionCommon.jsm"); -Components.utils.import("resource://gre/modules/Schemas.jsm"); - -let {BaseContext, LocalAPIImplementation} = ExtensionCommon; - -let schemaJson = [ - { - namespace: "testnamespace", - functions: [{ - name: "one_required", - type: "function", - parameters: [{ - name: "first", - type: "function", - parameters: [], - }], - }, { - name: "one_optional", - type: "function", - parameters: [{ - name: "first", - type: "function", - parameters: [], - optional: true, - }], - }, { - name: "async_required", - type: "function", - async: "first", - parameters: [{ - name: "first", - type: "function", - parameters: [], - }], - }, { - name: "async_optional", - type: "function", - async: "first", - parameters: [{ - name: "first", - type: "function", - parameters: [], - optional: true, - }], - }], - }, -]; - -const global = this; -class StubContext extends BaseContext { - constructor() { - let fakeExtension = {id: "test@web.extension"}; - super("testEnv", fakeExtension); - this.sandbox = Cu.Sandbox(global); - } - - get cloneScope() { - return this.sandbox; - } - - get principal() { - return Cu.getObjectPrincipal(this.sandbox); - } -} - -let context; - -function generateAPIs(extraWrapper, apiObj) { - context = new StubContext(); - let localWrapper = { - shouldInject() { - return true; - }, - getImplementation(namespace, name) { - return new LocalAPIImplementation(apiObj, name, context); - }, - }; - Object.assign(localWrapper, extraWrapper); - - let root = {}; - Schemas.inject(root, localWrapper); - return root.testnamespace; -} - -add_task(function* testParameterValidation() { - yield Schemas.load("data:," + JSON.stringify(schemaJson)); - - let testnamespace; - function assertThrows(name, ...args) { - Assert.throws(() => testnamespace[name](...args), - /Incorrect argument types/, - `Expected testnamespace.${name}(${args.map(String).join(", ")}) to throw.`); - } - function assertNoThrows(name, ...args) { - try { - testnamespace[name](...args); - } catch (e) { - do_print(`testnamespace.${name}(${args.map(String).join(", ")}) unexpectedly threw.`); - throw new Error(e); - } - } - let cb = () => {}; - - for (let isChromeCompat of [true, false]) { - do_print(`Testing API validation with isChromeCompat=${isChromeCompat}`); - testnamespace = generateAPIs({ - isChromeCompat, - }, { - one_required() {}, - one_optional() {}, - async_required() {}, - async_optional() {}, - }); - - assertThrows("one_required"); - assertThrows("one_required", null); - assertNoThrows("one_required", cb); - assertThrows("one_required", cb, null); - assertThrows("one_required", cb, cb); - - assertNoThrows("one_optional"); - assertNoThrows("one_optional", null); - assertNoThrows("one_optional", cb); - assertThrows("one_optional", cb, null); - assertThrows("one_optional", cb, cb); - - // Schema-based validation happens before an async method is called, so - // errors should be thrown synchronously. - - // The parameter was declared as required, but there was also an "async" - // attribute with the same value as the parameter name, so the callback - // parameter is actually optional. - assertNoThrows("async_required"); - assertNoThrows("async_required", null); - assertNoThrows("async_required", cb); - assertThrows("async_required", cb, null); - assertThrows("async_required", cb, cb); - - assertNoThrows("async_optional"); - assertNoThrows("async_optional", null); - assertNoThrows("async_optional", cb); - assertThrows("async_optional", cb, null); - assertThrows("async_optional", cb, cb); - } -}); - -add_task(function* testAsyncResults() { - yield Schemas.load("data:," + JSON.stringify(schemaJson)); - function* runWithCallback(func) { - do_print(`Calling testnamespace.${func.name}, expecting callback with result`); - return yield new Promise(resolve => { - let result = "uninitialized value"; - let returnValue = func(reply => { - result = reply; - resolve(result); - }); - // When a callback is given, the return value must be missing. - do_check_eq(returnValue, undefined); - // Callback must be called asynchronously. - do_check_eq(result, "uninitialized value"); - }); - } - - function* runFailCallback(func) { - do_print(`Calling testnamespace.${func.name}, expecting callback with error`); - return yield new Promise(resolve => { - func(reply => { - do_check_eq(reply, undefined); - resolve(context.lastError.message); // eslint-disable-line no-undef - }); - }); - } - - for (let isChromeCompat of [true, false]) { - do_print(`Testing API invocation with isChromeCompat=${isChromeCompat}`); - let testnamespace = generateAPIs({ - isChromeCompat, - }, { - async_required(cb) { - do_check_eq(cb, undefined); - return Promise.resolve(1); - }, - async_optional(cb) { - do_check_eq(cb, undefined); - return Promise.resolve(2); - }, - }); - if (!isChromeCompat) { // No promises for chrome. - do_print("testnamespace.async_required should be a Promise"); - let promise = testnamespace.async_required(); - do_check_true(promise instanceof context.cloneScope.Promise); - do_check_eq(yield promise, 1); - - do_print("testnamespace.async_optional should be a Promise"); - promise = testnamespace.async_optional(); - do_check_true(promise instanceof context.cloneScope.Promise); - do_check_eq(yield promise, 2); - } - - do_check_eq(yield* runWithCallback(testnamespace.async_required), 1); - do_check_eq(yield* runWithCallback(testnamespace.async_optional), 2); - - let otherSandbox = Cu.Sandbox(null, {}); - let errorFactories = [ - msg => { throw new context.cloneScope.Error(msg); }, - msg => context.cloneScope.Promise.reject({message: msg}), - msg => Cu.evalInSandbox(`throw new Error("${msg}")`, otherSandbox), - msg => Cu.evalInSandbox(`Promise.reject({message: "${msg}"})`, otherSandbox), - ]; - for (let makeError of errorFactories) { - do_print(`Testing callback/promise with error caused by: ${makeError}`); - testnamespace = generateAPIs({ - isChromeCompat, - }, { - async_required() { return makeError("ONE"); }, - async_optional() { return makeError("TWO"); }, - }); - - if (!isChromeCompat) { // No promises for chrome. - yield Assert.rejects(testnamespace.async_required(), /ONE/, - "should reject testnamespace.async_required()").catch(() => {}); - yield Assert.rejects(testnamespace.async_optional(), /TWO/, - "should reject testnamespace.async_optional()").catch(() => {}); - } - - do_check_eq(yield* runFailCallback(testnamespace.async_required), "ONE"); - do_check_eq(yield* runFailCallback(testnamespace.async_optional), "TWO"); - } - } -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_simple.js b/toolkit/components/webextensions/test/xpcshell/test_ext_simple.js deleted file mode 100644 index 91b10354c..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_simple.js +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_simple() { - let extensionData = { - manifest: { - "name": "Simple extension test", - "version": "1.0", - "manifest_version": 2, - "description": "", - }, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - yield extension.unload(); -}); - -add_task(function* test_background() { - 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, - manifest: { - "name": "Simple extension test", - "version": "1.0", - "manifest_version": 2, - "description": "", - }, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - - let [, x] = yield Promise.all([extension.startup(), extension.awaitMessage("running")]); - equal(x, 1, "got correct value from extension"); - - extension.sendMessage(10, 20); - yield extension.awaitFinish(); - yield extension.unload(); -}); - -add_task(function* test_extensionTypes() { - let extensionData = { - background: function() { - browser.test.assertEq(typeof browser.extensionTypes, "object", "browser.extensionTypes exists"); - browser.test.assertEq(typeof browser.extensionTypes.RunAt, "object", "browser.extensionTypes.RunAt exists"); - browser.test.notifyPass("extentionTypes test passed"); - }, - }; - - let extension = ExtensionTestUtils.loadExtension(extensionData); - - yield extension.startup(); - yield extension.awaitFinish(); - yield extension.unload(); -}); - diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_storage.js b/toolkit/components/webextensions/test/xpcshell/test_ext_storage.js deleted file mode 100644 index df46dfb63..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_storage.js +++ /dev/null @@ -1,334 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -const STORAGE_SYNC_PREF = "webextensions.storage.sync.enabled"; -Cu.import("resource://gre/modules/Preferences.jsm"); - -/** - * 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}`); -} - -add_task(function* test_local_cache_invalidation() { - 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"); - - Services.obs.notifyObservers(null, "extension-invalidate-storage-cache", ""); - - extension.sendMessage("check"); - yield extension.awaitMessage("check-done"); - - yield extension.unload(); -}); - -add_task(function* test_config_flag_needed() { - 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")); - } - - ok(!Preferences.get(STORAGE_SYNC_PREF)); - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - permissions: ["storage"], - }, - background: `(${background})(${checkGetImpl})`, - }); - - yield extension.startup(); - yield extension.awaitFinish("flag needed"); - yield extension.unload(); -}); - -add_task(function* test_reloading_extensions_works() { - // Just some random extension ID that we can re-use - const extensionId = "my-extension-id@1"; - - function loadExtension() { - function background() { - browser.storage.sync.set({"a": "b"}).then(() => { - browser.test.notifyPass("set-works"); - }); - } - - return ExtensionTestUtils.loadExtension({ - manifest: { - permissions: ["storage"], - }, - background: `(${background})()`, - }, extensionId); - } - - Preferences.set(STORAGE_SYNC_PREF, true); - - let extension1 = loadExtension(); - - yield extension1.startup(); - yield extension1.awaitFinish("set-works"); - yield extension1.unload(); - - let extension2 = loadExtension(); - - yield extension2.startup(); - yield extension2.awaitFinish("set-works"); - yield extension2.unload(); - - Preferences.reset(STORAGE_SYNC_PREF); -}); - -do_register_cleanup(() => { - Preferences.reset(STORAGE_SYNC_PREF); -}); - -add_task(function* test_backgroundScript() { - async function backgroundScript(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 = { - background: `(${backgroundScript})(${checkGetImpl})`, - manifest: { - permissions: ["storage"], - }, - }; - - Preferences.set(STORAGE_SYNC_PREF, true); - - let extension = ExtensionTestUtils.loadExtension(extensionData); - yield extension.startup(); - yield extension.awaitMessage("ready"); - - extension.sendMessage("test-local"); - yield extension.awaitMessage("test-finished"); - - extension.sendMessage("test-sync"); - yield extension.awaitMessage("test-finished"); - - Preferences.reset(STORAGE_SYNC_PREF); - yield extension.unload(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_ext_topSites.js b/toolkit/components/webextensions/test/xpcshell/test_ext_topSites.js deleted file mode 100644 index eb3f552ed..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_ext_topSites.js +++ /dev/null @@ -1,85 +0,0 @@ -"use strict"; - -Cu.import("resource://gre/modules/NewTabUtils.jsm"); - - -function TestProvider(getLinksFn) { - this.getLinks = getLinksFn; - this._observers = new Set(); -} - -TestProvider.prototype = { - addObserver: function(observer) { - this._observers.add(observer); - }, - notifyLinkChanged: function(link, index = -1, deleted = false) { - this._notifyObservers("onLinkChanged", link, index, deleted); - }, - notifyManyLinksChanged: function() { - this._notifyObservers("onManyLinksChanged"); - }, - _notifyObservers: function(observerMethodName, ...args) { - args.unshift(this); - for (let obs of this._observers) { - if (obs[observerMethodName]) { - obs[observerMethodName].apply(NewTabUtils.links, args); - } - } - }, -}; - -function makeLinks(links) { - // Important: To avoid test failures due to clock jitter on Windows XP, call - // Date.now() once here, not each time through the loop. - let frecency = 0; - let now = Date.now() * 1000; - let places = []; - links.map((link, i) => { - places.push({ - url: link.url, - title: link.title, - lastVisitDate: now - i, - frecency: frecency++, - }); - }); - return places; -} - -add_task(function* test_topSites() { - let expect = [{url: "http://example.com/", title: "site#-1"}, - {url: "http://example0.com/", title: "site#0"}, - {url: "http://example1.com/", title: "site#1"}, - {url: "http://example2.com/", title: "site#2"}, - {url: "http://example3.com/", title: "site#3"}]; - - let extension = ExtensionTestUtils.loadExtension({ - manifest: { - "permissions": [ - "topSites", - ], - }, - background() { - browser.topSites.get(result => { - browser.test.sendMessage("done", result); - }); - }, - }); - - - let expectedLinks = makeLinks(expect); - let provider = new TestProvider(done => done(expectedLinks)); - - NewTabUtils.initWithoutProviders(); - NewTabUtils.links.addProvider(provider); - - yield NewTabUtils.links.populateCache(); - - yield extension.startup(); - - let result = yield extension.awaitMessage("done"); - Assert.deepEqual(expect, result, "got topSites"); - - yield extension.unload(); - - NewTabUtils.links.removeProvider(provider); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_getAPILevelForWindow.js b/toolkit/components/webextensions/test/xpcshell/test_getAPILevelForWindow.js deleted file mode 100644 index 68741a6cc..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_getAPILevelForWindow.js +++ /dev/null @@ -1,55 +0,0 @@ -"use strict"; - -Cu.import("resource://gre/modules/ExtensionManagement.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -function createWindowWithAddonId(addonId) { - let baseURI = Services.io.newURI("about:blank", null, null); - let originAttributes = {addonId}; - let principal = Services.scriptSecurityManager - .createCodebasePrincipal(baseURI, originAttributes); - let chromeNav = Services.appShell.createWindowlessBrowser(true); - let interfaceRequestor = chromeNav.QueryInterface(Ci.nsIInterfaceRequestor); - let docShell = interfaceRequestor.getInterface(Ci.nsIDocShell); - docShell.createAboutBlankContentViewer(principal); - - return {chromeNav, window: docShell.contentViewer.DOMDocument.defaultView}; -} - -add_task(function* test_eventpages() { - const {getAPILevelForWindow, getAddonIdForWindow} = ExtensionManagement; - const {NO_PRIVILEGES, FULL_PRIVILEGES} = ExtensionManagement.API_LEVELS; - const FAKE_ADDON_ID = "fakeAddonId"; - const OTHER_ADDON_ID = "otherFakeAddonId"; - const EMPTY_ADDON_ID = ""; - - let fakeAddonId = createWindowWithAddonId(FAKE_ADDON_ID); - equal(getAddonIdForWindow(fakeAddonId.window), FAKE_ADDON_ID, - "the window has the expected addonId"); - - let apiLevel = getAPILevelForWindow(fakeAddonId.window, FAKE_ADDON_ID); - equal(apiLevel, FULL_PRIVILEGES, - "apiLevel for the window with the right addonId should be FULL_PRIVILEGES"); - - apiLevel = getAPILevelForWindow(fakeAddonId.window, OTHER_ADDON_ID); - equal(apiLevel, NO_PRIVILEGES, - "apiLevel for the window with a different addonId should be NO_PRIVILEGES"); - - fakeAddonId.chromeNav.close(); - - // NOTE: check that window with an empty addon Id (which are window that are - // not Extensions pages) always get no WebExtensions APIs. - let emptyAddonId = createWindowWithAddonId(EMPTY_ADDON_ID); - equal(getAddonIdForWindow(emptyAddonId.window), EMPTY_ADDON_ID, - "the window has the expected addonId"); - - apiLevel = getAPILevelForWindow(emptyAddonId.window, EMPTY_ADDON_ID); - equal(apiLevel, NO_PRIVILEGES, - "apiLevel for empty addonId should be NO_PRIVILEGES"); - - apiLevel = getAPILevelForWindow(emptyAddonId.window, OTHER_ADDON_ID); - equal(apiLevel, NO_PRIVILEGES, - "apiLevel for an 'empty addonId' window should be always NO_PRIVILEGES"); - - emptyAddonId.chromeNav.close(); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_locale_converter.js b/toolkit/components/webextensions/test/xpcshell/test_locale_converter.js deleted file mode 100644 index c8b1ee92b..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_locale_converter.js +++ /dev/null @@ -1,133 +0,0 @@ -"use strict"; - -const convService = Cc["@mozilla.org/streamConverters;1"] - .getService(Ci.nsIStreamConverterService); - -const UUID = "72b61ee3-aceb-476c-be1b-0822b036c9f1"; -const ADDON_ID = "test@web.extension"; -const URI = NetUtil.newURI(`moz-extension://${UUID}/file.css`); - -const FROM_TYPE = "application/vnd.mozilla.webext.unlocalized"; -const TO_TYPE = "text/css"; - - -function StringStream(string) { - let stream = Cc["@mozilla.org/io/string-input-stream;1"] - .createInstance(Ci.nsIStringInputStream); - - stream.data = string; - return stream; -} - - -// Initialize the policy service with a stub localizer for our -// add-on ID. -add_task(function* init() { - const aps = Cc["@mozilla.org/addons/policy-service;1"] - .getService(Ci.nsIAddonPolicyService).wrappedJSObject; - - let oldCallback = aps.setExtensionURIToAddonIdCallback(uri => { - if (uri.host == UUID) { - return ADDON_ID; - } - }); - - aps.setAddonLocalizeCallback(ADDON_ID, string => { - return string.replace(/__MSG_(.*?)__/g, "<localized-$1>"); - }); - - do_register_cleanup(() => { - aps.setExtensionURIToAddonIdCallback(oldCallback); - aps.setAddonLocalizeCallback(ADDON_ID, null); - }); -}); - - -// Test that the synchronous converter works as expected with a -// simple string. -add_task(function* testSynchronousConvert() { - let stream = StringStream("Foo __MSG_xxx__ bar __MSG_yyy__ baz"); - - let resultStream = convService.convert(stream, FROM_TYPE, TO_TYPE, URI); - - let result = NetUtil.readInputStreamToString(resultStream, resultStream.available()); - - equal(result, "Foo <localized-xxx> bar <localized-yyy> baz"); -}); - - -// Test that the asynchronous converter works as expected with input -// split into multiple chunks, and a boundary in the middle of a -// replacement token. -add_task(function* testAsyncConvert() { - let listener; - let awaitResult = new Promise((resolve, reject) => { - listener = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener]), - - onDataAvailable(request, context, inputStream, offset, count) { - this.resultParts.push(NetUtil.readInputStreamToString(inputStream, count)); - }, - - onStartRequest() { - ok(!("resultParts" in this)); - this.resultParts = []; - }, - - onStopRequest(request, context, statusCode) { - if (!Components.isSuccessCode(statusCode)) { - reject(new Error(statusCode)); - } - - resolve(this.resultParts.join("\n")); - }, - }; - }); - - let parts = ["Foo __MSG_x", "xx__ bar __MSG_yyy__ baz"]; - - let converter = convService.asyncConvertData(FROM_TYPE, TO_TYPE, listener, URI); - converter.onStartRequest(null, null); - - for (let part of parts) { - converter.onDataAvailable(null, null, StringStream(part), 0, part.length); - } - - converter.onStopRequest(null, null, Cr.NS_OK); - - - let result = yield awaitResult; - equal(result, "Foo <localized-xxx> bar <localized-yyy> baz"); -}); - - -// Test that attempting to initialize a converter with the URI of a -// nonexistent WebExtension fails. -add_task(function* testInvalidUUID() { - let uri = NetUtil.newURI("moz-extension://eb4f3be8-41c9-4970-aa6d-b84d1ecc02b2/file.css"); - let stream = StringStream("Foo __MSG_xxx__ bar __MSG_yyy__ baz"); - - // Assert.throws raise a TypeError exception when the expected param - // is an arrow function. (See Bug 1237961 for rationale) - let expectInvalidContextException = function(e) { - return e.result === Cr.NS_ERROR_INVALID_ARG && /Invalid context/.test(e); - }; - - Assert.throws(() => { - convService.convert(stream, FROM_TYPE, TO_TYPE, uri); - }, expectInvalidContextException); - - Assert.throws(() => { - let listener = {QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener])}; - - convService.asyncConvertData(FROM_TYPE, TO_TYPE, listener, uri); - }, expectInvalidContextException); -}); - - -// Test that an empty stream does not throw an NS_ERROR_ILLEGAL_VALUE. -add_task(function* testEmptyStream() { - let stream = StringStream(""); - let resultStream = convService.convert(stream, FROM_TYPE, TO_TYPE, URI); - equal(resultStream.data, ""); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_locale_data.js b/toolkit/components/webextensions/test/xpcshell/test_locale_data.js deleted file mode 100644 index c3cd44e57..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_locale_data.js +++ /dev/null @@ -1,130 +0,0 @@ -"use strict"; - -Cu.import("resource://gre/modules/Extension.jsm"); - -/* globals ExtensionData */ - -const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); - -function* generateAddon(data) { - let id = uuidGenerator.generateUUID().number; - - data = Object.assign({embedded: true}, data); - data.manifest = Object.assign({applications: {gecko: {id}}}, data.manifest); - - let xpi = Extension.generateXPI(data); - do_register_cleanup(() => { - Services.obs.notifyObservers(xpi, "flush-cache-entry", null); - xpi.remove(false); - }); - - let fileURI = Services.io.newFileURI(xpi); - let jarURI = NetUtil.newURI(`jar:${fileURI.spec}!/webextension/`); - - let extension = new ExtensionData(jarURI); - yield extension.readManifest(); - - return extension; -} - -add_task(function* testMissingDefaultLocale() { - let extension = yield generateAddon({ - "files": { - "_locales/en_US/messages.json": {}, - }, - }); - - equal(extension.errors.length, 0, "No errors reported"); - - yield extension.initAllLocales(); - - equal(extension.errors.length, 1, "One error reported"); - - do_print(`Got error: ${extension.errors[0]}`); - - ok(extension.errors[0].includes('"default_locale" property is required'), - "Got missing default_locale error"); -}); - - -add_task(function* testInvalidDefaultLocale() { - let extension = yield generateAddon({ - "manifest": { - "default_locale": "en", - }, - - "files": { - "_locales/en_US/messages.json": {}, - }, - }); - - equal(extension.errors.length, 1, "One error reported"); - - do_print(`Got error: ${extension.errors[0]}`); - - ok(extension.errors[0].includes("Loading locale file _locales/en/messages.json"), - "Got invalid default_locale error"); - - yield extension.initAllLocales(); - - equal(extension.errors.length, 2, "Two errors reported"); - - do_print(`Got error: ${extension.errors[1]}`); - - ok(extension.errors[1].includes('"default_locale" property must correspond'), - "Got invalid default_locale error"); -}); - - -add_task(function* testUnexpectedDefaultLocale() { - let extension = yield generateAddon({ - "manifest": { - "default_locale": "en_US", - }, - }); - - equal(extension.errors.length, 1, "One error reported"); - - do_print(`Got error: ${extension.errors[0]}`); - - ok(extension.errors[0].includes("Loading locale file _locales/en-US/messages.json"), - "Got invalid default_locale error"); - - yield extension.initAllLocales(); - - equal(extension.errors.length, 2, "One error reported"); - - do_print(`Got error: ${extension.errors[1]}`); - - ok(extension.errors[1].includes('"default_locale" property must correspond'), - "Got unexpected default_locale error"); -}); - - -add_task(function* testInvalidSyntax() { - let extension = yield generateAddon({ - "manifest": { - "default_locale": "en_US", - }, - - "files": { - "_locales/en_US/messages.json": '{foo: {message: "bar", description: "baz"}}', - }, - }); - - equal(extension.errors.length, 1, "No errors reported"); - - do_print(`Got error: ${extension.errors[0]}`); - - ok(extension.errors[0].includes("Loading locale file _locales\/en_US\/messages\.json: SyntaxError"), - "Got syntax error"); - - yield extension.initAllLocales(); - - equal(extension.errors.length, 2, "One error reported"); - - do_print(`Got error: ${extension.errors[1]}`); - - ok(extension.errors[1].includes("Loading locale file _locales\/en_US\/messages\.json: SyntaxError"), - "Got syntax error"); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/test_native_messaging.js b/toolkit/components/webextensions/test/xpcshell/test_native_messaging.js deleted file mode 100644 index 1fcb7799e..000000000 --- a/toolkit/components/webextensions/test/xpcshell/test_native_messaging.js +++ /dev/null @@ -1,302 +0,0 @@ -"use strict"; - -/* global OS, HostManifestManager, NativeApp */ -Cu.import("resource://gre/modules/AppConstants.jsm"); -Cu.import("resource://gre/modules/AsyncShutdown.jsm"); -Cu.import("resource://gre/modules/ExtensionCommon.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/Schemas.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -const {Subprocess, SubprocessImpl} = Cu.import("resource://gre/modules/Subprocess.jsm"); -Cu.import("resource://gre/modules/NativeMessaging.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); - -let registry = null; -if (AppConstants.platform == "win") { - Cu.import("resource://testing-common/MockRegistry.jsm"); - registry = new MockRegistry(); - do_register_cleanup(() => { - registry.shutdown(); - }); -} - -const REGPATH = "Software\\Mozilla\\NativeMessagingHosts"; - -const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json"; - -let dir = FileUtils.getDir("TmpD", ["NativeMessaging"]); -dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - -let userDir = dir.clone(); -userDir.append("user"); -userDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - -let globalDir = dir.clone(); -globalDir.append("global"); -globalDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - -let dirProvider = { - getFile(property) { - if (property == "XREUserNativeMessaging") { - return userDir.clone(); - } else if (property == "XRESysNativeMessaging") { - return globalDir.clone(); - } - return null; - }, -}; - -Services.dirsvc.registerProvider(dirProvider); - -do_register_cleanup(() => { - Services.dirsvc.unregisterProvider(dirProvider); - dir.remove(true); -}); - -function writeManifest(path, manifest) { - if (typeof manifest != "string") { - manifest = JSON.stringify(manifest); - } - return OS.File.writeAtomic(path, manifest); -} - -let PYTHON; -add_task(function* setup() { - yield Schemas.load(BASE_SCHEMA); - - PYTHON = yield Subprocess.pathSearch("python2.7"); - if (PYTHON == null) { - PYTHON = yield Subprocess.pathSearch("python"); - } - notEqual(PYTHON, null, "Found a suitable python interpreter"); -}); - -let global = this; - -// Test of HostManifestManager.lookupApplication() begin here... -let context = { - url: null, - jsonStringify(...args) { return JSON.stringify(...args); }, - cloneScope: global, - logError() {}, - preprocessors: {}, - callOnClose: () => {}, - forgetOnClose: () => {}, -}; - -class MockContext extends ExtensionCommon.BaseContext { - constructor(extensionId) { - let fakeExtension = {id: extensionId}; - super("testEnv", fakeExtension); - this.sandbox = Cu.Sandbox(global); - } - - get cloneScope() { - return global; - } - - get principal() { - return Cu.getObjectPrincipal(this.sandbox); - } -} - -let templateManifest = { - name: "test", - description: "this is only a test", - path: "/bin/cat", - type: "stdio", - allowed_extensions: ["extension@tests.mozilla.org"], -}; - -add_task(function* test_nonexistent_manifest() { - let result = yield HostManifestManager.lookupApplication("test", context); - equal(result, null, "lookupApplication returns null for non-existent application"); -}); - -const USER_TEST_JSON = OS.Path.join(userDir.path, "test.json"); - -add_task(function* test_good_manifest() { - yield writeManifest(USER_TEST_JSON, templateManifest); - if (registry) { - registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, - `${REGPATH}\\test`, "", USER_TEST_JSON); - } - - let result = yield HostManifestManager.lookupApplication("test", context); - notEqual(result, null, "lookupApplication finds a good manifest"); - equal(result.path, USER_TEST_JSON, "lookupApplication returns the correct path"); - deepEqual(result.manifest, templateManifest, "lookupApplication returns the manifest contents"); -}); - -add_task(function* test_invalid_json() { - yield writeManifest(USER_TEST_JSON, "this is not valid json"); - let result = yield HostManifestManager.lookupApplication("test", context); - equal(result, null, "lookupApplication ignores bad json"); -}); - -add_task(function* test_invalid_name() { - let manifest = Object.assign({}, templateManifest); - manifest.name = "../test"; - yield writeManifest(USER_TEST_JSON, manifest); - let result = yield HostManifestManager.lookupApplication("test", context); - equal(result, null, "lookupApplication ignores an invalid name"); -}); - -add_task(function* test_name_mismatch() { - let manifest = Object.assign({}, templateManifest); - manifest.name = "not test"; - yield writeManifest(USER_TEST_JSON, manifest); - let result = yield HostManifestManager.lookupApplication("test", context); - let what = (AppConstants.platform == "win") ? "registry key" : "json filename"; - equal(result, null, `lookupApplication ignores mistmatch between ${what} and name property`); -}); - -add_task(function* test_missing_props() { - const PROPS = [ - "name", - "description", - "path", - "type", - "allowed_extensions", - ]; - for (let prop of PROPS) { - let manifest = Object.assign({}, templateManifest); - delete manifest[prop]; - - yield writeManifest(USER_TEST_JSON, manifest); - let result = yield HostManifestManager.lookupApplication("test", context); - equal(result, null, `lookupApplication ignores missing ${prop}`); - } -}); - -add_task(function* test_invalid_type() { - let manifest = Object.assign({}, templateManifest); - manifest.type = "bogus"; - yield writeManifest(USER_TEST_JSON, manifest); - let result = yield HostManifestManager.lookupApplication("test", context); - equal(result, null, "lookupApplication ignores invalid type"); -}); - -add_task(function* test_no_allowed_extensions() { - let manifest = Object.assign({}, templateManifest); - manifest.allowed_extensions = []; - yield writeManifest(USER_TEST_JSON, manifest); - let result = yield HostManifestManager.lookupApplication("test", context); - equal(result, null, "lookupApplication ignores manifest with no allowed_extensions"); -}); - -const GLOBAL_TEST_JSON = OS.Path.join(globalDir.path, "test.json"); -let globalManifest = Object.assign({}, templateManifest); -globalManifest.description = "This manifest is from the systemwide directory"; - -add_task(function* good_manifest_system_dir() { - yield OS.File.remove(USER_TEST_JSON); - yield writeManifest(GLOBAL_TEST_JSON, globalManifest); - if (registry) { - registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, - `${REGPATH}\\test`, "", null); - registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, - `${REGPATH}\\test`, "", GLOBAL_TEST_JSON); - } - - let where = (AppConstants.platform == "win") ? "registry location" : "directory"; - let result = yield HostManifestManager.lookupApplication("test", context); - notEqual(result, null, `lookupApplication finds a manifest in the system-wide ${where}`); - equal(result.path, GLOBAL_TEST_JSON, `lookupApplication returns path in the system-wide ${where}`); - deepEqual(result.manifest, globalManifest, `lookupApplication returns manifest contents from the system-wide ${where}`); -}); - -add_task(function* test_user_dir_precedence() { - yield writeManifest(USER_TEST_JSON, templateManifest); - if (registry) { - registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, - `${REGPATH}\\test`, "", USER_TEST_JSON); - } - // global test.json and LOCAL_MACHINE registry key on windows are - // still present from the previous test - - let result = yield HostManifestManager.lookupApplication("test", context); - notEqual(result, null, "lookupApplication finds a manifest when entries exist in both user-specific and system-wide locations"); - equal(result.path, USER_TEST_JSON, "lookupApplication returns the user-specific path when user-specific and system-wide entries both exist"); - deepEqual(result.manifest, templateManifest, "lookupApplication returns user-specific manifest contents with user-specific and system-wide entries both exist"); -}); - -// Test shutdown handling in NativeApp -add_task(function* test_native_app_shutdown() { - const SCRIPT = String.raw` -import signal -import struct -import sys - -signal.signal(signal.SIGTERM, signal.SIG_IGN) - -while True: - rawlen = sys.stdin.read(4) - if len(rawlen) == 0: - signal.pause() - msglen = struct.unpack('@I', rawlen)[0] - msg = sys.stdin.read(msglen) - - sys.stdout.write(struct.pack('@I', msglen)) - sys.stdout.write(msg) - `; - - let scriptPath = OS.Path.join(userDir.path, "wontdie.py"); - let manifestPath = OS.Path.join(userDir.path, "wontdie.json"); - - const ID = "native@tests.mozilla.org"; - let manifest = { - name: "wontdie", - description: "test async shutdown of native apps", - type: "stdio", - allowed_extensions: [ID], - }; - - if (AppConstants.platform == "win") { - yield OS.File.writeAtomic(scriptPath, SCRIPT); - - let batPath = OS.Path.join(userDir.path, "wontdie.bat"); - let batBody = `@ECHO OFF\n${PYTHON} -u "${scriptPath}" %*\n`; - yield OS.File.writeAtomic(batPath, batBody); - yield OS.File.setPermissions(batPath, {unixMode: 0o755}); - - manifest.path = batPath; - yield writeManifest(manifestPath, manifest); - - registry.setValue(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, - `${REGPATH}\\wontdie`, "", manifestPath); - } else { - yield OS.File.writeAtomic(scriptPath, `#!${PYTHON} -u\n${SCRIPT}`); - yield OS.File.setPermissions(scriptPath, {unixMode: 0o755}); - manifest.path = scriptPath; - yield writeManifest(manifestPath, manifest); - } - - let mockContext = new MockContext(ID); - let app = new NativeApp(mockContext, "wontdie"); - - // send a message and wait for the reply to make sure the app is running - let MSG = "test"; - let recvPromise = new Promise(resolve => { - let listener = (what, msg) => { - equal(msg, MSG, "Received test message"); - app.off("message", listener); - resolve(); - }; - app.on("message", listener); - }); - - let buffer = NativeApp.encodeMessage(mockContext, MSG); - app.send(buffer); - yield recvPromise; - - app._cleanup(); - - do_print("waiting for async shutdown"); - Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true); - AsyncShutdown.profileBeforeChange._trigger(); - Services.prefs.clearUserPref("toolkit.asyncshutdown.testing"); - - let procs = yield SubprocessImpl.Process.getWorker().call("getProcesses", []); - equal(procs.size, 0, "native process exited"); -}); diff --git a/toolkit/components/webextensions/test/xpcshell/xpcshell.ini b/toolkit/components/webextensions/test/xpcshell/xpcshell.ini deleted file mode 100644 index d2c6fd5d0..000000000 --- a/toolkit/components/webextensions/test/xpcshell/xpcshell.ini +++ /dev/null @@ -1,69 +0,0 @@ -[DEFAULT] -head = head.js -tail = -firefox-appdir = browser -skip-if = appname == "thunderbird" -support-files = - data/** head_sync.js -tags = webextensions - -[test_csp_custom_policies.js] -[test_csp_validator.js] -[test_ext_alarms.js] -[test_ext_alarms_does_not_fire.js] -[test_ext_alarms_periodic.js] -[test_ext_alarms_replaces.js] -[test_ext_apimanager.js] -[test_ext_api_permissions.js] -[test_ext_background_generated_load_events.js] -[test_ext_background_generated_reload.js] -[test_ext_background_global_history.js] -skip-if = os == "android" # Android does not use Places for history. -[test_ext_background_private_browsing.js] -[test_ext_background_runtime_connect_params.js] -[test_ext_background_sub_windows.js] -[test_ext_background_window_properties.js] -skip-if = os == "android" -[test_ext_contexts.js] -[test_ext_downloads.js] -[test_ext_downloads_download.js] -skip-if = os == "android" -[test_ext_downloads_misc.js] -skip-if = os == "android" -[test_ext_downloads_search.js] -skip-if = os == "android" -[test_ext_experiments.js] -skip-if = release_or_beta -[test_ext_extension.js] -[test_ext_idle.js] -[test_ext_json_parser.js] -[test_ext_localStorage.js] -[test_ext_management.js] -[test_ext_management_uninstall_self.js] -[test_ext_manifest_content_security_policy.js] -[test_ext_manifest_incognito.js] -[test_ext_manifest_minimum_chrome_version.js] -[test_ext_onmessage_removelistener.js] -[test_ext_runtime_connect_no_receiver.js] -[test_ext_runtime_getBrowserInfo.js] -[test_ext_runtime_getPlatformInfo.js] -[test_ext_runtime_onInstalled_and_onStartup.js] -[test_ext_runtime_sendMessage.js] -[test_ext_runtime_sendMessage_errors.js] -[test_ext_runtime_sendMessage_no_receiver.js] -[test_ext_runtime_sendMessage_self.js] -[test_ext_schemas.js] -[test_ext_schemas_api_injection.js] -[test_ext_schemas_async.js] -[test_ext_schemas_allowed_contexts.js] -[test_ext_simple.js] -[test_ext_storage.js] -[test_ext_topSites.js] -skip-if = os == "android" -[test_getAPILevelForWindow.js] -[test_ext_legacy_extension_context.js] -[test_ext_legacy_extension_embedding.js] -[test_locale_converter.js] -[test_locale_data.js] -[test_native_messaging.js] -skip-if = os == "android" |