diff options
Diffstat (limited to 'addon-sdk/source/test/test-ui-frame.js')
-rw-r--r-- | addon-sdk/source/test/test-ui-frame.js | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/addon-sdk/source/test/test-ui-frame.js b/addon-sdk/source/test/test-ui-frame.js new file mode 100644 index 000000000..05b40edd5 --- /dev/null +++ b/addon-sdk/source/test/test-ui-frame.js @@ -0,0 +1,252 @@ +/* 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"; + +module.metadata = { + "engines": { + "Firefox": "*" + } +}; + +const { Cu } = require("chrome"); +const { Frame } = require("sdk/ui/frame"); +const { Toolbar } = require("sdk/ui/toolbar"); +const { Loader } = require("sdk/test/loader"); +const { identify } = require("sdk/ui/id"); +const { setTimeout } = require("sdk/timers"); +const { getMostRecentBrowserWindow, open } = require("sdk/window/utils"); +const { ready, loaded, close } = require("sdk/window/helpers"); +const { defer, all } = require("sdk/core/promise"); +const { send } = require("sdk/event/utils"); +const { object } = require("sdk/util/sequence"); +const { OutputPort } = require("sdk/output/system"); +const { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); +const output = new OutputPort({ id: "toolbar-change" }); + +const wait = (toolbar, event, times) => { + let { promise, resolve } = defer(); + if (times) { + let resolveArray = []; + let counter = 0; + toolbar.on(event, function onEvent (e) { + resolveArray.push(e); + if (++counter === times) { + toolbar.off(event, onEvent); + resolve(resolveArray); + } + }); + } + else { + toolbar.once(event, resolve); + } + return promise; +}; + +const stateEventsFor = frame => + [wait(frame, "attach"), wait(frame, "ready"), + wait(frame, "load"), wait(frame, "detach")]; + + +const isAttached = ({id}, window=getMostRecentBrowserWindow()) => + !!window.document.getElementById(id); + +// Use `Task.spawn` instead of `Task.async` because the returned function does not contain +// a length for the test harness to determine whether the test should be executed +exports["test frame API"] = function* (assert) { + const url = "data:text/html,frame-api"; + assert.throws(() => new Frame(), + /The `options.url`/, + "must provide url"); + + assert.throws(() => new Frame({ url: "http://mozilla.org/" }), + /The `options.url`/, + "options.url must be local url"); + + assert.throws(() => new Frame({url: url, name: "4you" }), + /The `option.name` must be a valid/, + "can only take valid names"); + + const f1 = new Frame({ url: url }); + + assert.ok(f1.id, "frame has an id"); + assert.equal(f1.url, void(0), "frame has no url until it's loaded"); + assert.equal(typeof(f1.postMessage), "function", + "frames can postMessages"); + + const p1 = wait(f1, "register"); + + assert.throws(() => new Frame({ url: url }), + /Frame with this id already exists/, + "can't have two identical frames"); + + + const f2 = new Frame({ name: "frame-2", url: url }); + assert.pass("can create frame with same url but diff name"); + const p2 = wait(f2, "register"); + + yield p1; + assert.pass("frame#1 was registered"); + assert.equal(f1.url, url, "once registered it get's url"); + + yield p2; + assert.pass("frame#2 was registered"); + assert.equal(f2.url, url, "once registered it get's url"); + + f1.destroy(); + const f3 = new Frame({ url: url }); + assert.pass("frame identical to destroyed one can be created"); + + yield wait(f3, "register"); + assert.equal(f3.url, url, "url is set"); + f2.destroy(); + f3.destroy(); +}; + +exports["test frame in toolbar"] = function* (assert) { + const assertEvent = (event, type) => { + assert.ok(event, "`" + type + "` event was dispatched"); + assert.equal(event.type, type, "event.type is: " + type); + assert.equal(typeof(event.source), "object", + "event.source is an object"); + assert.equal(typeof(event.source.postMessage), "function", + "messages can be posted to event.source"); + }; + + + const url = "data:text/html,toolbar-frame"; + const f1 = new Frame({ url: url }); + const t1 = new Toolbar({ + title: "frame toolbar", + items: [f1] + }); + + const w1 = getMostRecentBrowserWindow(); + const [a1, r1, l1] = stateEventsFor(f1); + + assertEvent((yield a1), "attach"); + assert.ok(isAttached(f1, w1), "frame is in the window#1"); + assertEvent((yield r1), "ready"); + assertEvent((yield l1), "load"); + + const [a2, r2, l2] = stateEventsFor(f1); + const w2 = open(); + + assertEvent((yield a2), "attach"); + assert.ok(isAttached(f1, w2), "frame is in the window#2"); + assertEvent((yield r2), "ready"); + assertEvent((yield l2), "load"); + assert.pass("frame attached to window#2"); + + + const d1 = wait(f1, "detach"); + yield close(w2); + assertEvent((yield d1), "detach"); + assert.pass("frame detached when window is closed"); + + t1.destroy(); + + assertEvent((yield wait(f1, "detach")), "detach"); + assert.ok(!isAttached(f1, w1), "frame was removed from window#1"); + assert.pass("toolbar destroy detaches frame"); +}; + + +exports["test host to content messaging"] = function* (assert) { + const url = "data:text/html,<script>new " + function() { + window.addEventListener("message", (event) => { + if (event.data === "ping!") + event.source.postMessage("pong!", event.origin); + }); + } + "</script>"; + const f1 = new Frame({ name: "mailbox", url: url }); + const t1 = new Toolbar({ title: "mailbox", items: [f1] }); + + const e1 = yield wait(f1, "ready"); + e1.source.postMessage("ping!", e1.origin); + + const pong = yield wait(f1, "message"); + assert.equal(pong.data, "pong!", "received ping back"); + t1.destroy(); + + yield wait(t1, "detach"); +}; + + +exports["test content to host messaging"] = function* (assert) { + const url = "data:text/html,<script>new " + function() { + window.addEventListener("message", (event) => { + if (event.data === "pong!") + event.source.postMessage("end", event.origin); + }); + + window.parent.postMessage("ping!", "*"); + } + "</script>"; + + const f1 = new Frame({ name: "inbox", url: url }); + const t1 = new Toolbar({ title: "inbox", items: [f1] }); + + const e1 = yield wait(f1, "message"); + assert.equal(e1.data, "ping!", "received ping from content"); + + e1.source.postMessage("pong!", e1.origin); + + const e2 = yield wait(f1, "message"); + assert.equal(e2.data, "end", "received end message"); + + t1.destroy(); + yield wait(t1, "detach"); + +}; + + +exports["test direct messaging"] = function* (assert) { + let message; + const url = "data:text/html,<script>new " + function() { + var n = 0; + window.addEventListener("message", (event) => { + if (event.data === "inc") + n = n + 1; + if (event.data === "print") + event.source.postMessage({ n: n }, event.origin); + }); + } + "</script>"; + + const w1 = getMostRecentBrowserWindow(); + const f1 = new Frame({ url: url, name: "mail-cluster" }); + const t1 = new Toolbar({ title: "claster", items: [f1] }); + + yield wait(f1, "ready"); + assert.pass("document loaded in window#1"); + + const w2 = open(); + + yield wait(f1, "ready"); + assert.pass("document loaded in window#2"); + + let messages = wait(f1, "message", 2); + f1.postMessage("inc", f1.origin); + f1.postMessage("print", f1.origin); + + const [e1, e2] = yield messages; + assert.deepEqual(e1.data, {n: 1}, "received message from window#1"); + assert.deepEqual(e2.data, {n: 1}, "received message from window#2"); + + message = wait(f1, "message"); + e1.source.postMessage("inc", e1.origin); + e1.source.postMessage("print", e1.origin); + const e3 = yield message; + assert.deepEqual(e3.data, {n: 2}, "state changed in window#1"); + + message = wait(f1, "message"); + e2.source.postMessage("print", e2.origin); + yield message; + assert.deepEqual(e2.data, {n:1}, "window#2 didn't received inc message"); + + yield close(w2); + t1.destroy(); + + yield wait(t1, "detach"); +}; + +require("sdk/test").run(module.exports); |