test-panel.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  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 { Cc, Ci } = require("chrome");
  11. const { Loader } = require('sdk/test/loader');
  12. const { LoaderWithHookedConsole } = require("sdk/test/loader");
  13. const timer = require("sdk/timers");
  14. const self = require('sdk/self');
  15. const { open, close, focus, ready } = require('sdk/window/helpers');
  16. const { isPrivate } = require('sdk/private-browsing');
  17. const { isWindowPBSupported, isGlobalPBSupported } = require('sdk/private-browsing/utils');
  18. const { defer, all } = require('sdk/core/promise');
  19. const { getMostRecentBrowserWindow } = require('sdk/window/utils');
  20. const { getWindow } = require('sdk/panel/window');
  21. const { pb } = require('./private-browsing/helper');
  22. const { URL } = require('sdk/url');
  23. const fixtures = require('./fixtures')
  24. const SVG_URL = fixtures.url('mofo_logo.SVG');
  25. const Isolate = fn => '(' + fn + ')()';
  26. function ignorePassingDOMNodeWarning(type, message) {
  27. if (type !== 'warn' || !message.startsWith('Passing a DOM node'))
  28. console[type](message);
  29. }
  30. function makeEmptyPrivateBrowserWindow(options) {
  31. options = options || {};
  32. return open('chrome://browser/content/browser.xul', {
  33. features: {
  34. chrome: true,
  35. toolbar: true,
  36. private: true
  37. }
  38. });
  39. }
  40. exports["test Panel"] = function(assert, done) {
  41. const { Panel } = require('sdk/panel');
  42. let panel = Panel({
  43. contentURL: "about:buildconfig",
  44. contentScript: "self.postMessage(1); self.on('message', function() self.postMessage(2));",
  45. onMessage: function (message) {
  46. assert.equal(this, panel, "The 'this' object is the panel.");
  47. switch(message) {
  48. case 1:
  49. assert.pass("The panel was loaded.");
  50. panel.postMessage('');
  51. break;
  52. case 2:
  53. assert.pass("The panel posted a message and received a response.");
  54. panel.destroy();
  55. done();
  56. break;
  57. }
  58. }
  59. });
  60. };
  61. exports["test Panel Emit"] = function(assert, done) {
  62. const { Panel } = require('sdk/panel');
  63. let panel = Panel({
  64. contentURL: "about:buildconfig",
  65. contentScript: "self.port.emit('loaded');" +
  66. "self.port.on('addon-to-content', " +
  67. " function() self.port.emit('received'));",
  68. });
  69. panel.port.on("loaded", function () {
  70. assert.pass("The panel was loaded and sent a first event.");
  71. panel.port.emit("addon-to-content");
  72. });
  73. panel.port.on("received", function () {
  74. assert.pass("The panel posted a message and received a response.");
  75. panel.destroy();
  76. done();
  77. });
  78. };
  79. exports["test Panel Emit Early"] = function(assert, done) {
  80. const { Panel } = require('sdk/panel');
  81. let panel = Panel({
  82. contentURL: "about:buildconfig",
  83. contentScript: "self.port.on('addon-to-content', " +
  84. " function() self.port.emit('received'));",
  85. });
  86. panel.port.on("received", function () {
  87. assert.pass("The panel posted a message early and received a response.");
  88. panel.destroy();
  89. done();
  90. });
  91. panel.port.emit("addon-to-content");
  92. };
  93. exports["test Show Hide Panel"] = function(assert, done) {
  94. const { Panel } = require('sdk/panel');
  95. let panel = Panel({
  96. contentScript: "self.postMessage('')",
  97. contentScriptWhen: "end",
  98. contentURL: "data:text/html;charset=utf-8,",
  99. onMessage: function (message) {
  100. panel.show();
  101. },
  102. onShow: function () {
  103. assert.pass("The panel was shown.");
  104. assert.equal(this, panel, "The 'this' object is the panel.");
  105. assert.equal(this.isShowing, true, "panel.isShowing == true.");
  106. panel.hide();
  107. },
  108. onHide: function () {
  109. assert.pass("The panel was hidden.");
  110. assert.equal(this, panel, "The 'this' object is the panel.");
  111. assert.equal(this.isShowing, false, "panel.isShowing == false.");
  112. panel.destroy();
  113. done();
  114. }
  115. });
  116. };
  117. exports["test Document Reload"] = function(assert, done) {
  118. const { Panel } = require('sdk/panel');
  119. let url2 = "data:text/html;charset=utf-8,page2";
  120. let content =
  121. "<script>" +
  122. "window.addEventListener('message', function({ data }) {"+
  123. " if (data == 'move') window.location = '" + url2 + "';" +
  124. '}, false);' +
  125. "</script>";
  126. let messageCount = 0;
  127. let panel = Panel({
  128. // using URL here is intentional, see bug 859009
  129. contentURL: URL("data:text/html;charset=utf-8," + encodeURIComponent(content)),
  130. contentScript: "self.postMessage(window.location.href);" +
  131. // initiate change to url2
  132. "self.port.once('move', function() document.defaultView.postMessage('move', '*'));",
  133. onMessage: function (message) {
  134. messageCount++;
  135. assert.notEqual(message, "about:blank", "about:blank is not a message " + messageCount);
  136. if (messageCount == 1) {
  137. assert.ok(/data:text\/html/.test(message), "First document had a content script; " + message);
  138. panel.port.emit('move');
  139. assert.pass('move message was sent');
  140. return;
  141. }
  142. else if (messageCount == 2) {
  143. assert.equal(message, url2, "Second document too; " + message);
  144. panel.destroy();
  145. done();
  146. }
  147. }
  148. });
  149. assert.pass('Panel was created');
  150. };
  151. // Test disabled because of bug 910230
  152. /*
  153. exports["test Parent Resize Hack"] = function(assert, done) {
  154. const { Panel } = require('sdk/panel');
  155. let browserWindow = getMostRecentBrowserWindow();
  156. let previousWidth = browserWindow.outerWidth;
  157. let previousHeight = browserWindow.outerHeight;
  158. let content = "<script>" +
  159. "function contentResize() {" +
  160. " resizeTo(200,200);" +
  161. " resizeBy(200,200);" +
  162. " window.postMessage('resize-attempt', '*');" +
  163. "}" +
  164. "</script>" +
  165. "Try to resize browser window";
  166. let panel = Panel({
  167. contentURL: "data:text/html;charset=utf-8," + encodeURIComponent(content),
  168. contentScriptWhen: "ready",
  169. contentScript: Isolate(() => {
  170. self.on('message', message => {
  171. if (message === 'resize') unsafeWindow.contentResize();
  172. });
  173. window.addEventListener('message', ({ data }) => self.postMessage(data));
  174. }),
  175. onMessage: function (message) {
  176. if (message !== "resize-attempt") return;
  177. assert.equal(browserWindow, getMostRecentBrowserWindow(),
  178. "The browser window is still the same");
  179. assert.equal(previousWidth, browserWindow.outerWidth,
  180. "Size doesn't change by calling resizeTo/By/...");
  181. assert.equal(previousHeight, browserWindow.outerHeight,
  182. "Size doesn't change by calling resizeTo/By/...");
  183. try {
  184. panel.destroy();
  185. }
  186. catch (e) {
  187. assert.fail(e);
  188. throw e;
  189. }
  190. done();
  191. },
  192. onShow: () => panel.postMessage('resize')
  193. });
  194. panel.show();
  195. }
  196. */
  197. exports["test Resize Panel"] = function(assert, done) {
  198. const { Panel } = require('sdk/panel');
  199. // These tests fail on Linux if the browser window in which the panel
  200. // is displayed is not active. And depending on what other tests have run
  201. // before this one, it might not be (the untitled window in which the test
  202. // runner executes is often active). So we make sure the browser window
  203. // is focused by focusing it before running the tests. Then, to be the best
  204. // possible test citizen, we refocus whatever window was focused before we
  205. // started running these tests.
  206. let activeWindow = Cc["@mozilla.org/embedcomp/window-watcher;1"].
  207. getService(Ci.nsIWindowWatcher).
  208. activeWindow;
  209. let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"].
  210. getService(Ci.nsIWindowMediator).
  211. getMostRecentWindow("navigator:browser");
  212. function onFocus() {
  213. browserWindow.removeEventListener("focus", onFocus, true);
  214. let panel = Panel({
  215. contentScript: "self.postMessage('')",
  216. contentScriptWhen: "end",
  217. contentURL: "data:text/html;charset=utf-8,",
  218. height: 10,
  219. width: 10,
  220. onMessage: function (message) {
  221. panel.show();
  222. },
  223. onShow: function () {
  224. panel.resize(100,100);
  225. panel.hide();
  226. },
  227. onHide: function () {
  228. assert.ok((panel.width == 100) && (panel.height == 100),
  229. "The panel was resized.");
  230. if (activeWindow)
  231. activeWindow.focus();
  232. done();
  233. }
  234. });
  235. }
  236. if (browserWindow === activeWindow) {
  237. onFocus();
  238. }
  239. else {
  240. browserWindow.addEventListener("focus", onFocus, true);
  241. browserWindow.focus();
  242. }
  243. };
  244. exports["test Hide Before Show"] = function(assert, done) {
  245. const { Panel } = require('sdk/panel');
  246. let showCalled = false;
  247. let panel = Panel({
  248. onShow: function () {
  249. showCalled = true;
  250. },
  251. onHide: function () {
  252. assert.ok(!showCalled, 'must not emit show if was hidden before');
  253. done();
  254. }
  255. });
  256. panel.show();
  257. panel.hide();
  258. };
  259. exports["test Several Show Hides"] = function(assert, done) {
  260. const { Panel } = require('sdk/panel');
  261. let hideCalled = 0;
  262. let panel = Panel({
  263. contentURL: "about:buildconfig",
  264. onShow: function () {
  265. panel.hide();
  266. },
  267. onHide: function () {
  268. hideCalled++;
  269. if (hideCalled < 3)
  270. panel.show();
  271. else {
  272. assert.pass("onHide called three times as expected");
  273. done();
  274. }
  275. }
  276. });
  277. panel.on('error', function(e) {
  278. assert.fail('error was emitted:' + e.message + '\n' + e.stack);
  279. });
  280. panel.show();
  281. };
  282. exports["test Anchor And Arrow"] = function(assert, done) {
  283. let { loader } = LoaderWithHookedConsole(module, ignorePassingDOMNodeWarning);
  284. let { Panel } = loader.require('sdk/panel');
  285. let count = 0;
  286. let queue = [];
  287. let tab;
  288. function newPanel(anchor) {
  289. let panel = Panel({
  290. contentURL: "data:text/html;charset=utf-8,<html><body style='padding: 0; margin: 0; " +
  291. "background: gray; text-align: center;'>Anchor: " +
  292. anchor.id + "</body></html>",
  293. width: 200,
  294. height: 100,
  295. onShow: function () {
  296. panel.destroy();
  297. next();
  298. }
  299. });
  300. queue.push({ panel: panel, anchor: anchor });
  301. }
  302. function next () {
  303. if (!queue.length) {
  304. assert.pass("All anchored panel test displayed");
  305. tab.close(function () {
  306. done();
  307. });
  308. return;
  309. }
  310. let { panel, anchor } = queue.shift();
  311. panel.show(null, anchor);
  312. }
  313. let tabs= require("sdk/tabs");
  314. let url = 'data:text/html;charset=utf-8,' +
  315. '<html><head><title>foo</title></head><body>' +
  316. '<style>div {background: gray; position: absolute; width: 300px; ' +
  317. 'border: 2px solid black;}</style>' +
  318. '<div id="tl" style="top: 0px; left: 0px;">Top Left</div>' +
  319. '<div id="tr" style="top: 0px; right: 0px;">Top Right</div>' +
  320. '<div id="bl" style="bottom: 0px; left: 0px;">Bottom Left</div>' +
  321. '<div id="br" style="bottom: 0px; right: 0px;">Bottom right</div>' +
  322. '</body></html>';
  323. tabs.open({
  324. url: url,
  325. onReady: function(_tab) {
  326. tab = _tab;
  327. let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"].
  328. getService(Ci.nsIWindowMediator).
  329. getMostRecentWindow("navigator:browser");
  330. let window = browserWindow.content;
  331. newPanel(window.document.getElementById('tl'));
  332. newPanel(window.document.getElementById('tr'));
  333. newPanel(window.document.getElementById('bl'));
  334. newPanel(window.document.getElementById('br'));
  335. let anchor = browserWindow.document.getElementById("identity-box");
  336. newPanel(anchor);
  337. next();
  338. }
  339. });
  340. };
  341. exports["test Panel Focus True"] = function(assert, done) {
  342. const { Panel } = require('sdk/panel');
  343. const FM = Cc["@mozilla.org/focus-manager;1"].
  344. getService(Ci.nsIFocusManager);
  345. let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"].
  346. getService(Ci.nsIWindowMediator).
  347. getMostRecentWindow("navigator:browser");
  348. // Make sure there is a focused element
  349. browserWindow.document.documentElement.focus();
  350. // Get the current focused element
  351. let focusedElement = FM.focusedElement;
  352. let panel = Panel({
  353. contentURL: "about:buildconfig",
  354. focus: true,
  355. onShow: function () {
  356. assert.ok(focusedElement !== FM.focusedElement,
  357. "The panel takes the focus away.");
  358. done();
  359. }
  360. });
  361. panel.show();
  362. };
  363. exports["test Panel Focus False"] = function(assert, done) {
  364. const { Panel } = require('sdk/panel');
  365. const FM = Cc["@mozilla.org/focus-manager;1"].
  366. getService(Ci.nsIFocusManager);
  367. let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"].
  368. getService(Ci.nsIWindowMediator).
  369. getMostRecentWindow("navigator:browser");
  370. // Make sure there is a focused element
  371. browserWindow.document.documentElement.focus();
  372. // Get the current focused element
  373. let focusedElement = FM.focusedElement;
  374. let panel = Panel({
  375. contentURL: "about:buildconfig",
  376. focus: false,
  377. onShow: function () {
  378. assert.ok(focusedElement === FM.focusedElement,
  379. "The panel does not take the focus away.");
  380. done();
  381. }
  382. });
  383. panel.show();
  384. };
  385. exports["test Panel Focus Not Set"] = function(assert, done) {
  386. const { Panel } = require('sdk/panel');
  387. const FM = Cc["@mozilla.org/focus-manager;1"].
  388. getService(Ci.nsIFocusManager);
  389. let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"].
  390. getService(Ci.nsIWindowMediator).
  391. getMostRecentWindow("navigator:browser");
  392. // Make sure there is a focused element
  393. browserWindow.document.documentElement.focus();
  394. // Get the current focused element
  395. let focusedElement = FM.focusedElement;
  396. let panel = Panel({
  397. contentURL: "about:buildconfig",
  398. onShow: function () {
  399. assert.ok(focusedElement !== FM.focusedElement,
  400. "The panel takes the focus away.");
  401. done();
  402. }
  403. });
  404. panel.show();
  405. };
  406. exports["test Panel Text Color"] = function(assert, done) {
  407. const { Panel } = require('sdk/panel');
  408. let html = "<html><head><style>body {color: yellow}</style></head>" +
  409. "<body><p>Foo</p></body></html>";
  410. let panel = Panel({
  411. contentURL: "data:text/html;charset=utf-8," + encodeURI(html),
  412. contentScript: "self.port.emit('color', " +
  413. "window.getComputedStyle(document.body.firstChild, null). " +
  414. " getPropertyValue('color'));"
  415. });
  416. panel.port.on("color", function (color) {
  417. assert.equal(color, "rgb(255, 255, 0)",
  418. "The panel text color style is preserved when a style exists.");
  419. panel.destroy();
  420. done();
  421. });
  422. };
  423. // Bug 866333
  424. exports["test watch event name"] = function(assert, done) {
  425. const { Panel } = require('sdk/panel');
  426. let html = "<html><head><style>body {color: yellow}</style></head>" +
  427. "<body><p>Foo</p></body></html>";
  428. let panel = Panel({
  429. contentURL: "data:text/html;charset=utf-8," + encodeURI(html),
  430. contentScript: "self.port.emit('watch', 'test');"
  431. });
  432. panel.port.on("watch", function (msg) {
  433. assert.equal(msg, "test", 'watch event name works');
  434. panel.destroy();
  435. done();
  436. });
  437. }
  438. // Bug 696552: Ensure panel.contentURL modification support
  439. exports["test Change Content URL"] = function(assert, done) {
  440. const { Panel } = require('sdk/panel');
  441. let panel = Panel({
  442. contentURL: "about:blank",
  443. contentScript: "self.port.emit('ready', document.location.href);"
  444. });
  445. let count = 0;
  446. panel.port.on("ready", function (location) {
  447. count++;
  448. if (count == 1) {
  449. assert.equal(location, "about:blank");
  450. assert.equal(panel.contentURL, "about:blank");
  451. panel.contentURL = "about:buildconfig";
  452. }
  453. else {
  454. assert.equal(location, "about:buildconfig");
  455. assert.equal(panel.contentURL, "about:buildconfig");
  456. panel.destroy();
  457. done();
  458. }
  459. });
  460. };
  461. function makeEventOrderTest(options) {
  462. let expectedEvents = [];
  463. return function(assert, done) {
  464. const { Panel } = require('sdk/panel');
  465. let panel = Panel({ contentURL: "about:buildconfig" });
  466. function expect(event, cb) {
  467. expectedEvents.push(event);
  468. panel.on(event, function() {
  469. assert.equal(event, expectedEvents.shift());
  470. if (cb)
  471. timer.setTimeout(cb, 1);
  472. });
  473. return {then: expect};
  474. }
  475. options.test(assert, done, expect, panel);
  476. }
  477. }
  478. exports["test Automatic Destroy"] = function(assert) {
  479. let loader = Loader(module);
  480. let panel = loader.require("sdk/panel").Panel({
  481. contentURL: "about:buildconfig",
  482. contentScript:
  483. "self.port.on('event', function() self.port.emit('event-back'));"
  484. });
  485. loader.unload();
  486. assert.throws(() => {
  487. panel.port.emit("event");
  488. }, /already have been unloaded/, "check automatic destroy");
  489. };
  490. exports["test Show Then Destroy"] = makeEventOrderTest({
  491. test: function(assert, done, expect, panel) {
  492. panel.show();
  493. expect('show', function() { panel.destroy(); }).
  494. then('hide', function() { done(); });
  495. }
  496. });
  497. exports["test Show Then Hide Then Destroy"] = makeEventOrderTest({
  498. test: function(assert, done, expect, panel) {
  499. panel.show();
  500. expect('show', function() { panel.hide(); }).
  501. then('hide', function() { panel.destroy(); done(); });
  502. }
  503. });
  504. exports["test Content URL Option"] = function(assert) {
  505. const { Panel } = require('sdk/panel');
  506. const URL_STRING = "about:buildconfig";
  507. const HTML_CONTENT = "<html><title>Test</title><p>This is a test.</p></html>";
  508. let (panel = Panel({ contentURL: URL_STRING })) {
  509. assert.pass("contentURL accepts a string URL.");
  510. assert.equal(panel.contentURL, URL_STRING,
  511. "contentURL is the string to which it was set.");
  512. }
  513. let dataURL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML_CONTENT);
  514. let (panel = Panel({ contentURL: dataURL })) {
  515. assert.pass("contentURL accepts a data: URL.");
  516. }
  517. let (panel = Panel({})) {
  518. assert.ok(panel.contentURL == null,
  519. "contentURL is undefined.");
  520. }
  521. assert.throws(function () Panel({ contentURL: "foo" }),
  522. /The `contentURL` option must be a valid URL./,
  523. "Panel throws an exception if contentURL is not a URL.");
  524. };
  525. exports["test SVG Document"] = function(assert) {
  526. let panel = require("sdk/panel").Panel({ contentURL: SVG_URL });
  527. panel.show();
  528. panel.hide();
  529. panel.destroy();
  530. assert.pass("contentURL accepts a svg document");
  531. assert.equal(panel.contentURL, SVG_URL,
  532. "contentURL is the string to which it was set.");
  533. };
  534. exports["test ContentScriptOptions Option"] = function(assert, done) {
  535. let loader = Loader(module);
  536. let panel = loader.require("sdk/panel").Panel({
  537. contentScript: "self.postMessage( [typeof self.options.d, self.options] );",
  538. contentScriptWhen: "end",
  539. contentScriptOptions: {a: true, b: [1,2,3], c: "string", d: function(){ return 'test'}},
  540. contentURL: "data:text/html;charset=utf-8,",
  541. onMessage: function(msg) {
  542. assert.equal( msg[0], 'undefined', 'functions are stripped from contentScriptOptions' );
  543. assert.equal( typeof msg[1], 'object', 'object as contentScriptOptions' );
  544. assert.equal( msg[1].a, true, 'boolean in contentScriptOptions' );
  545. assert.equal( msg[1].b.join(), '1,2,3', 'array and numbers in contentScriptOptions' );
  546. assert.equal( msg[1].c, 'string', 'string in contentScriptOptions' );
  547. done();
  548. }
  549. });
  550. };
  551. exports["test console.log in Panel"] = function(assert, done) {
  552. let text = 'console.log() in Panel works!';
  553. let html = '<script>onload = function log(){\
  554. console.log("' + text + '");\
  555. }</script>';
  556. let { loader } = LoaderWithHookedConsole(module, onMessage);
  557. let { Panel } = loader.require('sdk/panel');
  558. let panel = Panel({
  559. contentURL: 'data:text/html;charset=utf-8,' + encodeURIComponent(html)
  560. });
  561. panel.show();
  562. function onMessage(type, message) {
  563. assert.equal(type, 'log', 'console.log() works');
  564. assert.equal(message, text, 'console.log() works');
  565. panel.destroy();
  566. done();
  567. }
  568. };
  569. if (isWindowPBSupported) {
  570. exports.testPanelDoesNotShowInPrivateWindowNoAnchor = function(assert, done) {
  571. let { loader } = LoaderWithHookedConsole(module, ignorePassingDOMNodeWarning);
  572. let { Panel } = loader.require("sdk/panel");
  573. let browserWindow = getMostRecentBrowserWindow();
  574. assert.equal(isPrivate(browserWindow), false, 'open window is not private');
  575. let panel = Panel({
  576. contentURL: SVG_URL
  577. });
  578. testShowPanel(assert, panel).
  579. then(makeEmptyPrivateBrowserWindow).
  580. then(focus).
  581. then(function(window) {
  582. assert.equal(isPrivate(window), true, 'opened window is private');
  583. assert.pass('private window was focused');
  584. return window;
  585. }).
  586. then(function(window) {
  587. let { promise, resolve } = defer();
  588. let showTries = 0;
  589. let showCount = 0;
  590. panel.on('show', function runTests() {
  591. showCount++;
  592. if (showTries == 2) {
  593. panel.removeListener('show', runTests);
  594. assert.equal(showCount, 1, 'show count is correct - 1');
  595. resolve(window);
  596. }
  597. });
  598. showTries++;
  599. panel.show();
  600. showTries++;
  601. panel.show(null, browserWindow.gBrowser);
  602. return promise;
  603. }).
  604. then(function(window) {
  605. assert.equal(panel.isShowing, true, 'panel is still showing');
  606. panel.hide();
  607. assert.equal(panel.isShowing, false, 'panel is hidden');
  608. return window;
  609. }).
  610. then(close).
  611. then(function() {
  612. assert.pass('private window was closed');
  613. }).
  614. then(testShowPanel.bind(null, assert, panel)).
  615. then(done, assert.fail.bind(assert));
  616. }
  617. exports.testPanelDoesNotShowInPrivateWindowWithAnchor = function(assert, done) {
  618. let { loader } = LoaderWithHookedConsole(module, ignorePassingDOMNodeWarning);
  619. let { Panel } = loader.require("sdk/panel");
  620. let browserWindow = getMostRecentBrowserWindow();
  621. assert.equal(isPrivate(browserWindow), false, 'open window is not private');
  622. let panel = Panel({
  623. contentURL: SVG_URL
  624. });
  625. testShowPanel(assert, panel).
  626. then(makeEmptyPrivateBrowserWindow).
  627. then(focus).
  628. then(function(window) {
  629. assert.equal(isPrivate(window), true, 'opened window is private');
  630. assert.pass('private window was focused');
  631. return window;
  632. }).
  633. then(function(window) {
  634. let { promise, resolve } = defer();
  635. let showTries = 0;
  636. let showCount = 0;
  637. panel.on('show', function runTests() {
  638. showCount++;
  639. if (showTries == 2) {
  640. panel.removeListener('show', runTests);
  641. assert.equal(showCount, 1, 'show count is correct - 1');
  642. resolve(window);
  643. }
  644. });
  645. showTries++;
  646. panel.show(null, window.gBrowser);
  647. showTries++;
  648. panel.show(null, browserWindow.gBrowser);
  649. return promise;
  650. }).
  651. then(function(window) {
  652. assert.equal(panel.isShowing, true, 'panel is still showing');
  653. panel.hide();
  654. assert.equal(panel.isShowing, false, 'panel is hidden');
  655. return window;
  656. }).
  657. then(close).
  658. then(function() {
  659. assert.pass('private window was closed');
  660. }).
  661. then(testShowPanel.bind(null, assert, panel)).
  662. then(done, assert.fail.bind(assert));
  663. }
  664. }
  665. function testShowPanel(assert, panel) {
  666. let { promise, resolve } = defer();
  667. assert.ok(!panel.isShowing, 'the panel is not showing [1]');
  668. panel.once('show', function() {
  669. assert.ok(panel.isShowing, 'the panel is showing');
  670. panel.once('hide', function() {
  671. assert.ok(!panel.isShowing, 'the panel is not showing [2]');
  672. resolve(null);
  673. });
  674. panel.hide();
  675. })
  676. panel.show();
  677. return promise;
  678. }
  679. exports['test Style Applied Only Once'] = function (assert, done) {
  680. let loader = Loader(module);
  681. let panel = loader.require("sdk/panel").Panel({
  682. contentURL: "data:text/html;charset=utf-8,",
  683. contentScript:
  684. 'self.port.on("check",function() { self.port.emit("count", document.getElementsByTagName("style").length); });' +
  685. 'self.port.on("ping", function (count) { self.port.emit("pong", count); });'
  686. });
  687. panel.port.on('count', function (styleCount) {
  688. assert.equal(styleCount, 1, 'should only have one style');
  689. done();
  690. });
  691. panel.port.on('pong', function (counter) {
  692. panel[--counter % 2 ? 'hide' : 'show']();
  693. panel.port.emit(!counter ? 'check' : 'ping', counter);
  694. });
  695. panel.on('show', init);
  696. panel.show();
  697. function init () {
  698. panel.removeListener('show', init);
  699. panel.port.emit('ping', 10);
  700. }
  701. };
  702. exports['test Only One Panel Open Concurrently'] = function (assert, done) {
  703. const loader = Loader(module);
  704. const { Panel } = loader.require('sdk/panel')
  705. let panelA = Panel({
  706. contentURL: 'about:buildconfig'
  707. });
  708. let panelB = Panel({
  709. contentURL: 'about:buildconfig',
  710. onShow: function () {
  711. // When loading two panels simulataneously, only the second
  712. // should be shown, never showing the first
  713. assert.equal(panelA.isShowing, false, 'First panel is hidden');
  714. assert.equal(panelB.isShowing, true, 'Second panel is showing');
  715. panelC.show();
  716. }
  717. });
  718. let panelC = Panel({
  719. contentURL: 'about:buildconfig',
  720. onShow: function () {
  721. assert.equal(panelA.isShowing, false, 'First panel is hidden');
  722. assert.equal(panelB.isShowing, false, 'Second panel is hidden');
  723. assert.equal(panelC.isShowing, true, 'Third panel is showing');
  724. done();
  725. }
  726. });
  727. panelA.show();
  728. panelB.show();
  729. };
  730. exports['test passing DOM node as first argument'] = function (assert, done) {
  731. let warned = defer();
  732. let shown = defer();
  733. function onMessage(type, message) {
  734. let warning = 'Passing a DOM node to Panel.show() method is an unsupported ' +
  735. 'feature that will be soon replaced. ' +
  736. 'See: https://bugzilla.mozilla.org/show_bug.cgi?id=878877';
  737. assert.equal(type, 'warn',
  738. 'the message logged is a warning');
  739. assert.equal(message, warning,
  740. 'the warning content is correct');
  741. warned.resolve();
  742. }
  743. let { loader } = LoaderWithHookedConsole(module, onMessage);
  744. let { Panel } = loader.require('sdk/panel');
  745. let { Widget } = loader.require('sdk/widget');
  746. let { document } = getMostRecentBrowserWindow();
  747. let widgetId = 'widget:' + self.id + '-panel-widget';
  748. let panel = Panel({
  749. onShow: function() {
  750. let panelNode = document.getElementById('mainPopupSet').lastChild;
  751. assert.equal(panelNode.anchorNode, widgetNode,
  752. 'the panel is properly anchored to the widget');
  753. shown.resolve();
  754. }
  755. });
  756. let widget = Widget({
  757. id: 'panel-widget',
  758. label: 'panel widget',
  759. content: '<i></i>',
  760. });
  761. let widgetNode = document.getElementById(widgetId);
  762. all(warned.promise, shown.promise).
  763. then(loader.unload).
  764. then(done, assert.fail)
  765. panel.show(widgetNode);
  766. };
  767. // This test is checking that `onpupshowing` events emitted by panel's children
  768. // are not considered.
  769. // See Bug 886329
  770. exports['test nested popups'] = function (assert, done) {
  771. let loader = Loader(module);
  772. let { Panel } = loader.require('sdk/panel');
  773. let { getActiveView } = loader.require('sdk/view/core');
  774. let url = '<select><option>1<option>2<option>3</select>';
  775. let getContentWindow = panel => {
  776. return getActiveView(panel).querySelector('iframe').contentWindow;
  777. }
  778. let panel = Panel({
  779. contentURL: 'data:text/html;charset=utf-8,' + encodeURIComponent(url),
  780. onShow: () => {
  781. ready(getContentWindow(panel)).then(({ window, document }) => {
  782. let select = document.querySelector('select');
  783. let event = document.createEvent('UIEvent');
  784. event.initUIEvent('popupshowing', true, true, window, null);
  785. select.dispatchEvent(event);
  786. assert.equal(
  787. select,
  788. getContentWindow(panel).document.querySelector('select'),
  789. 'select is still loaded in panel'
  790. );
  791. done();
  792. });
  793. }
  794. });
  795. panel.show();
  796. };
  797. exports['test emits on url changes'] = function (assert, done) {
  798. let loader = Loader(module);
  799. let { Panel } = loader.require('sdk/panel');
  800. let uriA = 'data:text/html;charset=utf-8,A';
  801. let uriB = 'data:text/html;charset=utf-8,B';
  802. let panel = Panel({
  803. contentURL: uriA,
  804. contentScript: 'new ' + function() {
  805. self.port.on('hi', function() {
  806. self.port.emit('bye', document.URL);
  807. });
  808. }
  809. });
  810. panel.contentURL = uriB;
  811. panel.port.emit('hi', 'hi')
  812. panel.port.on('bye', function(uri) {
  813. assert.equal(uri, uriB, 'message was delivered to new uri');
  814. loader.unload();
  815. done();
  816. });
  817. };
  818. exports['test panel can be constructed without any arguments'] = function (assert) {
  819. const { Panel } = require('sdk/panel');
  820. let panel = Panel();
  821. assert.ok(true, "Creating a panel with no arguments does not throw");
  822. };
  823. if (isWindowPBSupported) {
  824. exports.testGetWindow = function(assert, done) {
  825. let activeWindow = getMostRecentBrowserWindow();
  826. open(null, { features: {
  827. toolbar: true,
  828. chrome: true,
  829. private: true
  830. } }).then(function(window) {
  831. assert.ok(isPrivate(window), 'window is private');
  832. assert.equal(getWindow(window.gBrowser), null, 'private window elements returns null');
  833. assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'non-private window elements returns window');
  834. close(window).then(done);
  835. })
  836. }
  837. }
  838. else if (isGlobalPBSupported) {
  839. exports.testGetWindow = function(assert, done) {
  840. let activeWindow = getMostRecentBrowserWindow();
  841. assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'non-private window elements returns window');
  842. pb.once('start', function() {
  843. assert.ok(isPrivate(activeWindow), 'window is private');
  844. assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'private window elements returns window');
  845. open(null, { features: {
  846. toolbar: true,
  847. chrome: true
  848. } }).then(function(window) {
  849. assert.ok(isPrivate(window), 'window is private');
  850. assert.equal(getWindow(window.gBrowser), window, 'private window elements returns window');
  851. assert.equal(getWindow(activeWindow.gBrowser), activeWindow, 'active window elements returns window');
  852. pb.once('stop', done);
  853. pb.deactivate();
  854. })
  855. });
  856. pb.activate();
  857. }
  858. }
  859. require("test").run(exports);