addon-sdk/source/test/test-panel.js

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

mercurial