test-ui-frame.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. module.metadata = {
  6. "engines": {
  7. "Firefox": "*"
  8. }
  9. };
  10. const { Frame } = require("sdk/ui/frame");
  11. const { Toolbar } = require("sdk/ui/toolbar");
  12. const { Loader } = require("sdk/test/loader");
  13. const { identify } = require("sdk/ui/id");
  14. const { setTimeout } = require("sdk/timers");
  15. const { getMostRecentBrowserWindow, open } = require("sdk/window/utils");
  16. const { ready, loaded, close } = require("sdk/window/helpers");
  17. const { defer } = require("sdk/core/promise");
  18. const { send } = require("sdk/event/utils");
  19. const { object } = require("sdk/util/sequence");
  20. const { OutputPort } = require("sdk/output/system");
  21. const output = new OutputPort({ id: "toolbar-change" });
  22. const wait = (toolbar, event) => {
  23. let { promise, resolve } = defer();
  24. toolbar.once(event, resolve);
  25. return promise;
  26. };
  27. const stateEventsFor = frame =>
  28. [wait(frame, "attach"), wait(frame, "ready"),
  29. wait(frame, "load"), wait(frame, "detach")];
  30. const isAttached = ({id}, window=getMostRecentBrowserWindow()) =>
  31. !!window.document.getElementById(id);
  32. exports["test frame API"] = function*(assert) {
  33. const url = "data:text/html,frame-api";
  34. assert.throws(() => new Frame(),
  35. /The `options.url`/,
  36. "must provide url");
  37. assert.throws(() => new Frame({ url: "http://mozilla.org/" }),
  38. /The `options.url`/,
  39. "options.url must be local url");
  40. assert.throws(() => new Frame({url: url, name: "4you" }),
  41. /The `option.name` must be a valid/,
  42. "can only take valid names");
  43. const f1 = new Frame({ url: url });
  44. assert.ok(f1.id, "frame has an id");
  45. assert.equal(f1.url, void(0), "frame has no url until it's loaded");
  46. assert.equal(typeof(f1.postMessage), "function",
  47. "frames can postMessages");
  48. const p1 = wait(f1, "register");
  49. assert.throws(() => new Frame({ url: url }),
  50. /Frame with this id already exists/,
  51. "can't have two identical frames");
  52. const f2 = new Frame({ name: "frame-2", url: url });
  53. assert.pass("can create frame with same url but diff name");
  54. const p2 = wait(f2, "register");
  55. yield p1;
  56. assert.pass("frame#1 was registered");
  57. assert.equal(f1.url, url, "once registered it get's url");
  58. yield p2;
  59. assert.pass("frame#2 was registered");
  60. assert.equal(f2.url, url, "once registered it get's url");
  61. f1.destroy();
  62. const f3 = new Frame({ url: url });
  63. assert.pass("frame identical to destroyed one can be created");
  64. yield wait(f3, "register");
  65. assert.equal(f3.url, url, "url is set");
  66. f2.destroy();
  67. f3.destroy();
  68. };
  69. exports["test frame in toolbar"] = function*(assert) {
  70. const assertEvent = (event, type) => {
  71. assert.ok(event, "`" + type + "` event was dispatched");
  72. assert.equal(event.type, type, "event.type is: " + type);
  73. assert.equal(typeof(event.source), "object",
  74. "event.source is an object");
  75. assert.equal(typeof(event.source.postMessage), "function",
  76. "messages can be posted to event.source");
  77. };
  78. const url = "data:text/html,toolbar-frame";
  79. const f1 = new Frame({ url: url });
  80. const t1 = new Toolbar({
  81. title: "frame toolbar",
  82. items: [f1]
  83. });
  84. const w1 = getMostRecentBrowserWindow();
  85. const [a1, r1, l1] = stateEventsFor(f1);
  86. assertEvent((yield a1), "attach");
  87. assert.ok(isAttached(f1, w1), "frame is in the window#1");
  88. assertEvent((yield r1), "ready");
  89. assertEvent((yield l1), "load");
  90. const [a2, r2, l2] = stateEventsFor(f1);
  91. const w2 = open();
  92. assertEvent((yield a2), "attach");
  93. assert.ok(isAttached(f1, w2), "frame is in the window#2");
  94. assertEvent((yield r2), "ready");
  95. assertEvent((yield l2), "load");
  96. assert.pass("frame attached to window#2");
  97. const d1 = wait(f1, "detach");
  98. yield close(w2);
  99. assertEvent((yield d1), "detach");
  100. assert.pass("frame detached when window is closed");
  101. t1.destroy();
  102. assertEvent((yield wait(f1, "detach")), "detach");
  103. assert.ok(!isAttached(f1, w1), "frame was removed from window#1");
  104. assert.pass("toolbar destroy detaches frame");
  105. };
  106. exports["test host to content messaging"] = function*(assert) {
  107. const url = "data:text/html,<script>new " + function() {
  108. window.addEventListener("message", (event) => {
  109. if (event.data === "ping!")
  110. event.source.postMessage("pong!", event.origin);
  111. });
  112. } + "</script>";
  113. const f1 = new Frame({ name: "mailbox", url: url });
  114. const t1 = new Toolbar({ title: "mailbox", items: [f1] });
  115. const e1 = yield wait(f1, "ready");
  116. e1.source.postMessage("ping!", e1.origin);
  117. const pong = yield wait(f1, "message");
  118. assert.equal(pong.data, "pong!", "received ping back");
  119. t1.destroy();
  120. yield wait(t1, "detach");
  121. };
  122. exports["test content to host messaging"] = function*(assert) {
  123. const url = "data:text/html,<script>new " + function() {
  124. window.addEventListener("message", (event) => {
  125. if (event.data === "pong!")
  126. event.source.postMessage("end", event.origin);
  127. });
  128. window.parent.postMessage("ping!", "*");
  129. } + "</script>";
  130. const f1 = new Frame({ name: "inbox", url: url });
  131. const t1 = new Toolbar({ title: "inbox", items: [f1] });
  132. const e1 = yield wait(f1, "message");
  133. assert.equal(e1.data, "ping!", "received ping from content");
  134. e1.source.postMessage("pong!", e1.origin);
  135. const e2 = yield wait(f1, "message");
  136. assert.equal(e2.data, "end", "received end message");
  137. t1.destroy();
  138. yield wait(t1, "detach");
  139. };
  140. exports["test direct messaging"] = function*(assert) {
  141. const url = "data:text/html,<script>new " + function() {
  142. var n = 0;
  143. window.addEventListener("message", (event) => {
  144. if (event.data === "inc")
  145. n = n + 1;
  146. if (event.data === "print")
  147. event.source.postMessage({ n: n }, event.origin);
  148. });
  149. } + "</script>";
  150. const w1 = getMostRecentBrowserWindow();
  151. const f1 = new Frame({ url: url, name: "mail-cluster" });
  152. const t1 = new Toolbar({ title: "claster", items: [f1] });
  153. yield wait(f1, "ready");
  154. assert.pass("document loaded in window#1");
  155. const w2 = open();
  156. yield wait(f1, "ready");
  157. assert.pass("document loaded in window#2");
  158. f1.postMessage("inc", f1.origin);
  159. f1.postMessage("print", f1.origin);
  160. const e1 = yield wait(f1, "message");
  161. assert.deepEqual(e1.data, {n: 1}, "received message from window#1");
  162. const e2 = yield wait(f1, "message");
  163. assert.deepEqual(e2.data, {n: 1}, "received message from window#2");
  164. e1.source.postMessage("inc", e1.origin);
  165. e1.source.postMessage("print", e1.origin);
  166. const e3 = yield wait(f1, "message");
  167. assert.deepEqual(e3.data, {n: 2}, "state changed in window#1");
  168. e2.source.postMessage("print", e2.origin);
  169. const e4 = yield wait(f1, "message");
  170. assert.deepEqual(e2.data, {n:1}, "window#2 didn't received inc message");
  171. yield close(w2);
  172. t1.destroy();
  173. yield wait(t1, "detach");
  174. };
  175. require("sdk/test").run(exports);