Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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';
6 const { Cc, Ci } = require('chrome');
7 const { Loader } = require('sdk/test/loader');
8 const { setTimeout } = require('sdk/timers');
9 const { getOwnerWindow } = require('sdk/private-browsing/window/utils');
10 const { windows, onFocus, getMostRecentBrowserWindow } = require('sdk/window/utils');
11 const { open, focus, close } = require('sdk/window/helpers');
12 const tabs = require('sdk/tabs');
13 const { browserWindows } = require('sdk/windows');
14 const { set: setPref } = require("sdk/preferences/service");
15 const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
16 const fixtures = require("../fixtures");
18 // Bug 682681 - tab.title should never be empty
19 exports.testBug682681_aboutURI = function(assert, done) {
20 let url = 'chrome://browser/locale/tabbrowser.properties';
21 let stringBundle = Cc["@mozilla.org/intl/stringbundle;1"].
22 getService(Ci.nsIStringBundleService).
23 createBundle(url);
24 let emptyTabTitle = stringBundle.GetStringFromName('tabs.emptyTabTitle');
26 tabs.on('ready', function onReady(tab) {
27 tabs.removeListener('ready', onReady);
29 assert.equal(tab.title,
30 emptyTabTitle,
31 "title of about: tab is not blank");
33 tab.close(done);
34 });
36 // open a about: url
37 tabs.open({
38 url: "about:blank",
39 inBackground: true
40 });
41 };
43 // related to Bug 682681
44 exports.testTitleForDataURI = function(assert, done) {
45 tabs.open({
46 url: "data:text/html;charset=utf-8,<title>tab</title>",
47 inBackground: true,
48 onReady: function(tab) {
49 assert.equal(tab.title, "tab", "data: title is not Connecting...");
50 tab.close(done);
51 }
52 });
53 };
55 // TEST: 'BrowserWindow' instance creation on tab 'activate' event
56 // See bug 648244: there was a infinite loop.
57 exports.testBrowserWindowCreationOnActivate = function(assert, done) {
58 let windows = require("sdk/windows").browserWindows;
59 let gotActivate = false;
61 tabs.once('activate', function onActivate(eventTab) {
62 assert.ok(windows.activeWindow, "Is able to fetch activeWindow");
63 gotActivate = true;
64 });
66 open().then(function(window) {
67 assert.ok(gotActivate, "Received activate event");
68 return close(window);
69 }).then(done).then(null, assert.fail);
70 }
72 // TEST: tab unloader
73 exports.testAutomaticDestroyEventOpen = function(assert, done) {
74 let called = false;
75 let loader = Loader(module);
76 let tabs2 = loader.require("sdk/tabs");
77 tabs2.on('open', _ => called = true);
79 // Fire a tab event and ensure that the destroyed tab is inactive
80 tabs.once('open', tab => {
81 setTimeout(_ => {
82 assert.ok(!called, "Unloaded tab module is destroyed and inactive");
83 tab.close(done);
84 });
85 });
87 loader.unload();
88 tabs.open("data:text/html;charset=utf-8,testAutomaticDestroyEventOpen");
89 };
91 exports.testAutomaticDestroyEventActivate = function(assert, done) {
92 let called = false;
93 let loader = Loader(module);
94 let tabs2 = loader.require("sdk/tabs");
95 tabs2.on('activate', _ => called = true);
97 // Fire a tab event and ensure that the destroyed tab is inactive
98 tabs.once('activate', tab => {
99 setTimeout(_ => {
100 assert.ok(!called, "Unloaded tab module is destroyed and inactive");
101 tab.close(done);
102 });
103 });
105 loader.unload();
106 tabs.open("data:text/html;charset=utf-8,testAutomaticDestroyEventActivate");
107 };
109 exports.testAutomaticDestroyEventDeactivate = function(assert, done) {
110 let called = false;
111 let currentTab = tabs.activeTab;
112 let loader = Loader(module);
113 let tabs2 = loader.require("sdk/tabs");
115 tabs.open({
116 url: "data:text/html;charset=utf-8,testAutomaticDestroyEventDeactivate",
117 onActivate: _ => setTimeout(_ => {
118 tabs2.on('deactivate', _ => called = true);
120 // Fire a tab event and ensure that the destroyed tab is inactive
121 tabs.once('deactivate', tab => {
122 setTimeout(_ => {
123 assert.ok(!called, "Unloaded tab module is destroyed and inactive");
124 tab.close(done);
125 });
126 });
128 loader.unload();
129 currentTab.activate();
130 })
131 });
132 };
134 exports.testAutomaticDestroyEventClose = function(assert, done) {
135 let called = false;
136 let loader = Loader(module);
137 let tabs2 = loader.require("sdk/tabs");
139 tabs.open({
140 url: "data:text/html;charset=utf-8,testAutomaticDestroyEventClose",
141 onReady: tab => {
142 tabs2.on('close', _ => called = true);
144 // Fire a tab event and ensure that the destroyed tab is inactive
145 tabs.once('close', tab => {
146 setTimeout(_ => {
147 assert.ok(!called, "Unloaded tab module is destroyed and inactive");
148 done();
149 });
150 });
152 loader.unload();
153 tab.close();
154 }
155 });
156 };
158 exports.testTabPropertiesInNewWindow = function(assert, done) {
159 let warning = "DEPRECATED: tab.favicon is deprecated, please use require(\"sdk/places/favicon\").getFavicon instead.\n"
160 const { LoaderWithFilteredConsole } = require("sdk/test/loader");
161 let loader = LoaderWithFilteredConsole(module, function(type, message) {
162 if (type == "error" && message.substring(0, warning.length) == warning)
163 return false;
164 return true;
165 });
167 let tabs = loader.require('sdk/tabs');
168 let { getOwnerWindow } = loader.require('sdk/private-browsing/window/utils');
170 let count = 0;
171 function onReadyOrLoad (tab) {
172 if (count++) {
173 close(getOwnerWindow(tab)).then(done).then(null, assert.fail);
174 }
175 }
177 let url = "data:text/html;charset=utf-8,<html><head><title>foo</title></head><body>foo</body></html>";
178 tabs.open({
179 inNewWindow: true,
180 url: url,
181 onReady: function(tab) {
182 assert.equal(tab.title, "foo", "title of the new tab matches");
183 assert.equal(tab.url, url, "URL of the new tab matches");
184 assert.ok(tab.favicon, "favicon of the new tab is not empty");
185 assert.equal(tab.style, null, "style of the new tab matches");
186 assert.equal(tab.index, 0, "index of the new tab matches");
187 assert.notEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
188 assert.notEqual(tab.id, null, "a tab object always has an id property.");
190 onReadyOrLoad(tab);
191 },
192 onLoad: function(tab) {
193 assert.equal(tab.title, "foo", "title of the new tab matches");
194 assert.equal(tab.url, url, "URL of the new tab matches");
195 assert.ok(tab.favicon, "favicon of the new tab is not empty");
196 assert.equal(tab.style, null, "style of the new tab matches");
197 assert.equal(tab.index, 0, "index of the new tab matches");
198 assert.notEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
199 assert.notEqual(tab.id, null, "a tab object always has an id property.");
201 onReadyOrLoad(tab);
202 }
203 });
204 };
206 exports.testTabPropertiesInSameWindow = function(assert, done) {
207 let warning = "DEPRECATED: tab.favicon is deprecated, please use require(\"sdk/places/favicon\").getFavicon instead.\n"
208 const { LoaderWithFilteredConsole } = require("sdk/test/loader");
209 let loader = LoaderWithFilteredConsole(module, function(type, message) {
210 if (type == "error" && message.substring(0, warning.length) == warning)
211 return false;
212 return true;
213 });
215 let tabs = loader.require('sdk/tabs');
217 // Get current count of tabs so we know the index of the
218 // new tab, bug 893846
219 let tabCount = tabs.length;
220 let count = 0;
221 function onReadyOrLoad (tab) {
222 if (count++) {
223 tab.close(done);
224 }
225 }
227 let url = "data:text/html;charset=utf-8,<html><head><title>foo</title></head><body>foo</body></html>";
228 tabs.open({
229 url: url,
230 onReady: function(tab) {
231 assert.equal(tab.title, "foo", "title of the new tab matches");
232 assert.equal(tab.url, url, "URL of the new tab matches");
233 assert.ok(tab.favicon, "favicon of the new tab is not empty");
234 assert.equal(tab.style, null, "style of the new tab matches");
235 assert.equal(tab.index, tabCount, "index of the new tab matches");
236 assert.notEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
237 assert.notEqual(tab.id, null, "a tab object always has an id property.");
239 onReadyOrLoad(tab);
240 },
241 onLoad: function(tab) {
242 assert.equal(tab.title, "foo", "title of the new tab matches");
243 assert.equal(tab.url, url, "URL of the new tab matches");
244 assert.ok(tab.favicon, "favicon of the new tab is not empty");
245 assert.equal(tab.style, null, "style of the new tab matches");
246 assert.equal(tab.index, tabCount, "index of the new tab matches");
247 assert.notEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
248 assert.notEqual(tab.id, null, "a tab object always has an id property.");
250 onReadyOrLoad(tab);
251 }
252 });
253 };
255 // TEST: tab properties
256 exports.testTabContentTypeAndReload = function(assert, done) {
257 open().then(focus).then(function(window) {
258 let url = "data:text/html;charset=utf-8,<html><head><title>foo</title></head><body>foo</body></html>";
259 let urlXML = "data:text/xml;charset=utf-8,<foo>bar</foo>";
260 tabs.open({
261 url: url,
262 onReady: function(tab) {
263 if (tab.url === url) {
264 assert.equal(tab.contentType, "text/html");
265 tab.url = urlXML;
266 }
267 else {
268 assert.equal(tab.contentType, "text/xml");
269 close(window).then(done).then(null, assert.fail);
270 }
271 }
272 });
273 });
274 };
276 // TEST: tabs iterator and length property
277 exports.testTabsIteratorAndLength = function(assert, done) {
278 open(null, { features: { chrome: true, toolbar: true } }).then(focus).then(function(window) {
279 let startCount = 0;
280 for each (let t in tabs) startCount++;
281 assert.equal(startCount, tabs.length, "length property is correct");
282 let url = "data:text/html;charset=utf-8,default";
284 tabs.open(url);
285 tabs.open(url);
286 tabs.open({
287 url: url,
288 onOpen: function(tab) {
289 let count = 0;
290 for each (let t in tabs) count++;
291 assert.equal(count, startCount + 3, "iterated tab count matches");
292 assert.equal(startCount + 3, tabs.length, "iterated tab count matches length property");
294 close(window).then(done).then(null, assert.fail);
295 }
296 });
297 });
298 };
300 // TEST: tab.url setter
301 exports.testTabLocation = function(assert, done) {
302 open().then(focus).then(function(window) {
303 let url1 = "data:text/html;charset=utf-8,foo";
304 let url2 = "data:text/html;charset=utf-8,bar";
306 tabs.on('ready', function onReady(tab) {
307 if (tab.url != url2)
308 return;
309 tabs.removeListener('ready', onReady);
310 assert.pass("tab.load() loaded the correct url");
311 close(window).then(done).then(null, assert.fail);
312 });
314 tabs.open({
315 url: url1,
316 onOpen: function(tab) {
317 tab.url = url2
318 }
319 });
320 });
321 };
323 // TEST: tab.close()
324 exports.testTabClose = function(assert, done) {
325 let testName = "testTabClose";
326 let url = "data:text/html;charset=utf-8," + testName;
328 assert.notEqual(tabs.activeTab.url, url, "tab is not the active tab");
329 tabs.once('ready', function onReady(tab) {
330 assert.equal(tabs.activeTab.url, tab.url, "tab is now the active tab");
331 assert.equal(url, tab.url, "tab url is the test url");
332 let secondOnCloseCalled = false;
334 // Bug 699450: Multiple calls to tab.close should not throw
335 tab.close(function() secondOnCloseCalled = true);
336 try {
337 tab.close(function () {
338 assert.notEqual(tabs.activeTab.url, url, "tab is no longer the active tab");
339 assert.ok(secondOnCloseCalled,
340 "The immediate second call to tab.close happened");
341 assert.notEqual(tabs.activeTab.url, url, "tab is no longer the active tab");
343 done();
344 });
345 }
346 catch(e) {
347 assert.fail("second call to tab.close() thrown an exception: " + e);
348 }
349 });
351 tabs.open(url);
352 };
354 // TEST: tab.move()
355 exports.testTabMove = function(assert, done) {
356 open().then(focus).then(function(window) {
357 let url = "data:text/html;charset=utf-8,foo";
359 tabs.open({
360 url: url,
361 onOpen: function(tab) {
362 assert.equal(tab.index, 1, "tab index before move matches");
363 tab.index = 0;
364 assert.equal(tab.index, 0, "tab index after move matches");
365 close(window).then(done).then(null, assert.fail);
366 }
367 });
368 }).then(null, assert.fail);
369 };
371 // TEST: open tab with default options
372 exports.testOpen = function(assert, done) {
373 let url = "data:text/html;charset=utf-8,default";
374 tabs.open({
375 url: url,
376 onReady: function(tab) {
377 assert.equal(tab.url, url, "URL of the new tab matches");
378 assert.equal(tab.isPinned, false, "The new tab is not pinned");
380 tab.close(done);
381 }
382 });
383 };
385 // TEST: opening a pinned tab
386 exports.testOpenPinned = function(assert, done) {
387 let url = "data:text/html;charset=utf-8,default";
388 tabs.open({
389 url: url,
390 isPinned: true,
391 onOpen: function(tab) {
392 assert.equal(tab.isPinned, true, "The new tab is pinned");
393 tab.close(done);
394 }
395 });
396 };
398 // TEST: pin/unpin opened tab
399 exports.testPinUnpin = function(assert, done) {
400 let url = "data:text/html;charset=utf-8,default";
401 tabs.open({
402 url: url,
403 inBackground: true,
404 onOpen: function(tab) {
405 tab.pin();
406 assert.equal(tab.isPinned, true, "The tab was pinned correctly");
407 tab.unpin();
408 assert.equal(tab.isPinned, false, "The tab was unpinned correctly");
409 tab.close(done);
410 }
411 });
412 }
414 // TEST: open tab in background
415 exports.testInBackground = function(assert, done) {
416 let window = getMostRecentBrowserWindow();
417 let activeUrl = tabs.activeTab.url;
418 let url = "data:text/html;charset=utf-8,background";
419 assert.equal(getMostRecentBrowserWindow(), window, "getMostRecentBrowserWindow() matches this window");
420 tabs.on('ready', function onReady(tab) {
421 tabs.removeListener('ready', onReady);
422 assert.equal(tabs.activeTab.url, activeUrl, "URL of active tab has not changed");
423 assert.equal(tab.url, url, "URL of the new background tab matches");
424 assert.equal(getMostRecentBrowserWindow(), window, "a new window was not opened");
425 assert.notEqual(tabs.activeTab.url, url, "URL of active tab is not the new URL");
426 tab.close(done);
427 });
429 tabs.open({
430 url: url,
431 inBackground: true
432 });
433 }
435 // TEST: open tab in new window
436 exports.testOpenInNewWindow = function(assert, done) {
437 let startWindowCount = windows().length;
439 let url = "data:text/html;charset=utf-8,testOpenInNewWindow";
440 tabs.open({
441 url: url,
442 inNewWindow: true,
443 onReady: function(tab) {
444 let newWindow = getOwnerWindow(tab);
445 assert.equal(windows().length, startWindowCount + 1, "a new window was opened");
447 onFocus(newWindow).then(function() {
448 assert.equal(getMostRecentBrowserWindow(), newWindow, "new window is active");
449 assert.equal(tab.url, url, "URL of the new tab matches");
450 assert.equal(newWindow.content.location, url, "URL of new tab in new window matches");
451 assert.equal(tabs.activeTab.url, url, "URL of activeTab matches");
453 return close(newWindow).then(done);
454 }).then(null, assert.fail);
455 }
456 });
458 }
460 // Test tab.open inNewWindow + onOpen combination
461 exports.testOpenInNewWindowOnOpen = function(assert, done) {
462 let startWindowCount = windows().length;
464 let url = "data:text/html;charset=utf-8,newwindow";
465 tabs.open({
466 url: url,
467 inNewWindow: true,
468 onOpen: function(tab) {
469 let newWindow = getOwnerWindow(tab);
471 onFocus(newWindow).then(function() {
472 assert.equal(windows().length, startWindowCount + 1, "a new window was opened");
473 assert.equal(getMostRecentBrowserWindow(), newWindow, "new window is active");
475 close(newWindow).then(done).then(null, assert.fail);
476 });
477 }
478 });
479 };
481 // TEST: onOpen event handler
482 exports.testTabsEvent_onOpen = function(assert, done) {
483 open().then(focus).then(window => {
484 let url = "data:text/html;charset=utf-8,1";
485 let eventCount = 0;
487 // add listener via property assignment
488 function listener1(tab) {
489 eventCount++;
490 };
491 tabs.on('open', listener1);
493 // add listener via collection add
494 tabs.on('open', function listener2(tab) {
495 assert.equal(++eventCount, 2, "both listeners notified");
496 tabs.removeListener('open', listener1);
497 tabs.removeListener('open', listener2);
498 close(window).then(done).then(null, assert.fail);
499 });
501 tabs.open(url);
502 }).then(null, assert.fail);
503 };
505 // TEST: onClose event handler
506 exports.testTabsEvent_onClose = function(assert, done) {
507 open().then(focus).then(window => {
508 let url = "data:text/html;charset=utf-8,onclose";
509 let eventCount = 0;
511 // add listener via property assignment
512 function listener1(tab) {
513 eventCount++;
514 }
515 tabs.on('close', listener1);
517 // add listener via collection add
518 tabs.on('close', function listener2(tab) {
519 assert.equal(++eventCount, 2, "both listeners notified");
520 tabs.removeListener('close', listener1);
521 tabs.removeListener('close', listener2);
522 close(window).then(done).then(null, assert.fail);
523 });
525 tabs.on('ready', function onReady(tab) {
526 tabs.removeListener('ready', onReady);
527 tab.close();
528 });
530 tabs.open(url);
531 }).then(null, assert.fail);
532 };
534 // TEST: onClose event handler when a window is closed
535 exports.testTabsEvent_onCloseWindow = function(assert, done) {
536 let closeCount = 0;
537 let individualCloseCount = 0;
539 open().then(focus).then(window => {
540 assert.pass('opened a new window');
542 tabs.on("close", function listener() {
543 if (++closeCount == 4) {
544 tabs.removeListener("close", listener);
545 }
546 });
548 function endTest() {
549 if (++individualCloseCount < 3) {
550 assert.pass('tab closed ' + individualCloseCount);
551 return;
552 }
554 assert.equal(closeCount, 4, "Correct number of close events received");
555 assert.equal(individualCloseCount, 3,
556 "Each tab with an attached onClose listener received a close " +
557 "event when the window was closed");
559 done();
560 }
562 // One tab is already open with the window
563 let openTabs = 1;
564 function testCasePossiblyLoaded() {
565 if (++openTabs == 4) {
566 window.close();
567 }
568 assert.pass('tab opened ' + openTabs);
569 }
571 tabs.open({
572 url: "data:text/html;charset=utf-8,tab2",
573 onOpen: testCasePossiblyLoaded,
574 onClose: endTest
575 });
577 tabs.open({
578 url: "data:text/html;charset=utf-8,tab3",
579 onOpen: testCasePossiblyLoaded,
580 onClose: endTest
581 });
583 tabs.open({
584 url: "data:text/html;charset=utf-8,tab4",
585 onOpen: testCasePossiblyLoaded,
586 onClose: endTest
587 });
588 }).then(null, assert.fail);
589 }
591 // TEST: onReady event handler
592 exports.testTabsEvent_onReady = function(assert, done) {
593 open().then(focus).then(window => {
594 let url = "data:text/html;charset=utf-8,onready";
595 let eventCount = 0;
597 // add listener via property assignment
598 function listener1(tab) {
599 eventCount++;
600 };
601 tabs.on('ready', listener1);
603 // add listener via collection add
604 tabs.on('ready', function listener2(tab) {
605 assert.equal(++eventCount, 2, "both listeners notified");
606 tabs.removeListener('ready', listener1);
607 tabs.removeListener('ready', listener2);
608 close(window).then(done);
609 });
611 tabs.open(url);
612 }).then(null, assert.fail);
613 };
615 // TEST: onActivate event handler
616 exports.testTabsEvent_onActivate = function(assert, done) {
617 open().then(focus).then(window => {
618 let url = "data:text/html;charset=utf-8,onactivate";
619 let eventCount = 0;
621 // add listener via property assignment
622 function listener1(tab) {
623 eventCount++;
624 };
625 tabs.on('activate', listener1);
627 // add listener via collection add
628 tabs.on('activate', function listener2(tab) {
629 assert.equal(++eventCount, 2, "both listeners notified");
630 tabs.removeListener('activate', listener1);
631 tabs.removeListener('activate', listener2);
632 close(window).then(done).then(null, assert.fail);
633 });
635 tabs.open(url);
636 }).then(null, assert.fail);
637 };
639 // onDeactivate event handler
640 exports.testTabsEvent_onDeactivate = function(assert, done) {
641 open().then(focus).then(window => {
642 let url = "data:text/html;charset=utf-8,ondeactivate";
643 let eventCount = 0;
645 // add listener via property assignment
646 function listener1(tab) {
647 eventCount++;
648 };
649 tabs.on('deactivate', listener1);
651 // add listener via collection add
652 tabs.on('deactivate', function listener2(tab) {
653 assert.equal(++eventCount, 2, "both listeners notified");
654 tabs.removeListener('deactivate', listener1);
655 tabs.removeListener('deactivate', listener2);
656 close(window).then(done).then(null, assert.fail);
657 });
659 tabs.on('open', function onOpen(tab) {
660 tabs.removeListener('open', onOpen);
661 tabs.open("data:text/html;charset=utf-8,foo");
662 });
664 tabs.open(url);
665 }).then(null, assert.fail);
666 };
668 // pinning
669 exports.testTabsEvent_pinning = function(assert, done) {
670 open().then(focus).then(window => {
671 let url = "data:text/html;charset=utf-8,1";
673 tabs.on('open', function onOpen(tab) {
674 tabs.removeListener('open', onOpen);
675 tab.pin();
676 });
678 tabs.on('pinned', function onPinned(tab) {
679 tabs.removeListener('pinned', onPinned);
680 assert.ok(tab.isPinned, "notified tab is pinned");
681 tab.unpin();
682 });
684 tabs.on('unpinned', function onUnpinned(tab) {
685 tabs.removeListener('unpinned', onUnpinned);
686 assert.ok(!tab.isPinned, "notified tab is not pinned");
687 close(window).then(done).then(null, assert.fail);
688 });
690 tabs.open(url);
691 }).then(null, assert.fail);
692 };
694 // TEST: per-tab event handlers
695 exports.testPerTabEvents = function(assert, done) {
696 open().then(focus).then(window => {
697 let eventCount = 0;
699 tabs.open({
700 url: "data:text/html;charset=utf-8,foo",
701 onOpen: function(tab) {
702 // add listener via property assignment
703 function listener1() {
704 eventCount++;
705 };
706 tab.on('ready', listener1);
708 // add listener via collection add
709 tab.on('ready', function listener2() {
710 assert.equal(eventCount, 1, "both listeners notified");
711 tab.removeListener('ready', listener1);
712 tab.removeListener('ready', listener2);
713 close(window).then(done).then(null, assert.fail);
714 });
715 }
716 });
717 }).then(null, assert.fail);
718 };
720 exports.testAttachOnOpen = function (assert, done) {
721 // Take care that attach has to be called on tab ready and not on tab open.
722 open().then(focus).then(window => {
723 tabs.open({
724 url: "data:text/html;charset=utf-8,foobar",
725 onOpen: function (tab) {
726 let worker = tab.attach({
727 contentScript: 'self.postMessage(document.location.href); ',
728 onMessage: function (msg) {
729 assert.equal(msg, "about:blank",
730 "Worker document url is about:blank on open");
731 worker.destroy();
732 close(window).then(done).then(null, assert.fail);
733 }
734 });
735 }
736 });
737 }).then(null, assert.fail);
738 }
740 exports.testAttachOnMultipleDocuments = function (assert, done) {
741 // Example of attach that process multiple tab documents
742 open().then(focus).then(window => {
743 let firstLocation = "data:text/html;charset=utf-8,foobar";
744 let secondLocation = "data:text/html;charset=utf-8,bar";
745 let thirdLocation = "data:text/html;charset=utf-8,fox";
746 let onReadyCount = 0;
747 let worker1 = null;
748 let worker2 = null;
749 let detachEventCount = 0;
751 tabs.open({
752 url: firstLocation,
753 onReady: function (tab) {
754 onReadyCount++;
755 if (onReadyCount == 1) {
756 worker1 = tab.attach({
757 contentScript: 'self.on("message", ' +
758 ' function () self.postMessage(document.location.href)' +
759 ');',
760 onMessage: function (msg) {
761 assert.equal(msg, firstLocation,
762 "Worker url is equal to the 1st document");
763 tab.url = secondLocation;
764 },
765 onDetach: function () {
766 detachEventCount++;
767 assert.pass("Got worker1 detach event");
768 assert.throws(function () {
769 worker1.postMessage("ex-1");
770 },
771 /Couldn't find the worker/,
772 "postMessage throw because worker1 is destroyed");
773 checkEnd();
774 }
775 });
776 worker1.postMessage("new-doc-1");
777 }
778 else if (onReadyCount == 2) {
780 worker2 = tab.attach({
781 contentScript: 'self.on("message", ' +
782 ' function () self.postMessage(document.location.href)' +
783 ');',
784 onMessage: function (msg) {
785 assert.equal(msg, secondLocation,
786 "Worker url is equal to the 2nd document");
787 tab.url = thirdLocation;
788 },
789 onDetach: function () {
790 detachEventCount++;
791 assert.pass("Got worker2 detach event");
792 assert.throws(function () {
793 worker2.postMessage("ex-2");
794 },
795 /Couldn't find the worker/,
796 "postMessage throw because worker2 is destroyed");
797 checkEnd();
798 }
799 });
800 worker2.postMessage("new-doc-2");
801 }
802 else if (onReadyCount == 3) {
803 tab.close();
804 }
805 }
806 });
808 function checkEnd() {
809 if (detachEventCount != 2)
810 return;
812 assert.pass("Got all detach events");
814 close(window).then(done).then(null, assert.fail);
815 }
816 }).then(null, assert.fail);
817 }
820 exports.testAttachWrappers = function (assert, done) {
821 // Check that content script has access to wrapped values by default
822 open().then(focus).then(window => {
823 let document = "data:text/html;charset=utf-8,<script>var globalJSVar = true; " +
824 " document.getElementById = 3;</script>";
825 let count = 0;
827 tabs.open({
828 url: document,
829 onReady: function (tab) {
830 let worker = tab.attach({
831 contentScript: 'try {' +
832 ' self.postMessage(!("globalJSVar" in window));' +
833 ' self.postMessage(typeof window.globalJSVar == "undefined");' +
834 '} catch(e) {' +
835 ' self.postMessage(e.message);' +
836 '}',
837 onMessage: function (msg) {
838 assert.equal(msg, true, "Worker has wrapped objects ("+count+")");
839 if (count++ == 1)
840 close(window).then(done).then(null, assert.fail);
841 }
842 });
843 }
844 });
845 }).then(null, assert.fail);
846 }
848 /*
849 // We do not offer unwrapped access to DOM since bug 601295 landed
850 // See 660780 to track progress of unwrap feature
851 exports.testAttachUnwrapped = function (assert, done) {
852 // Check that content script has access to unwrapped values through unsafeWindow
853 openBrowserWindow(function(window, browser) {
854 let document = "data:text/html;charset=utf-8,<script>var globalJSVar=true;</script>";
855 let count = 0;
857 tabs.open({
858 url: document,
859 onReady: function (tab) {
860 let worker = tab.attach({
861 contentScript: 'try {' +
862 ' self.postMessage(unsafeWindow.globalJSVar);' +
863 '} catch(e) {' +
864 ' self.postMessage(e.message);' +
865 '}',
866 onMessage: function (msg) {
867 assert.equal(msg, true, "Worker has access to javascript content globals ("+count+")");
868 close(window).then(done);
869 }
870 });
871 }
872 });
874 });
875 }
876 */
878 exports['test window focus changes active tab'] = function(assert, done) {
879 let url1 = "data:text/html;charset=utf-8," + encodeURIComponent("test window focus changes active tab</br><h1>Window #1");
881 let win1 = openBrowserWindow(function() {
882 assert.pass("window 1 is open");
884 let win2 = openBrowserWindow(function() {
885 assert.pass("window 2 is open");
887 focus(win2).then(function() {
888 tabs.on("activate", function onActivate(tab) {
889 tabs.removeListener("activate", onActivate);
890 assert.pass("activate was called on windows focus change.");
891 assert.equal(tab.url, url1, 'the activated tab url is correct');
893 return close(win2).then(function() {
894 assert.pass('window 2 was closed');
895 return close(win1);
896 }).then(done).then(null, assert.fail);
897 });
899 win1.focus();
900 });
901 }, "data:text/html;charset=utf-8,test window focus changes active tab</br><h1>Window #2");
902 }, url1);
903 };
905 exports['test ready event on new window tab'] = function(assert, done) {
906 let uri = encodeURI("data:text/html;charset=utf-8,Waiting for ready event!");
908 require("sdk/tabs").on("ready", function onReady(tab) {
909 if (tab.url === uri) {
910 require("sdk/tabs").removeListener("ready", onReady);
911 assert.pass("ready event was emitted");
912 close(window).then(done).then(null, assert.fail);
913 }
914 });
916 let window = openBrowserWindow(function(){}, uri);
917 };
919 exports['test unique tab ids'] = function(assert, done) {
920 var windows = require('sdk/windows').browserWindows;
921 var { all, defer } = require('sdk/core/promise');
923 function openWindow() {
924 let deferred = defer();
925 let win = windows.open({
926 url: "data:text/html;charset=utf-8,<html>foo</html>",
927 });
929 win.on('open', function(window) {
930 assert.ok(window.tabs.length);
931 assert.ok(window.tabs.activeTab);
932 assert.ok(window.tabs.activeTab.id);
933 deferred.resolve({
934 id: window.tabs.activeTab.id,
935 win: win
936 });
937 });
939 return deferred.promise;
940 }
942 var one = openWindow(), two = openWindow();
943 all([one, two]).then(function(results) {
944 assert.notEqual(results[0].id, results[1].id, "tab Ids should not be equal.");
945 results[0].win.close();
946 results[1].win.close();
947 done();
948 });
949 }
951 // related to Bug 671305
952 exports.testOnLoadEventWithDOM = function(assert, done) {
953 let count = 0;
954 let title = 'testOnLoadEventWithDOM';
956 // open a about: url
957 tabs.open({
958 url: 'data:text/html;charset=utf-8,<title>' + title + '</title>',
959 inBackground: true,
960 onLoad: function(tab) {
961 assert.equal(tab.title, title, 'tab passed in as arg, load called');
963 if (++count > 1) {
964 assert.pass('onLoad event called on reload');
965 tab.close(done);
966 }
967 else {
968 assert.pass('first onLoad event occured');
969 tab.reload();
970 }
971 }
972 });
973 };
975 // related to Bug 671305
976 exports.testOnLoadEventWithImage = function(assert, done) {
977 let count = 0;
979 tabs.open({
980 url: fixtures.url('Firefox.jpg'),
981 inBackground: true,
982 onLoad: function(tab) {
983 if (++count > 1) {
984 assert.pass('onLoad event called on reload with image');
985 tab.close(done);
986 }
987 else {
988 assert.pass('first onLoad event occured');
989 tab.reload();
990 }
991 }
992 });
993 };
995 exports.testFaviconGetterDeprecation = function (assert, done) {
996 setPref(DEPRECATE_PREF, true);
997 const { LoaderWithHookedConsole } = require("sdk/test/loader");
998 let { loader, messages } = LoaderWithHookedConsole(module);
999 let tabs = loader.require('sdk/tabs');
1001 tabs.open({
1002 url: 'data:text/html;charset=utf-8,',
1003 onOpen: function (tab) {
1004 let favicon = tab.favicon;
1005 assert.ok(messages.length === 1, 'only one error is dispatched');
1006 assert.ok(messages[0].type, 'error', 'the console message is an error');
1008 let msg = messages[0].msg;
1009 assert.ok(msg.indexOf('tab.favicon is deprecated') !== -1,
1010 'message contains the given message');
1011 tab.close(done);
1012 loader.unload();
1013 }
1014 });
1015 }
1017 /******************* helpers *********************/
1019 // Utility function to open a new browser window.
1020 function openBrowserWindow(callback, url) {
1021 let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
1022 getService(Ci.nsIWindowWatcher);
1023 let urlString = Cc["@mozilla.org/supports-string;1"].
1024 createInstance(Ci.nsISupportsString);
1025 urlString.data = url;
1026 let window = ww.openWindow(null, "chrome://browser/content/browser.xul",
1027 "_blank", "chrome,all,dialog=no", urlString);
1029 if (callback) {
1030 window.addEventListener("load", function onLoad(event) {
1031 if (event.target && event.target.defaultView == window) {
1032 window.removeEventListener("load", onLoad, true);
1033 let browsers = window.document.getElementsByTagName("tabbrowser");
1034 try {
1035 setTimeout(function () {
1036 callback(window, browsers[0]);
1037 }, 10);
1038 }
1039 catch (e) {
1040 console.exception(e);
1041 }
1042 }
1043 }, true);
1044 }
1046 return window;
1047 }
1049 require('sdk/test').run(exports);