new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_chrome_ext_hybrid_addons.html
@@ -0,0 +1,268 @@
+<!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";
+
+function generateClassicExtensionFiles({id, files, isSDK = false}) {
+ 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:embeddedWebExtension>true</em:embeddedWebExtension>
+ <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>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>49.0a1</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+ </Description>
+ </RDF>`;
+
+ if (isSDK) {
+ files["package.json"] = `{
+ "id": "${id}",
+ "name": "hybrid-addon",
+ "version": "0.1.0",
+ "description": "A fake hybrid addon",
+ "main": "index.js",
+ "engines": {
+ "firefox": ">=49.0a1"
+ },
+ "license": "MPL-2.0"
+ }`;
+
+ 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_onmessage() {
+ 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");
+ });
+ }
+
+ function sdkMainScript() {
+ /* globals require */
+ const webext = require("sdk/webextension");
+ webext.api.onMessage.addListener((msg, sender, sendReply) => {
+ sendReply(`sdk received message: ${msg}`);
+ });
+ }
+
+ let id = "fake@hybrid.addon";
+ let extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: true,
+ files: generateClassicExtensionFiles({
+ id,
+ isSDK: true,
+ files: {
+ "index.js": `new ${sdkMainScript}`,
+ "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}`,
+ },
+ }),
+ }, id);
+
+ extension.startup();
+
+ yield extension.awaitFinish("sdk.webext-api.onmessage");
+
+ yield extension.unload();
+});
+
+add_task(function* test_bootstrap_hybrid_addon_onmessage() {
+ function backgroundScript() {
+ browser.runtime.sendMessage("background message", (reply) => {
+ browser.test.assertEq("bootstrap received message: background message", reply,
+ "Got the expected reply from the bootstrap based addon context");
+ browser.test.notifyPass("bootstrap.webext-api.onmessage");
+ });
+ }
+
+ let bootstrapScript = `
+ function install() {}
+ function shutdown() {}
+ function uninstall() {}
+ function startup(data, reason) {
+ let api = data.embeddedWebExtensionAPI;
+ api.onMessage.addListener((msg, sender, sendReply) => {
+ sendReply("bootstrap received message: " + msg);
+ });
+ }
+ `;
+
+ let id = "fake@hybrid.addon";
+ let extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: true,
+ files: generateClassicExtensionFiles({
+ id,
+ isSDK: false,
+ files: {
+ "bootstrap.js": bootstrapScript,
+ "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}`,
+ },
+ }),
+ }, id);
+
+ extension.startup();
+
+ yield extension.awaitFinish("bootstrap.webext-api.onmessage");
+
+ yield extension.unload();
+});
+
+add_task(function* test_sdk_hybrid_addon_onconnect() {
+ function backgroundScript() {
+ let port = browser.runtime.connect();
+ port.onMessage.addListener((msg) => {
+ browser.test.assertEq("sdk received message: background message", msg,
+ "Got the expected reply from the SDK context");
+ browser.test.notifyPass("sdk.webext-api.onconnect");
+ });
+ port.postMessage("background message");
+ }
+
+ function sdkMainScript() {
+ const webext = require("sdk/webextension");
+ webext.api.onConnect.addListener((port) => {
+ port.onMessage.addListener((msg) => {
+ port.postMessage(`sdk received message: ${msg}`);
+ });
+ });
+ }
+
+ let id = "fake@hybrid.addon";
+ let extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: true,
+ files: generateClassicExtensionFiles({
+ id,
+ isSDK: true,
+ files: {
+ "index.js": `new ${sdkMainScript}`,
+ "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}`,
+ },
+ }),
+ }, id);
+
+ extension.startup();
+
+ yield extension.awaitFinish("sdk.webext-api.onconnect");
+
+ yield extension.unload();
+});
+
+add_task(function* test_bootstrap_hybrid_addon_onconnect() {
+ function backgroundScript() {
+ let port = browser.runtime.connect();
+ port.onMessage.addListener((msg) => {
+ browser.test.assertEq("bootstrap received message: background message", msg,
+ "Got the expected reply from the bootstrap based addon context");
+ browser.test.notifyPass("bootstrap.webext-api.onconnect");
+ });
+ port.postMessage("background message");
+ }
+
+ let bootstrapScript = `
+ function install() {}
+ function shutdown() {}
+ function uninstall() {}
+ function startup(data, reason) {
+ let api = data.embeddedWebExtensionAPI;
+ api.onConnect.addListener((port) => {
+ port.onMessage.addListener((msg) => {
+ port.postMessage("bootstrap received message: " + msg);
+ });
+ });
+ }
+ `;
+
+ let id = "fake@hybrid.addon";
+ let extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: true,
+ files: generateClassicExtensionFiles({
+ id,
+ isSDK: false,
+ files: {
+ "bootstrap.js": bootstrapScript,
+ "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}`,
+ },
+ }),
+ }, id);
+
+ extension.startup();
+
+ yield extension.awaitFinish("bootstrap.webext-api.onconnect");
+
+ yield extension.unload();
+});
+
+</script>
+
+</body>
+</html>