1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
<!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(async function testSendMessage_and_remove_frame() {
let extension = createTestExtension("frame", sendMessage_background, sendMessage_contentScript);
await extension.startup();
let frame = document.createElement("iframe");
frame.src = "file_sample.html";
document.body.appendChild(frame);
await extension.awaitFinish("Received sendMessage from closing frame");
await extension.unload();
});
add_task(async function testConnect_and_remove_frame() {
let extension = createTestExtension("frame", connect_background, connect_contentScript);
await extension.startup();
let frame = document.createElement("iframe");
frame.src = "file_sample.html";
document.body.appendChild(frame);
await extension.awaitFinish("Received onDisconnect from closing frame");
await extension.unload();
});
add_task(async function testSendMessage_and_remove_window() {
if (AppConstants.MOZ_BUILD_APP !== "browser") {
// We can't rely on this timing on Android.
return;
}
let extension = createTestExtension("window", sendMessage_background, sendMessage_contentScript);
await extension.startup();
window.open("file_sample.html");
await extension.awaitFinish("Received sendMessage from closing frame");
await extension.unload();
});
add_task(async function testConnect_and_remove_window() {
if (AppConstants.MOZ_BUILD_APP !== "browser") {
// We can't rely on this timing on Android.
return;
}
let extension = createTestExtension("window", connect_background, connect_contentScript);
await extension.startup();
window.open("file_sample.html");
await extension.awaitFinish("Received onDisconnect from closing frame");
await extension.unload();
});
</script>
</body>
</html>
|