test-firefox-windows.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  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. const { Cc, Ci } = require('chrome');
  6. const { setTimeout } = require('sdk/timers');
  7. const { Loader } = require('sdk/test/loader');
  8. const { onFocus, getMostRecentWindow, windows, isBrowser, getWindowTitle } = require('sdk/window/utils');
  9. const { open, close, focus } = require('sdk/window/helpers');
  10. const { browserWindows } = require("sdk/windows");
  11. const tabs = require("sdk/tabs");
  12. const winUtils = require("sdk/deprecated/window-utils");
  13. const { WindowTracker } = winUtils;
  14. const { isPrivate } = require('sdk/private-browsing');
  15. const { isWindowPBSupported } = require('sdk/private-browsing/utils');
  16. const { viewFor } = require("sdk/view/core");
  17. const { defer } = require("sdk/lang/functional");
  18. // TEST: open & close window
  19. exports.testOpenAndCloseWindow = function(assert, done) {
  20. assert.equal(browserWindows.length, 1, "Only one window open");
  21. let title = 'testOpenAndCloseWindow';
  22. browserWindows.open({
  23. url: "data:text/html;charset=utf-8,<title>" + title + "</title>",
  24. onOpen: function(window) {
  25. assert.equal(this, browserWindows, "The 'this' object is the windows object.");
  26. assert.equal(window.tabs.length, 1, "Only one tab open");
  27. assert.equal(browserWindows.length, 2, "Two windows open");
  28. window.tabs.activeTab.once('ready', function onReady(tab) {
  29. assert.pass(RegExp(title).test(window.title), "URL correctly loaded");
  30. window.close();
  31. });
  32. },
  33. onClose: function(window) {
  34. assert.equal(window.tabs.length, 0, "Tabs were cleared");
  35. assert.equal(browserWindows.length, 1, "Only one window open");
  36. done();
  37. }
  38. });
  39. };
  40. exports.testAutomaticDestroy = function(assert, done) {
  41. let windows = browserWindows;
  42. // Create a second windows instance that we will unload
  43. let called = false;
  44. let loader = Loader(module);
  45. let windows2 = loader.require("sdk/windows").browserWindows;
  46. windows2.on("open", function() {
  47. called = true;
  48. });
  49. loader.unload();
  50. // Fire a windows event and check that this unloaded instance is inactive
  51. windows.open({
  52. url: "data:text/html;charset=utf-8,foo",
  53. onOpen: function(window) {
  54. setTimeout(function () {
  55. assert.ok(!called, "Unloaded windows instance is destroyed and inactive");
  56. window.close(done);
  57. });
  58. }
  59. });
  60. };
  61. exports.testWindowTabsObject = function(assert, done) {
  62. let window, count = 0;
  63. function runTest() {
  64. if (++count != 2)
  65. return;
  66. assert.equal(window.tabs.length, 1, "Only 1 tab open");
  67. assert.equal(window.tabs.activeTab.title, "tab 1", "Correct active tab");
  68. window.tabs.open({
  69. url: "data:text/html;charset=utf-8,<title>tab 2</title>",
  70. inBackground: true,
  71. onReady: function onReady(newTab) {
  72. assert.equal(window.tabs.length, 2, "New tab open");
  73. assert.equal(newTab.title, "tab 2", "Correct new tab title");
  74. assert.equal(window.tabs.activeTab.title, "tab 1", "Correct active tab");
  75. let i = 1;
  76. for (let tab of window.tabs)
  77. assert.equal(tab.title, "tab " + i++, "Correct title");
  78. window.close();
  79. }
  80. });
  81. }
  82. tabs.once("ready", runTest);
  83. browserWindows.open({
  84. url: "data:text/html;charset=utf-8,<title>tab 1</title>",
  85. onActivate: function onActivate(win) {
  86. window = win;
  87. runTest();
  88. },
  89. onClose: function onClose(window) {
  90. assert.equal(window.tabs.length, 0, "No more tabs on closed window");
  91. done();
  92. }
  93. });
  94. };
  95. exports.testOnOpenOnCloseListeners = function(assert, done) {
  96. let windows = browserWindows;
  97. assert.equal(browserWindows.length, 1, "Only one window open");
  98. let received = {
  99. listener1: false,
  100. listener2: false,
  101. listener3: false,
  102. listener4: false
  103. }
  104. function listener1() {
  105. assert.equal(this, windows, "The 'this' object is the windows object.");
  106. if (received.listener1)
  107. assert.fail("Event received twice");
  108. received.listener1 = true;
  109. }
  110. function listener2() {
  111. if (received.listener2)
  112. assert.fail("Event received twice");
  113. received.listener2 = true;
  114. }
  115. function listener3() {
  116. assert.equal(this, windows, "The 'this' object is the windows object.");
  117. if (received.listener3)
  118. assert.fail("Event received twice");
  119. received.listener3 = true;
  120. }
  121. function listener4() {
  122. if (received.listener4)
  123. assert.fail("Event received twice");
  124. received.listener4 = true;
  125. }
  126. windows.on('open', listener1);
  127. windows.on('open', listener2);
  128. windows.on('close', listener3);
  129. windows.on('close', listener4);
  130. windows.open({
  131. url: "data:text/html;charset=utf-8,foo",
  132. onOpen: function(window) {
  133. window.close(function() {
  134. assert.ok(received.listener1, "onOpen handler called");
  135. assert.ok(received.listener2, "onOpen handler called");
  136. assert.ok(received.listener3, "onClose handler called");
  137. assert.ok(received.listener4, "onClose handler called");
  138. windows.removeListener('open', listener1);
  139. windows.removeListener('open', listener2);
  140. windows.removeListener('close', listener3);
  141. windows.removeListener('close', listener4);
  142. done();
  143. });
  144. }
  145. });
  146. };
  147. exports.testActiveWindow = function(assert, done) {
  148. let windows = browserWindows;
  149. // API window objects
  150. let window2, window3;
  151. // Raw window objects
  152. let rawWindow2, rawWindow3;
  153. let testSteps = [
  154. function() {
  155. assert.equal(windows.length, 3, "Correct number of browser windows");
  156. let count = 0;
  157. for (let window in windows)
  158. count++;
  159. assert.equal(count, 3, "Correct number of windows returned by iterator");
  160. assert.equal(windows.activeWindow.title, window3.title, "Correct active window - 3");
  161. continueAfterFocus(rawWindow2);
  162. rawWindow2.focus();
  163. },
  164. function() {
  165. assert.equal(windows.activeWindow.title, window2.title, "Correct active window - 2");
  166. continueAfterFocus(rawWindow2);
  167. window2.activate();
  168. },
  169. function() {
  170. assert.equal(windows.activeWindow.title, window2.title, "Correct active window - 2");
  171. continueAfterFocus(rawWindow3);
  172. window3.activate();
  173. },
  174. function() {
  175. assert.equal(windows.activeWindow.title, window3.title, "Correct active window - 3");
  176. finishTest();
  177. }
  178. ];
  179. let newWindow = null;
  180. let tracker = new WindowTracker({
  181. onTrack: function(window) {
  182. newWindow = window;
  183. }
  184. });
  185. windows.open({
  186. url: "data:text/html;charset=utf-8,<title>window 2</title>",
  187. onOpen: function(window) {
  188. assert.pass('window 2 open');
  189. window.tabs.activeTab.on('ready', function() {
  190. assert.pass('window 2 tab activated');
  191. window2 = window;
  192. assert.ok(newWindow, "A new window was opened");
  193. rawWindow2 = newWindow;
  194. newWindow = null;
  195. assert.equal(rawWindow2.content.document.title, "window 2", "Got correct raw window 2");
  196. assert.equal(rawWindow2.document.title, window2.title, "Saw correct title on window 2");
  197. windows.open({
  198. url: "data:text/html;charset=utf-8,<title>window 3</title>",
  199. onOpen: function(window) {
  200. assert.pass('window 3 open');
  201. window.tabs.activeTab.on('ready', function onReady() {
  202. assert.pass('window 3 tab activated');
  203. window3 = window;
  204. assert.ok(newWindow, "A new window was opened");
  205. rawWindow3 = newWindow;
  206. tracker.unload();
  207. assert.equal(rawWindow3.content.document.title, "window 3", "Got correct raw window 3");
  208. assert.equal(rawWindow3.document.title, window3.title, "Saw correct title on window 3");
  209. continueAfterFocus(rawWindow3);
  210. rawWindow3.focus();
  211. });
  212. }
  213. });
  214. });
  215. }
  216. });
  217. function nextStep() {
  218. if (testSteps.length) {
  219. setTimeout(testSteps.shift())
  220. }
  221. }
  222. let continueAfterFocus = function(w) onFocus(w).then(nextStep);
  223. function finishTest() {
  224. // close unactive window first to avoid unnecessary focus changing
  225. window2.close(function() {
  226. window3.close(function() {
  227. assert.equal(rawWindow2.closed, true, 'window 2 is closed');
  228. assert.equal(rawWindow3.closed, true, 'window 3 is closed');
  229. done();
  230. });
  231. });
  232. }
  233. };
  234. exports.testTrackWindows = function(assert, done) {
  235. let windows = [];
  236. let actions = [];
  237. let expects = [
  238. "activate 0", "global activate 0", "deactivate 0", "global deactivate 0",
  239. "activate 1", "global activate 1", "deactivate 1", "global deactivate 1",
  240. "activate 2", "global activate 2"
  241. ];
  242. function windowsActivation(window) {
  243. let index = windows.indexOf(window);
  244. // only concerned with windows opened for this test
  245. if (index < 0)
  246. return;
  247. assert.equal(actions.join(), expects.slice(0, index*4 + 1).join(), expects[index*4 + 1]);
  248. actions.push("global activate " + index)
  249. }
  250. function windowsDeactivation(window) {
  251. let index = windows.indexOf(window);
  252. // only concerned with windows opened for this test
  253. if (index < 0)
  254. return;
  255. assert.equal(actions.join(), expects.slice(0, index*4 + 3).join(), expects[index*4 + 3]);
  256. actions.push("global deactivate " + index)
  257. }
  258. // listen to global activate events
  259. browserWindows.on("activate", windowsActivation);
  260. // listen to global deactivate events
  261. browserWindows.on("deactivate", windowsDeactivation);
  262. function openWindow() {
  263. windows.push(browserWindows.open({
  264. url: "data:text/html;charset=utf-8,<i>testTrackWindows</i>",
  265. onActivate: function(window) {
  266. let index = windows.indexOf(window);
  267. // Guard against windows that have already been removed.
  268. // See bug 874502 comment 32.
  269. if (index == -1)
  270. return;
  271. assert.equal(actions.join(),
  272. expects.slice(0, index*4).join(),
  273. "expecting " + expects[index*4]);
  274. actions.push("activate " + index);
  275. if (windows.length < 3) {
  276. openWindow()
  277. }
  278. else {
  279. (function closeWindows(windows) {
  280. if (!windows.length) {
  281. browserWindows.removeListener("activate", windowsActivation);
  282. browserWindows.removeListener("deactivate", windowsDeactivation);
  283. return done();
  284. }
  285. return windows.pop().close(function() {
  286. assert.pass('window was closed');
  287. closeWindows(windows);
  288. });
  289. })(windows)
  290. }
  291. },
  292. onDeactivate: function(window) {
  293. let index = windows.indexOf(window);
  294. // Guard against windows that have already been removed.
  295. // See bug 874502 comment 32.
  296. if (index == -1)
  297. return;
  298. assert.equal(actions.join(),
  299. expects.slice(0, index*4 + 2).join(),
  300. "expecting " + expects[index*4 + 2]);
  301. actions.push("deactivate " + index)
  302. }
  303. }));
  304. }
  305. openWindow();
  306. }
  307. // test that it is not possible to open a private window by default
  308. exports.testWindowOpenPrivateDefault = function(assert, done) {
  309. browserWindows.open({
  310. url: 'about:mozilla',
  311. isPrivate: true,
  312. onOpen: function(window) {
  313. let tab = window.tabs[0];
  314. tab.once('ready', function() {
  315. assert.equal(tab.url, 'about:mozilla', 'opened correct tab');
  316. assert.equal(isPrivate(tab), false, 'tab is not private');
  317. window.close(done);
  318. });
  319. }
  320. });
  321. }
  322. // test that it is not possible to find a private window in
  323. // windows module's iterator
  324. exports.testWindowIteratorPrivateDefault = function(assert, done) {
  325. assert.equal(browserWindows.length, 1, 'only one window open');
  326. open('chrome://browser/content/browser.xul', {
  327. features: {
  328. private: true,
  329. chrome: true
  330. }
  331. }).then(focus).then(function(window) {
  332. // test that there is a private window opened
  333. assert.equal(isPrivate(window), isWindowPBSupported, 'there is a private window open');
  334. assert.strictEqual(window, winUtils.activeWindow);
  335. assert.strictEqual(window, getMostRecentWindow());
  336. assert.ok(!isPrivate(browserWindows.activeWindow));
  337. assert.equal(browserWindows.length, 1, 'only one window in browserWindows');
  338. assert.equal(windows().length, 1, 'only one window in windows()');
  339. assert.equal(windows(null, { includePrivate: true }).length, 2);
  340. // test that all windows in iterator are not private
  341. for (let window of browserWindows)
  342. assert.ok(!isPrivate(window), 'no window in browserWindows is private');
  343. close(window).then(done);
  344. });
  345. };
  346. exports["test getView(window)"] = function(assert, done) {
  347. browserWindows.once("open", window => {
  348. const view = viewFor(window);
  349. assert.ok(view instanceof Ci.nsIDOMWindow, "view is a window");
  350. assert.ok(isBrowser(view), "view is a browser window");
  351. assert.equal(getWindowTitle(view), window.title,
  352. "window has a right title");
  353. window.close();
  354. // Defer handler cause window is destroyed after event is dispatched.
  355. browserWindows.once("close", defer(_ => {
  356. assert.equal(viewFor(window), null, "window view is gone");
  357. done();
  358. }));
  359. });
  360. browserWindows.open({ url: "data:text/html,<title>yo</title>" });
  361. };
  362. require('sdk/test').run(exports);