summaryrefslogtreecommitdiffstats
path: root/dom/base/test/chrome/window_swapFrameLoaders.xul
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/test/chrome/window_swapFrameLoaders.xul')
-rw-r--r--dom/base/test/chrome/window_swapFrameLoaders.xul258
1 files changed, 258 insertions, 0 deletions
diff --git a/dom/base/test/chrome/window_swapFrameLoaders.xul b/dom/base/test/chrome/window_swapFrameLoaders.xul
new file mode 100644
index 000000000..3deae2e63
--- /dev/null
+++ b/dom/base/test/chrome/window_swapFrameLoaders.xul
@@ -0,0 +1,258 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1242644
+Test swapFrameLoaders with different frame types and remoteness
+-->
+<window title="Mozilla Bug 1242644"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
+
+ <script type="application/javascript"><![CDATA[
+ ["SimpleTest", "SpecialPowers", "info", "is", "ok"].forEach(key => {
+ window[key] = window.opener[key];
+ })
+ const { interfaces: Ci } = Components;
+
+ const NS = {
+ xul: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
+ html: "http://www.w3.org/1999/xhtml",
+ }
+
+ const TAG = {
+ xul: "browser",
+ html: "iframe", // mozbrowser
+ }
+
+ const SCENARIOS = [
+ ["xul", "xul"],
+ ["xul", "html"],
+ ["html", "xul"],
+ ["html", "html"],
+ ["xul", "xul", "remote"],
+ ["xul", "html", "remote"],
+ ["html", "xul", "remote"],
+ ["html", "html", "remote"],
+ ];
+
+ const HEIGHTS = [
+ 200,
+ 400
+ ];
+
+ function frameScript() {
+ addEventListener("load", function onLoad() {
+ sendAsyncMessage("test:load");
+ }, true);
+ }
+
+ // Watch for loads in new frames
+ window.messageManager.loadFrameScript(`data:,(${frameScript})();`, true);
+
+ function once(target, eventName, useCapture = false) {
+ info("Waiting for event: '" + eventName + "' on " + target + ".");
+
+ return new Promise(resolve => {
+ for (let [add, remove] of [
+ ["addEventListener", "removeEventListener"],
+ ["addMessageListener", "removeMessageListener"],
+ ]) {
+ if ((add in target) && (remove in target)) {
+ target[add](eventName, function onEvent(...aArgs) {
+ info("Got event: '" + eventName + "' on " + target + ".");
+ target[remove](eventName, onEvent, useCapture);
+ resolve(aArgs);
+ }, useCapture);
+ break;
+ }
+ }
+ });
+ }
+
+ function* addFrame(type, remote, height) {
+ let frame = document.createElementNS(NS[type], TAG[type]);
+ frame.setAttribute("remote", remote);
+ if (remote && type == "xul") {
+ frame.setAttribute("style", "-moz-binding: none;");
+ }
+ if (type == "html") {
+ frame.setAttribute("mozbrowser", "true");
+ frame.setAttribute("noisolation", "true");
+ frame.setAttribute("allowfullscreen", "true");
+ } else if (type == "xul") {
+ frame.setAttribute("type", "content");
+ }
+ let src = `data:text/html,<!doctype html>` +
+ `<body style="height:${height}px"/>`;
+ frame.setAttribute("src", src);
+ document.documentElement.appendChild(frame);
+ let mm = frame.frameLoader.messageManager;
+ yield once(mm, "test:load");
+ return frame;
+ }
+
+ add_task(function*() {
+ yield new Promise(resolve => {
+ SpecialPowers.pushPrefEnv(
+ { "set": [["dom.mozBrowserFramesEnabled", true],
+ ["network.disable.ipc.security", true]] },
+ resolve);
+ });
+ });
+
+ add_task(function*() {
+ for (let scenario of SCENARIOS) {
+ let [ typeA, typeB, remote ] = scenario;
+ remote = !!remote;
+ let heightA = HEIGHTS[0];
+ info(`Adding frame A, type ${typeA}, remote ${remote}, height ${heightA}`);
+ let frameA = yield addFrame(typeA, remote, heightA);
+
+ let heightB = HEIGHTS[1];
+ info(`Adding frame B, type ${typeB}, remote ${remote}, height ${heightB}`);
+ let frameB = yield addFrame(typeB, remote, heightB);
+
+ let frameScriptFactory = function(name) {
+ return `function() {
+ addMessageListener("ping", function() {
+ sendAsyncMessage("pong", "${name}");
+ });
+ addMessageListener("check-browser-api", function() {
+ let exists = "api" in this;
+ sendAsyncMessage("check-browser-api", {
+ exists,
+ running: exists && !this.api._shuttingDown,
+ });
+ });
+ }`;
+ }
+
+ // Load frame script into each frame
+ {
+ let mmA = frameA.frameLoader.messageManager;
+ let mmB = frameB.frameLoader.messageManager;
+
+ mmA.loadFrameScript("data:,(" + frameScriptFactory("A") + ")()", false);
+ mmB.loadFrameScript("data:,(" + frameScriptFactory("B") + ")()", false);
+ }
+
+ // Ping before swap
+ {
+ let mmA = frameA.frameLoader.messageManager;
+ let mmB = frameB.frameLoader.messageManager;
+
+ let inflightA = once(mmA, "pong");
+ let inflightB = once(mmB, "pong");
+
+ info("Ping message manager for frame A");
+ mmA.sendAsyncMessage("ping");
+ let [ { data: pongA } ] = yield inflightA;
+ is(pongA, "A", "Frame A message manager gets reply A before swap");
+
+ info("Ping message manager for frame B");
+ mmB.sendAsyncMessage("ping");
+ let [ { data: pongB } ] = yield inflightB;
+ is(pongB, "B", "Frame B message manager gets reply B before swap");
+ }
+
+ // Check height before swap
+ {
+ if (frameA.getContentDimensions) {
+ let { height } = yield frameA.getContentDimensions();
+ is(height, heightA, "Frame A's content height is 200px before swap");
+ }
+ if (frameB.getContentDimensions) {
+ let { height } = yield frameB.getContentDimensions();
+ is(height, heightB, "Frame B's content height is 400px before swap");
+ }
+ }
+
+ // Ping after swap using message managers acquired before
+ {
+ let mmA = frameA.frameLoader.messageManager;
+ let mmB = frameB.frameLoader.messageManager;
+
+ info("swapFrameLoaders");
+ frameA.swapFrameLoaders(frameB);
+
+ let inflightA = once(mmA, "pong");
+ let inflightB = once(mmB, "pong");
+
+ info("Ping message manager for frame A");
+ mmA.sendAsyncMessage("ping");
+ let [ { data: pongA } ] = yield inflightA;
+ is(pongA, "B", "Frame A message manager acquired before swap gets reply B after swap");
+
+ info("Ping message manager for frame B");
+ mmB.sendAsyncMessage("ping");
+ let [ { data: pongB } ] = yield inflightB;
+ is(pongB, "A", "Frame B message manager acquired before swap gets reply A after swap");
+ }
+
+ // Check height after swap
+ {
+ if (frameA.getContentDimensions) {
+ let { height } = yield frameA.getContentDimensions();
+ is(height, heightB, "Frame A's content height is 400px after swap");
+ }
+ if (frameB.getContentDimensions) {
+ let { height } = yield frameB.getContentDimensions();
+ is(height, heightA, "Frame B's content height is 200px after swap");
+ }
+ }
+
+ // Ping after swap using message managers acquired after
+ {
+ let mmA = frameA.frameLoader.messageManager;
+ let mmB = frameB.frameLoader.messageManager;
+
+ let inflightA = once(mmA, "pong");
+ let inflightB = once(mmB, "pong");
+
+ info("Ping message manager for frame A");
+ mmA.sendAsyncMessage("ping");
+ let [ { data: pongA } ] = yield inflightA;
+ is(pongA, "B", "Frame A message manager acquired after swap gets reply B after swap");
+
+ info("Ping message manager for frame B");
+ mmB.sendAsyncMessage("ping");
+ let [ { data: pongB } ] = yield inflightB;
+ is(pongB, "A", "Frame B message manager acquired after swap gets reply A after swap");
+ }
+
+ // Verify browser API frame scripts destroyed if swapped out of browser frame
+ if (frameA.hasAttribute("mozbrowser") != frameB.hasAttribute("mozbrowser")) {
+ let mmA = frameA.frameLoader.messageManager;
+ let mmB = frameB.frameLoader.messageManager;
+
+ let inflightA = once(mmA, "check-browser-api");
+ let inflightB = once(mmB, "check-browser-api");
+
+ info("Check browser API for frame A");
+ mmA.sendAsyncMessage("check-browser-api");
+ let [ { data: apiA } ] = yield inflightA;
+ if (frameA.hasAttribute("mozbrowser")) {
+ ok(apiA.exists && apiA.running, "Frame A browser API exists and is running");
+ } else {
+ ok(apiA.exists && !apiA.running, "Frame A browser API did exist but is now destroyed");
+ }
+
+ info("Check browser API for frame B");
+ mmB.sendAsyncMessage("check-browser-api");
+ let [ { data: apiB } ] = yield inflightB;
+ if (frameB.hasAttribute("mozbrowser")) {
+ ok(apiB.exists && apiB.running, "Frame B browser API exists and is running");
+ } else {
+ ok(apiB.exists && !apiB.running, "Frame B browser API did exist but is now destroyed");
+ }
+ } else {
+ info("Frames have matching mozbrowser state, skipping browser API destruction check");
+ }
+
+ frameA.remove();
+ frameB.remove();
+ }
+ });
+ ]]></script>
+</window>