diff options
Diffstat (limited to 'dom/base/test/chrome/window_swapFrameLoaders.xul')
-rw-r--r-- | dom/base/test/chrome/window_swapFrameLoaders.xul | 258 |
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> |