addon-sdk/source/test/tabs/test-firefox-tabs.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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();
  1014   });
  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);
  1039         catch (e) {
  1040           console.exception(e);
  1043     }, true);
  1046   return window;
  1049 require('sdk/test').run(exports);

mercurial