1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/test/test-ui-frame.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,252 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +"use strict"; 1.8 + 1.9 +module.metadata = { 1.10 + "engines": { 1.11 + "Firefox": "*" 1.12 + } 1.13 +}; 1.14 + 1.15 +const { Cu } = require("chrome"); 1.16 +const { Frame } = require("sdk/ui/frame"); 1.17 +const { Toolbar } = require("sdk/ui/toolbar"); 1.18 +const { Loader } = require("sdk/test/loader"); 1.19 +const { identify } = require("sdk/ui/id"); 1.20 +const { setTimeout } = require("sdk/timers"); 1.21 +const { getMostRecentBrowserWindow, open } = require("sdk/window/utils"); 1.22 +const { ready, loaded, close } = require("sdk/window/helpers"); 1.23 +const { defer, all } = require("sdk/core/promise"); 1.24 +const { send } = require("sdk/event/utils"); 1.25 +const { object } = require("sdk/util/sequence"); 1.26 +const { OutputPort } = require("sdk/output/system"); 1.27 +const { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); 1.28 +const output = new OutputPort({ id: "toolbar-change" }); 1.29 + 1.30 +const wait = (toolbar, event, times) => { 1.31 + let { promise, resolve } = defer(); 1.32 + if (times) { 1.33 + let resolveArray = []; 1.34 + let counter = 0; 1.35 + toolbar.on(event, function onEvent (e) { 1.36 + resolveArray.push(e); 1.37 + if (++counter === times) { 1.38 + toolbar.off(event, onEvent); 1.39 + resolve(resolveArray); 1.40 + } 1.41 + }); 1.42 + } 1.43 + else { 1.44 + toolbar.once(event, resolve); 1.45 + } 1.46 + return promise; 1.47 +}; 1.48 + 1.49 +const stateEventsFor = frame => 1.50 + [wait(frame, "attach"), wait(frame, "ready"), 1.51 + wait(frame, "load"), wait(frame, "detach")]; 1.52 + 1.53 + 1.54 +const isAttached = ({id}, window=getMostRecentBrowserWindow()) => 1.55 + !!window.document.getElementById(id); 1.56 + 1.57 +// Use `Task.spawn` instead of `Task.async` because the returned function does not contain 1.58 +// a length for the test harness to determine whether the test should be executed 1.59 +exports["test frame API"] = function* (assert) { 1.60 + const url = "data:text/html,frame-api"; 1.61 + assert.throws(() => new Frame(), 1.62 + /The `options.url`/, 1.63 + "must provide url"); 1.64 + 1.65 + assert.throws(() => new Frame({ url: "http://mozilla.org/" }), 1.66 + /The `options.url`/, 1.67 + "options.url must be local url"); 1.68 + 1.69 + assert.throws(() => new Frame({url: url, name: "4you" }), 1.70 + /The `option.name` must be a valid/, 1.71 + "can only take valid names"); 1.72 + 1.73 + const f1 = new Frame({ url: url }); 1.74 + 1.75 + assert.ok(f1.id, "frame has an id"); 1.76 + assert.equal(f1.url, void(0), "frame has no url until it's loaded"); 1.77 + assert.equal(typeof(f1.postMessage), "function", 1.78 + "frames can postMessages"); 1.79 + 1.80 + const p1 = wait(f1, "register"); 1.81 + 1.82 + assert.throws(() => new Frame({ url: url }), 1.83 + /Frame with this id already exists/, 1.84 + "can't have two identical frames"); 1.85 + 1.86 + 1.87 + const f2 = new Frame({ name: "frame-2", url: url }); 1.88 + assert.pass("can create frame with same url but diff name"); 1.89 + const p2 = wait(f2, "register"); 1.90 + 1.91 + yield p1; 1.92 + assert.pass("frame#1 was registered"); 1.93 + assert.equal(f1.url, url, "once registered it get's url"); 1.94 + 1.95 + yield p2; 1.96 + assert.pass("frame#2 was registered"); 1.97 + assert.equal(f2.url, url, "once registered it get's url"); 1.98 + 1.99 + f1.destroy(); 1.100 + const f3 = new Frame({ url: url }); 1.101 + assert.pass("frame identical to destroyed one can be created"); 1.102 + 1.103 + yield wait(f3, "register"); 1.104 + assert.equal(f3.url, url, "url is set"); 1.105 + f2.destroy(); 1.106 + f3.destroy(); 1.107 +}; 1.108 + 1.109 +exports["test frame in toolbar"] = function* (assert) { 1.110 + const assertEvent = (event, type) => { 1.111 + assert.ok(event, "`" + type + "` event was dispatched"); 1.112 + assert.equal(event.type, type, "event.type is: " + type); 1.113 + assert.equal(typeof(event.source), "object", 1.114 + "event.source is an object"); 1.115 + assert.equal(typeof(event.source.postMessage), "function", 1.116 + "messages can be posted to event.source"); 1.117 + }; 1.118 + 1.119 + 1.120 + const url = "data:text/html,toolbar-frame"; 1.121 + const f1 = new Frame({ url: url }); 1.122 + const t1 = new Toolbar({ 1.123 + title: "frame toolbar", 1.124 + items: [f1] 1.125 + }); 1.126 + 1.127 + const w1 = getMostRecentBrowserWindow(); 1.128 + const [a1, r1, l1] = stateEventsFor(f1); 1.129 + 1.130 + assertEvent((yield a1), "attach"); 1.131 + assert.ok(isAttached(f1, w1), "frame is in the window#1"); 1.132 + assertEvent((yield r1), "ready"); 1.133 + assertEvent((yield l1), "load"); 1.134 + 1.135 + const [a2, r2, l2] = stateEventsFor(f1); 1.136 + const w2 = open(); 1.137 + 1.138 + assertEvent((yield a2), "attach"); 1.139 + assert.ok(isAttached(f1, w2), "frame is in the window#2"); 1.140 + assertEvent((yield r2), "ready"); 1.141 + assertEvent((yield l2), "load"); 1.142 + assert.pass("frame attached to window#2"); 1.143 + 1.144 + 1.145 + const d1 = wait(f1, "detach"); 1.146 + yield close(w2); 1.147 + assertEvent((yield d1), "detach"); 1.148 + assert.pass("frame detached when window is closed"); 1.149 + 1.150 + t1.destroy(); 1.151 + 1.152 + assertEvent((yield wait(f1, "detach")), "detach"); 1.153 + assert.ok(!isAttached(f1, w1), "frame was removed from window#1"); 1.154 + assert.pass("toolbar destroy detaches frame"); 1.155 +}; 1.156 + 1.157 + 1.158 +exports["test host to content messaging"] = function* (assert) { 1.159 + const url = "data:text/html,<script>new " + function() { 1.160 + window.addEventListener("message", (event) => { 1.161 + if (event.data === "ping!") 1.162 + event.source.postMessage("pong!", event.origin); 1.163 + }); 1.164 + } + "</script>"; 1.165 + const f1 = new Frame({ name: "mailbox", url: url }); 1.166 + const t1 = new Toolbar({ title: "mailbox", items: [f1] }); 1.167 + 1.168 + const e1 = yield wait(f1, "ready"); 1.169 + e1.source.postMessage("ping!", e1.origin); 1.170 + 1.171 + const pong = yield wait(f1, "message"); 1.172 + assert.equal(pong.data, "pong!", "received ping back"); 1.173 + t1.destroy(); 1.174 + 1.175 + yield wait(t1, "detach"); 1.176 +}; 1.177 + 1.178 + 1.179 +exports["test content to host messaging"] = function* (assert) { 1.180 + const url = "data:text/html,<script>new " + function() { 1.181 + window.addEventListener("message", (event) => { 1.182 + if (event.data === "pong!") 1.183 + event.source.postMessage("end", event.origin); 1.184 + }); 1.185 + 1.186 + window.parent.postMessage("ping!", "*"); 1.187 + } + "</script>"; 1.188 + 1.189 + const f1 = new Frame({ name: "inbox", url: url }); 1.190 + const t1 = new Toolbar({ title: "inbox", items: [f1] }); 1.191 + 1.192 + const e1 = yield wait(f1, "message"); 1.193 + assert.equal(e1.data, "ping!", "received ping from content"); 1.194 + 1.195 + e1.source.postMessage("pong!", e1.origin); 1.196 + 1.197 + const e2 = yield wait(f1, "message"); 1.198 + assert.equal(e2.data, "end", "received end message"); 1.199 + 1.200 + t1.destroy(); 1.201 + yield wait(t1, "detach"); 1.202 + 1.203 +}; 1.204 + 1.205 + 1.206 +exports["test direct messaging"] = function* (assert) { 1.207 + const url = "data:text/html,<script>new " + function() { 1.208 + var n = 0; 1.209 + window.addEventListener("message", (event) => { 1.210 + if (event.data === "inc") 1.211 + n = n + 1; 1.212 + if (event.data === "print") 1.213 + event.source.postMessage({ n: n }, event.origin); 1.214 + }); 1.215 + } + "</script>"; 1.216 + 1.217 + const w1 = getMostRecentBrowserWindow(); 1.218 + const f1 = new Frame({ url: url, name: "mail-cluster" }); 1.219 + const t1 = new Toolbar({ title: "claster", items: [f1] }); 1.220 + 1.221 + yield wait(f1, "ready"); 1.222 + assert.pass("document loaded in window#1"); 1.223 + 1.224 + const w2 = open(); 1.225 + 1.226 + yield wait(f1, "ready"); 1.227 + assert.pass("document loaded in window#2"); 1.228 + 1.229 + let messages = wait(f1, "message", 2); 1.230 + f1.postMessage("inc", f1.origin); 1.231 + f1.postMessage("print", f1.origin); 1.232 + 1.233 + const [e1, e2] = yield messages; 1.234 + assert.deepEqual(e1.data, {n: 1}, "received message from window#1"); 1.235 + assert.deepEqual(e2.data, {n: 1}, "received message from window#2"); 1.236 + 1.237 + let message = wait(f1, "message"); 1.238 + e1.source.postMessage("inc", e1.origin); 1.239 + e1.source.postMessage("print", e1.origin); 1.240 + const e3 = yield message; 1.241 + assert.deepEqual(e3.data, {n: 2}, "state changed in window#1"); 1.242 + 1.243 + let message = wait(f1, "message"); 1.244 + e2.source.postMessage("print", e2.origin); 1.245 + yield message; 1.246 + assert.deepEqual(e2.data, {n:1}, "window#2 didn't received inc message"); 1.247 + 1.248 + yield close(w2); 1.249 + t1.destroy(); 1.250 + 1.251 + yield wait(t1, "detach"); 1.252 + 1.253 +}; 1.254 + 1.255 +require("sdk/test").run(exports);