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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/addon-sdk/source/test/tabs/test-firefox-tabs.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1049 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +'use strict';
     1.8 +
     1.9 +const { Cc, Ci } = require('chrome');
    1.10 +const { Loader } = require('sdk/test/loader');
    1.11 +const { setTimeout } = require('sdk/timers');
    1.12 +const { getOwnerWindow } = require('sdk/private-browsing/window/utils');
    1.13 +const { windows, onFocus, getMostRecentBrowserWindow } = require('sdk/window/utils');
    1.14 +const { open, focus, close } = require('sdk/window/helpers');
    1.15 +const tabs = require('sdk/tabs');
    1.16 +const { browserWindows } = require('sdk/windows');
    1.17 +const { set: setPref } = require("sdk/preferences/service");
    1.18 +const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
    1.19 +const fixtures = require("../fixtures");
    1.20 +
    1.21 +// Bug 682681 - tab.title should never be empty
    1.22 +exports.testBug682681_aboutURI = function(assert, done) {
    1.23 +  let url = 'chrome://browser/locale/tabbrowser.properties';
    1.24 +  let stringBundle = Cc["@mozilla.org/intl/stringbundle;1"].
    1.25 +                        getService(Ci.nsIStringBundleService).
    1.26 +                        createBundle(url);
    1.27 +  let emptyTabTitle = stringBundle.GetStringFromName('tabs.emptyTabTitle');
    1.28 +
    1.29 +  tabs.on('ready', function onReady(tab) {
    1.30 +    tabs.removeListener('ready', onReady);
    1.31 +
    1.32 +    assert.equal(tab.title,
    1.33 +                     emptyTabTitle,
    1.34 +                     "title of about: tab is not blank");
    1.35 +
    1.36 +    tab.close(done);
    1.37 +  });
    1.38 +
    1.39 +  // open a about: url
    1.40 +  tabs.open({
    1.41 +    url: "about:blank",
    1.42 +    inBackground: true
    1.43 +  });
    1.44 +};
    1.45 +
    1.46 +// related to Bug 682681
    1.47 +exports.testTitleForDataURI = function(assert, done) {
    1.48 +  tabs.open({
    1.49 +    url: "data:text/html;charset=utf-8,<title>tab</title>",
    1.50 +    inBackground: true,
    1.51 +    onReady: function(tab) {
    1.52 +      assert.equal(tab.title, "tab", "data: title is not Connecting...");
    1.53 +      tab.close(done);
    1.54 +    }
    1.55 +  });
    1.56 +};
    1.57 +
    1.58 +// TEST: 'BrowserWindow' instance creation on tab 'activate' event
    1.59 +// See bug 648244: there was a infinite loop.
    1.60 +exports.testBrowserWindowCreationOnActivate = function(assert, done) {
    1.61 +  let windows = require("sdk/windows").browserWindows;
    1.62 +  let gotActivate = false;
    1.63 +
    1.64 +  tabs.once('activate', function onActivate(eventTab) {
    1.65 +    assert.ok(windows.activeWindow, "Is able to fetch activeWindow");
    1.66 +    gotActivate = true;
    1.67 +  });
    1.68 +
    1.69 +  open().then(function(window) {
    1.70 +    assert.ok(gotActivate, "Received activate event");
    1.71 +    return close(window);
    1.72 +  }).then(done).then(null, assert.fail);
    1.73 +}
    1.74 +
    1.75 +// TEST: tab unloader
    1.76 +exports.testAutomaticDestroyEventOpen = function(assert, done) {
    1.77 +  let called = false;
    1.78 +  let loader = Loader(module);
    1.79 +  let tabs2 = loader.require("sdk/tabs");
    1.80 +  tabs2.on('open', _ => called = true);
    1.81 +
    1.82 +  // Fire a tab event and ensure that the destroyed tab is inactive
    1.83 +  tabs.once('open', tab => {
    1.84 +    setTimeout(_ => {
    1.85 +      assert.ok(!called, "Unloaded tab module is destroyed and inactive");
    1.86 +      tab.close(done);
    1.87 +    });
    1.88 +  });
    1.89 +
    1.90 +  loader.unload();
    1.91 +  tabs.open("data:text/html;charset=utf-8,testAutomaticDestroyEventOpen");
    1.92 +};
    1.93 +
    1.94 +exports.testAutomaticDestroyEventActivate = function(assert, done) {
    1.95 +  let called = false;
    1.96 +  let loader = Loader(module);
    1.97 +  let tabs2 = loader.require("sdk/tabs");
    1.98 +  tabs2.on('activate', _ => called = true);
    1.99 +
   1.100 +  // Fire a tab event and ensure that the destroyed tab is inactive
   1.101 +  tabs.once('activate', tab => {
   1.102 +    setTimeout(_ => {
   1.103 +      assert.ok(!called, "Unloaded tab module is destroyed and inactive");
   1.104 +      tab.close(done);
   1.105 +    });
   1.106 +  });
   1.107 +
   1.108 +  loader.unload();
   1.109 +  tabs.open("data:text/html;charset=utf-8,testAutomaticDestroyEventActivate");
   1.110 +};
   1.111 +
   1.112 +exports.testAutomaticDestroyEventDeactivate = function(assert, done) {
   1.113 +  let called = false;
   1.114 +  let currentTab = tabs.activeTab;
   1.115 +  let loader = Loader(module);
   1.116 +  let tabs2 = loader.require("sdk/tabs");
   1.117 +
   1.118 +  tabs.open({
   1.119 +    url: "data:text/html;charset=utf-8,testAutomaticDestroyEventDeactivate",
   1.120 +    onActivate: _ => setTimeout(_ => {
   1.121 +      tabs2.on('deactivate', _ => called = true);
   1.122 +
   1.123 +      // Fire a tab event and ensure that the destroyed tab is inactive
   1.124 +      tabs.once('deactivate', tab => {
   1.125 +        setTimeout(_ => {
   1.126 +          assert.ok(!called, "Unloaded tab module is destroyed and inactive");
   1.127 +          tab.close(done);
   1.128 +        });
   1.129 +      });
   1.130 +
   1.131 +      loader.unload();
   1.132 +      currentTab.activate();
   1.133 +    })
   1.134 +  });
   1.135 +};
   1.136 +
   1.137 +exports.testAutomaticDestroyEventClose = function(assert, done) {
   1.138 +  let called = false;
   1.139 +  let loader = Loader(module);
   1.140 +  let tabs2 = loader.require("sdk/tabs");
   1.141 +
   1.142 +  tabs.open({
   1.143 +    url: "data:text/html;charset=utf-8,testAutomaticDestroyEventClose",
   1.144 +    onReady: tab => {
   1.145 +      tabs2.on('close', _ => called = true);
   1.146 +
   1.147 +      // Fire a tab event and ensure that the destroyed tab is inactive
   1.148 +      tabs.once('close', tab => {
   1.149 +        setTimeout(_ => {
   1.150 +          assert.ok(!called, "Unloaded tab module is destroyed and inactive");
   1.151 +          done();
   1.152 +        });
   1.153 +      });
   1.154 +
   1.155 +      loader.unload();
   1.156 +      tab.close();
   1.157 +    }
   1.158 +  });
   1.159 +};
   1.160 +
   1.161 +exports.testTabPropertiesInNewWindow = function(assert, done) {
   1.162 +  let warning = "DEPRECATED: tab.favicon is deprecated, please use require(\"sdk/places/favicon\").getFavicon instead.\n"
   1.163 +  const { LoaderWithFilteredConsole } = require("sdk/test/loader");
   1.164 +  let loader = LoaderWithFilteredConsole(module, function(type, message) {
   1.165 +    if (type == "error" && message.substring(0, warning.length) == warning)
   1.166 +      return false;
   1.167 +    return true;
   1.168 +  });
   1.169 +
   1.170 +  let tabs = loader.require('sdk/tabs');
   1.171 +  let { getOwnerWindow } = loader.require('sdk/private-browsing/window/utils');
   1.172 +
   1.173 +  let count = 0;
   1.174 +  function onReadyOrLoad (tab) {
   1.175 +    if (count++) {
   1.176 +      close(getOwnerWindow(tab)).then(done).then(null, assert.fail);
   1.177 +    }
   1.178 +  }
   1.179 +
   1.180 +  let url = "data:text/html;charset=utf-8,<html><head><title>foo</title></head><body>foo</body></html>";
   1.181 +  tabs.open({
   1.182 +    inNewWindow: true,
   1.183 +    url: url,
   1.184 +    onReady: function(tab) {
   1.185 +      assert.equal(tab.title, "foo", "title of the new tab matches");
   1.186 +      assert.equal(tab.url, url, "URL of the new tab matches");
   1.187 +      assert.ok(tab.favicon, "favicon of the new tab is not empty");
   1.188 +      assert.equal(tab.style, null, "style of the new tab matches");
   1.189 +      assert.equal(tab.index, 0, "index of the new tab matches");
   1.190 +      assert.notEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
   1.191 +      assert.notEqual(tab.id, null, "a tab object always has an id property.");
   1.192 +
   1.193 +      onReadyOrLoad(tab);
   1.194 +    },
   1.195 +    onLoad: function(tab) {
   1.196 +      assert.equal(tab.title, "foo", "title of the new tab matches");
   1.197 +      assert.equal(tab.url, url, "URL of the new tab matches");
   1.198 +      assert.ok(tab.favicon, "favicon of the new tab is not empty");
   1.199 +      assert.equal(tab.style, null, "style of the new tab matches");
   1.200 +      assert.equal(tab.index, 0, "index of the new tab matches");
   1.201 +      assert.notEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
   1.202 +      assert.notEqual(tab.id, null, "a tab object always has an id property.");
   1.203 +
   1.204 +      onReadyOrLoad(tab);
   1.205 +    }
   1.206 +  });
   1.207 +};
   1.208 +
   1.209 +exports.testTabPropertiesInSameWindow = function(assert, done) {
   1.210 +  let warning = "DEPRECATED: tab.favicon is deprecated, please use require(\"sdk/places/favicon\").getFavicon instead.\n"
   1.211 +  const { LoaderWithFilteredConsole } = require("sdk/test/loader");
   1.212 +  let loader = LoaderWithFilteredConsole(module, function(type, message) {
   1.213 +    if (type == "error" && message.substring(0, warning.length) == warning)
   1.214 +      return false;
   1.215 +    return true;
   1.216 +  });
   1.217 +
   1.218 +  let tabs = loader.require('sdk/tabs');
   1.219 +
   1.220 +  // Get current count of tabs so we know the index of the
   1.221 +  // new tab, bug 893846
   1.222 +  let tabCount = tabs.length;
   1.223 +  let count = 0;
   1.224 +  function onReadyOrLoad (tab) {
   1.225 +    if (count++) {
   1.226 +      tab.close(done);
   1.227 +    }
   1.228 +  }
   1.229 +
   1.230 +  let url = "data:text/html;charset=utf-8,<html><head><title>foo</title></head><body>foo</body></html>";
   1.231 +  tabs.open({
   1.232 +    url: url,
   1.233 +    onReady: function(tab) {
   1.234 +      assert.equal(tab.title, "foo", "title of the new tab matches");
   1.235 +      assert.equal(tab.url, url, "URL of the new tab matches");
   1.236 +      assert.ok(tab.favicon, "favicon of the new tab is not empty");
   1.237 +      assert.equal(tab.style, null, "style of the new tab matches");
   1.238 +      assert.equal(tab.index, tabCount, "index of the new tab matches");
   1.239 +      assert.notEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
   1.240 +      assert.notEqual(tab.id, null, "a tab object always has an id property.");
   1.241 +
   1.242 +      onReadyOrLoad(tab);
   1.243 +    },
   1.244 +    onLoad: function(tab) {
   1.245 +      assert.equal(tab.title, "foo", "title of the new tab matches");
   1.246 +      assert.equal(tab.url, url, "URL of the new tab matches");
   1.247 +      assert.ok(tab.favicon, "favicon of the new tab is not empty");
   1.248 +      assert.equal(tab.style, null, "style of the new tab matches");
   1.249 +      assert.equal(tab.index, tabCount, "index of the new tab matches");
   1.250 +      assert.notEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
   1.251 +      assert.notEqual(tab.id, null, "a tab object always has an id property.");
   1.252 +
   1.253 +      onReadyOrLoad(tab);
   1.254 +    }
   1.255 +  });
   1.256 +};
   1.257 +
   1.258 +// TEST: tab properties
   1.259 +exports.testTabContentTypeAndReload = function(assert, done) {
   1.260 +  open().then(focus).then(function(window) {
   1.261 +    let url = "data:text/html;charset=utf-8,<html><head><title>foo</title></head><body>foo</body></html>";
   1.262 +    let urlXML = "data:text/xml;charset=utf-8,<foo>bar</foo>";
   1.263 +    tabs.open({
   1.264 +      url: url,
   1.265 +      onReady: function(tab) {
   1.266 +        if (tab.url === url) {
   1.267 +          assert.equal(tab.contentType, "text/html");
   1.268 +          tab.url = urlXML;
   1.269 +        }
   1.270 +        else {
   1.271 +          assert.equal(tab.contentType, "text/xml");
   1.272 +          close(window).then(done).then(null, assert.fail);
   1.273 +        }
   1.274 +      }
   1.275 +    });
   1.276 +  });
   1.277 +};
   1.278 +
   1.279 +// TEST: tabs iterator and length property
   1.280 +exports.testTabsIteratorAndLength = function(assert, done) {
   1.281 +  open(null, { features: { chrome: true, toolbar: true } }).then(focus).then(function(window) {
   1.282 +    let startCount = 0;
   1.283 +    for each (let t in tabs) startCount++;
   1.284 +    assert.equal(startCount, tabs.length, "length property is correct");
   1.285 +    let url = "data:text/html;charset=utf-8,default";
   1.286 +
   1.287 +    tabs.open(url);
   1.288 +    tabs.open(url);
   1.289 +    tabs.open({
   1.290 +      url: url,
   1.291 +      onOpen: function(tab) {
   1.292 +        let count = 0;
   1.293 +        for each (let t in tabs) count++;
   1.294 +        assert.equal(count, startCount + 3, "iterated tab count matches");
   1.295 +        assert.equal(startCount + 3, tabs.length, "iterated tab count matches length property");
   1.296 +
   1.297 +        close(window).then(done).then(null, assert.fail);
   1.298 +      }
   1.299 +    });
   1.300 +  });
   1.301 +};
   1.302 +
   1.303 +// TEST: tab.url setter
   1.304 +exports.testTabLocation = function(assert, done) {
   1.305 +  open().then(focus).then(function(window) {
   1.306 +    let url1 = "data:text/html;charset=utf-8,foo";
   1.307 +    let url2 = "data:text/html;charset=utf-8,bar";
   1.308 +
   1.309 +    tabs.on('ready', function onReady(tab) {
   1.310 +      if (tab.url != url2)
   1.311 +        return;
   1.312 +      tabs.removeListener('ready', onReady);
   1.313 +      assert.pass("tab.load() loaded the correct url");
   1.314 +      close(window).then(done).then(null, assert.fail);
   1.315 +    });
   1.316 +
   1.317 +    tabs.open({
   1.318 +      url: url1,
   1.319 +      onOpen: function(tab) {
   1.320 +        tab.url = url2
   1.321 +      }
   1.322 +    });
   1.323 +  });
   1.324 +};
   1.325 +
   1.326 +// TEST: tab.close()
   1.327 +exports.testTabClose = function(assert, done) {
   1.328 +  let testName = "testTabClose";
   1.329 +  let url = "data:text/html;charset=utf-8," + testName;
   1.330 +
   1.331 +  assert.notEqual(tabs.activeTab.url, url, "tab is not the active tab");
   1.332 +  tabs.once('ready', function onReady(tab) {
   1.333 +    assert.equal(tabs.activeTab.url, tab.url, "tab is now the active tab");
   1.334 +    assert.equal(url, tab.url, "tab url is the test url");
   1.335 +    let secondOnCloseCalled = false;
   1.336 +
   1.337 +    // Bug 699450: Multiple calls to tab.close should not throw
   1.338 +    tab.close(function() secondOnCloseCalled = true);
   1.339 +    try {
   1.340 +      tab.close(function () {
   1.341 +        assert.notEqual(tabs.activeTab.url, url, "tab is no longer the active tab");
   1.342 +        assert.ok(secondOnCloseCalled,
   1.343 +          "The immediate second call to tab.close happened");
   1.344 +        assert.notEqual(tabs.activeTab.url, url, "tab is no longer the active tab");
   1.345 +
   1.346 +        done();
   1.347 +      });
   1.348 +    }
   1.349 +    catch(e) {
   1.350 +      assert.fail("second call to tab.close() thrown an exception: " + e);
   1.351 +    }
   1.352 +  });
   1.353 +
   1.354 +  tabs.open(url);
   1.355 +};
   1.356 +
   1.357 +// TEST: tab.move()
   1.358 +exports.testTabMove = function(assert, done) {
   1.359 +  open().then(focus).then(function(window) {
   1.360 +    let url = "data:text/html;charset=utf-8,foo";
   1.361 +
   1.362 +    tabs.open({
   1.363 +      url: url,
   1.364 +      onOpen: function(tab) {
   1.365 +        assert.equal(tab.index, 1, "tab index before move matches");
   1.366 +        tab.index = 0;
   1.367 +        assert.equal(tab.index, 0, "tab index after move matches");
   1.368 +        close(window).then(done).then(null, assert.fail);
   1.369 +      }
   1.370 +    });
   1.371 +  }).then(null, assert.fail);
   1.372 +};
   1.373 +
   1.374 +// TEST: open tab with default options
   1.375 +exports.testOpen = function(assert, done) {
   1.376 +  let url = "data:text/html;charset=utf-8,default";
   1.377 +  tabs.open({
   1.378 +    url: url,
   1.379 +    onReady: function(tab) {
   1.380 +      assert.equal(tab.url, url, "URL of the new tab matches");
   1.381 +      assert.equal(tab.isPinned, false, "The new tab is not pinned");
   1.382 +
   1.383 +      tab.close(done);
   1.384 +    }
   1.385 +  });
   1.386 +};
   1.387 +
   1.388 +// TEST: opening a pinned tab
   1.389 +exports.testOpenPinned = function(assert, done) {
   1.390 +  let url = "data:text/html;charset=utf-8,default";
   1.391 +  tabs.open({
   1.392 +    url: url,
   1.393 +    isPinned: true,
   1.394 +    onOpen: function(tab) {
   1.395 +      assert.equal(tab.isPinned, true, "The new tab is pinned");
   1.396 +      tab.close(done);
   1.397 +    }
   1.398 +  });
   1.399 +};
   1.400 +
   1.401 +// TEST: pin/unpin opened tab
   1.402 +exports.testPinUnpin = function(assert, done) {
   1.403 +  let url = "data:text/html;charset=utf-8,default";
   1.404 +  tabs.open({
   1.405 +    url: url,
   1.406 +    inBackground: true,
   1.407 +    onOpen: function(tab) {
   1.408 +      tab.pin();
   1.409 +      assert.equal(tab.isPinned, true, "The tab was pinned correctly");
   1.410 +      tab.unpin();
   1.411 +      assert.equal(tab.isPinned, false, "The tab was unpinned correctly");
   1.412 +      tab.close(done);
   1.413 +    }
   1.414 +  });
   1.415 +}
   1.416 +
   1.417 +// TEST: open tab in background
   1.418 +exports.testInBackground = function(assert, done) {
   1.419 +  let window = getMostRecentBrowserWindow();
   1.420 +  let activeUrl = tabs.activeTab.url;
   1.421 +  let url = "data:text/html;charset=utf-8,background";
   1.422 +  assert.equal(getMostRecentBrowserWindow(), window, "getMostRecentBrowserWindow() matches this window");
   1.423 +  tabs.on('ready', function onReady(tab) {
   1.424 +    tabs.removeListener('ready', onReady);
   1.425 +    assert.equal(tabs.activeTab.url, activeUrl, "URL of active tab has not changed");
   1.426 +    assert.equal(tab.url, url, "URL of the new background tab matches");
   1.427 +    assert.equal(getMostRecentBrowserWindow(), window, "a new window was not opened");
   1.428 +    assert.notEqual(tabs.activeTab.url, url, "URL of active tab is not the new URL");
   1.429 +    tab.close(done);
   1.430 +  });
   1.431 +
   1.432 +  tabs.open({
   1.433 +    url: url,
   1.434 +    inBackground: true
   1.435 +  });
   1.436 +}
   1.437 +
   1.438 +// TEST: open tab in new window
   1.439 +exports.testOpenInNewWindow = function(assert, done) {
   1.440 +  let startWindowCount = windows().length;
   1.441 +
   1.442 +  let url = "data:text/html;charset=utf-8,testOpenInNewWindow";
   1.443 +  tabs.open({
   1.444 +    url: url,
   1.445 +    inNewWindow: true,
   1.446 +    onReady: function(tab) {
   1.447 +      let newWindow = getOwnerWindow(tab);
   1.448 +      assert.equal(windows().length, startWindowCount + 1, "a new window was opened");
   1.449 +
   1.450 +      onFocus(newWindow).then(function() {
   1.451 +        assert.equal(getMostRecentBrowserWindow(), newWindow, "new window is active");
   1.452 +        assert.equal(tab.url, url, "URL of the new tab matches");
   1.453 +        assert.equal(newWindow.content.location, url, "URL of new tab in new window matches");
   1.454 +        assert.equal(tabs.activeTab.url, url, "URL of activeTab matches");
   1.455 +
   1.456 +        return close(newWindow).then(done);
   1.457 +      }).then(null, assert.fail);
   1.458 +    }
   1.459 +  });
   1.460 +
   1.461 +}
   1.462 +
   1.463 +// Test tab.open inNewWindow + onOpen combination
   1.464 +exports.testOpenInNewWindowOnOpen = function(assert, done) {
   1.465 +  let startWindowCount = windows().length;
   1.466 +
   1.467 +  let url = "data:text/html;charset=utf-8,newwindow";
   1.468 +  tabs.open({
   1.469 +    url: url,
   1.470 +    inNewWindow: true,
   1.471 +    onOpen: function(tab) {
   1.472 +      let newWindow = getOwnerWindow(tab);
   1.473 +
   1.474 +      onFocus(newWindow).then(function() {
   1.475 +        assert.equal(windows().length, startWindowCount + 1, "a new window was opened");
   1.476 +        assert.equal(getMostRecentBrowserWindow(), newWindow, "new window is active");
   1.477 +
   1.478 +        close(newWindow).then(done).then(null, assert.fail);
   1.479 +      });
   1.480 +    }
   1.481 +  });
   1.482 +};
   1.483 +
   1.484 +// TEST: onOpen event handler
   1.485 +exports.testTabsEvent_onOpen = function(assert, done) {
   1.486 +  open().then(focus).then(window => {
   1.487 +    let url = "data:text/html;charset=utf-8,1";
   1.488 +    let eventCount = 0;
   1.489 +
   1.490 +    // add listener via property assignment
   1.491 +    function listener1(tab) {
   1.492 +      eventCount++;
   1.493 +    };
   1.494 +    tabs.on('open', listener1);
   1.495 +
   1.496 +    // add listener via collection add
   1.497 +    tabs.on('open', function listener2(tab) {
   1.498 +      assert.equal(++eventCount, 2, "both listeners notified");
   1.499 +      tabs.removeListener('open', listener1);
   1.500 +      tabs.removeListener('open', listener2);
   1.501 +      close(window).then(done).then(null, assert.fail);
   1.502 +    });
   1.503 +
   1.504 +    tabs.open(url);
   1.505 +  }).then(null, assert.fail);
   1.506 +};
   1.507 +
   1.508 +// TEST: onClose event handler
   1.509 +exports.testTabsEvent_onClose = function(assert, done) {
   1.510 +  open().then(focus).then(window => {
   1.511 +    let url = "data:text/html;charset=utf-8,onclose";
   1.512 +    let eventCount = 0;
   1.513 +
   1.514 +    // add listener via property assignment
   1.515 +    function listener1(tab) {
   1.516 +      eventCount++;
   1.517 +    }
   1.518 +    tabs.on('close', listener1);
   1.519 +
   1.520 +    // add listener via collection add
   1.521 +    tabs.on('close', function listener2(tab) {
   1.522 +      assert.equal(++eventCount, 2, "both listeners notified");
   1.523 +      tabs.removeListener('close', listener1);
   1.524 +      tabs.removeListener('close', listener2);
   1.525 +      close(window).then(done).then(null, assert.fail);
   1.526 +    });
   1.527 +
   1.528 +    tabs.on('ready', function onReady(tab) {
   1.529 +      tabs.removeListener('ready', onReady);
   1.530 +      tab.close();
   1.531 +    });
   1.532 +
   1.533 +    tabs.open(url);
   1.534 +  }).then(null, assert.fail);
   1.535 +};
   1.536 +
   1.537 +// TEST: onClose event handler when a window is closed
   1.538 +exports.testTabsEvent_onCloseWindow = function(assert, done) {
   1.539 +  let closeCount = 0;
   1.540 +  let individualCloseCount = 0;
   1.541 +
   1.542 +  open().then(focus).then(window => {
   1.543 +    assert.pass('opened a new window');
   1.544 +
   1.545 +    tabs.on("close", function listener() {
   1.546 +      if (++closeCount == 4) {
   1.547 +        tabs.removeListener("close", listener);
   1.548 +      }
   1.549 +    });
   1.550 +
   1.551 +    function endTest() {
   1.552 +      if (++individualCloseCount < 3) {
   1.553 +        assert.pass('tab closed ' + individualCloseCount);
   1.554 +        return;
   1.555 +      }
   1.556 +
   1.557 +      assert.equal(closeCount, 4, "Correct number of close events received");
   1.558 +      assert.equal(individualCloseCount, 3,
   1.559 +                   "Each tab with an attached onClose listener received a close " +
   1.560 +                   "event when the window was closed");
   1.561 +
   1.562 +      done();
   1.563 +    }
   1.564 +
   1.565 +    // One tab is already open with the window
   1.566 +    let openTabs = 1;
   1.567 +    function testCasePossiblyLoaded() {
   1.568 +      if (++openTabs == 4) {
   1.569 +        window.close();
   1.570 +      }
   1.571 +      assert.pass('tab opened ' + openTabs);
   1.572 +    }
   1.573 +
   1.574 +    tabs.open({
   1.575 +      url: "data:text/html;charset=utf-8,tab2",
   1.576 +      onOpen: testCasePossiblyLoaded,
   1.577 +      onClose: endTest
   1.578 +    });
   1.579 +
   1.580 +    tabs.open({
   1.581 +      url: "data:text/html;charset=utf-8,tab3",
   1.582 +      onOpen: testCasePossiblyLoaded,
   1.583 +      onClose: endTest
   1.584 +    });
   1.585 +
   1.586 +    tabs.open({
   1.587 +      url: "data:text/html;charset=utf-8,tab4",
   1.588 +      onOpen: testCasePossiblyLoaded,
   1.589 +      onClose: endTest
   1.590 +    });
   1.591 +  }).then(null, assert.fail);
   1.592 +}
   1.593 +
   1.594 +// TEST: onReady event handler
   1.595 +exports.testTabsEvent_onReady = function(assert, done) {
   1.596 +  open().then(focus).then(window => {
   1.597 +    let url = "data:text/html;charset=utf-8,onready";
   1.598 +    let eventCount = 0;
   1.599 +
   1.600 +    // add listener via property assignment
   1.601 +    function listener1(tab) {
   1.602 +      eventCount++;
   1.603 +    };
   1.604 +    tabs.on('ready', listener1);
   1.605 +
   1.606 +    // add listener via collection add
   1.607 +    tabs.on('ready', function listener2(tab) {
   1.608 +      assert.equal(++eventCount, 2, "both listeners notified");
   1.609 +      tabs.removeListener('ready', listener1);
   1.610 +      tabs.removeListener('ready', listener2);
   1.611 +      close(window).then(done);
   1.612 +    });
   1.613 +
   1.614 +    tabs.open(url);
   1.615 +  }).then(null, assert.fail);
   1.616 +};
   1.617 +
   1.618 +// TEST: onActivate event handler
   1.619 +exports.testTabsEvent_onActivate = function(assert, done) {
   1.620 +  open().then(focus).then(window => {
   1.621 +    let url = "data:text/html;charset=utf-8,onactivate";
   1.622 +    let eventCount = 0;
   1.623 +
   1.624 +    // add listener via property assignment
   1.625 +    function listener1(tab) {
   1.626 +      eventCount++;
   1.627 +    };
   1.628 +    tabs.on('activate', listener1);
   1.629 +
   1.630 +    // add listener via collection add
   1.631 +    tabs.on('activate', function listener2(tab) {
   1.632 +      assert.equal(++eventCount, 2, "both listeners notified");
   1.633 +      tabs.removeListener('activate', listener1);
   1.634 +      tabs.removeListener('activate', listener2);
   1.635 +      close(window).then(done).then(null, assert.fail);
   1.636 +    });
   1.637 +
   1.638 +    tabs.open(url);
   1.639 +  }).then(null, assert.fail);
   1.640 +};
   1.641 +
   1.642 +// onDeactivate event handler
   1.643 +exports.testTabsEvent_onDeactivate = function(assert, done) {
   1.644 +  open().then(focus).then(window => {
   1.645 +    let url = "data:text/html;charset=utf-8,ondeactivate";
   1.646 +    let eventCount = 0;
   1.647 +
   1.648 +    // add listener via property assignment
   1.649 +    function listener1(tab) {
   1.650 +      eventCount++;
   1.651 +    };
   1.652 +    tabs.on('deactivate', listener1);
   1.653 +
   1.654 +    // add listener via collection add
   1.655 +    tabs.on('deactivate', function listener2(tab) {
   1.656 +      assert.equal(++eventCount, 2, "both listeners notified");
   1.657 +      tabs.removeListener('deactivate', listener1);
   1.658 +      tabs.removeListener('deactivate', listener2);
   1.659 +      close(window).then(done).then(null, assert.fail);
   1.660 +    });
   1.661 +
   1.662 +    tabs.on('open', function onOpen(tab) {
   1.663 +      tabs.removeListener('open', onOpen);
   1.664 +      tabs.open("data:text/html;charset=utf-8,foo");
   1.665 +    });
   1.666 +
   1.667 +    tabs.open(url);
   1.668 +  }).then(null, assert.fail);
   1.669 +};
   1.670 +
   1.671 +// pinning
   1.672 +exports.testTabsEvent_pinning = function(assert, done) {
   1.673 +  open().then(focus).then(window => {
   1.674 +    let url = "data:text/html;charset=utf-8,1";
   1.675 +
   1.676 +    tabs.on('open', function onOpen(tab) {
   1.677 +      tabs.removeListener('open', onOpen);
   1.678 +      tab.pin();
   1.679 +    });
   1.680 +
   1.681 +    tabs.on('pinned', function onPinned(tab) {
   1.682 +      tabs.removeListener('pinned', onPinned);
   1.683 +      assert.ok(tab.isPinned, "notified tab is pinned");
   1.684 +      tab.unpin();
   1.685 +    });
   1.686 +
   1.687 +    tabs.on('unpinned', function onUnpinned(tab) {
   1.688 +      tabs.removeListener('unpinned', onUnpinned);
   1.689 +      assert.ok(!tab.isPinned, "notified tab is not pinned");
   1.690 +      close(window).then(done).then(null, assert.fail);
   1.691 +    });
   1.692 +
   1.693 +    tabs.open(url);
   1.694 +  }).then(null, assert.fail);
   1.695 +};
   1.696 +
   1.697 +// TEST: per-tab event handlers
   1.698 +exports.testPerTabEvents = function(assert, done) {
   1.699 +  open().then(focus).then(window => {
   1.700 +    let eventCount = 0;
   1.701 +
   1.702 +    tabs.open({
   1.703 +      url: "data:text/html;charset=utf-8,foo",
   1.704 +      onOpen: function(tab) {
   1.705 +        // add listener via property assignment
   1.706 +        function listener1() {
   1.707 +          eventCount++;
   1.708 +        };
   1.709 +        tab.on('ready', listener1);
   1.710 +
   1.711 +        // add listener via collection add
   1.712 +        tab.on('ready', function listener2() {
   1.713 +          assert.equal(eventCount, 1, "both listeners notified");
   1.714 +          tab.removeListener('ready', listener1);
   1.715 +          tab.removeListener('ready', listener2);
   1.716 +          close(window).then(done).then(null, assert.fail);
   1.717 +        });
   1.718 +      }
   1.719 +    });
   1.720 +  }).then(null, assert.fail);
   1.721 +};
   1.722 +
   1.723 +exports.testAttachOnOpen = function (assert, done) {
   1.724 +  // Take care that attach has to be called on tab ready and not on tab open.
   1.725 +  open().then(focus).then(window => {
   1.726 +    tabs.open({
   1.727 +      url: "data:text/html;charset=utf-8,foobar",
   1.728 +      onOpen: function (tab) {
   1.729 +        let worker = tab.attach({
   1.730 +          contentScript: 'self.postMessage(document.location.href); ',
   1.731 +          onMessage: function (msg) {
   1.732 +            assert.equal(msg, "about:blank",
   1.733 +              "Worker document url is about:blank on open");
   1.734 +            worker.destroy();
   1.735 +            close(window).then(done).then(null, assert.fail);
   1.736 +          }
   1.737 +        });
   1.738 +      }
   1.739 +    });
   1.740 +  }).then(null, assert.fail);
   1.741 +}
   1.742 +
   1.743 +exports.testAttachOnMultipleDocuments = function (assert, done) {
   1.744 +  // Example of attach that process multiple tab documents
   1.745 +  open().then(focus).then(window => {
   1.746 +    let firstLocation = "data:text/html;charset=utf-8,foobar";
   1.747 +    let secondLocation = "data:text/html;charset=utf-8,bar";
   1.748 +    let thirdLocation = "data:text/html;charset=utf-8,fox";
   1.749 +    let onReadyCount = 0;
   1.750 +    let worker1 = null;
   1.751 +    let worker2 = null;
   1.752 +    let detachEventCount = 0;
   1.753 +
   1.754 +    tabs.open({
   1.755 +      url: firstLocation,
   1.756 +      onReady: function (tab) {
   1.757 +        onReadyCount++;
   1.758 +        if (onReadyCount == 1) {
   1.759 +          worker1 = tab.attach({
   1.760 +            contentScript: 'self.on("message", ' +
   1.761 +                           '  function () self.postMessage(document.location.href)' +
   1.762 +                           ');',
   1.763 +            onMessage: function (msg) {
   1.764 +              assert.equal(msg, firstLocation,
   1.765 +                               "Worker url is equal to the 1st document");
   1.766 +              tab.url = secondLocation;
   1.767 +            },
   1.768 +            onDetach: function () {
   1.769 +              detachEventCount++;
   1.770 +              assert.pass("Got worker1 detach event");
   1.771 +              assert.throws(function () {
   1.772 +                  worker1.postMessage("ex-1");
   1.773 +                },
   1.774 +                /Couldn't find the worker/,
   1.775 +                "postMessage throw because worker1 is destroyed");
   1.776 +              checkEnd();
   1.777 +            }
   1.778 +          });
   1.779 +          worker1.postMessage("new-doc-1");
   1.780 +        }
   1.781 +        else if (onReadyCount == 2) {
   1.782 +
   1.783 +          worker2 = tab.attach({
   1.784 +            contentScript: 'self.on("message", ' +
   1.785 +                           '  function () self.postMessage(document.location.href)' +
   1.786 +                           ');',
   1.787 +            onMessage: function (msg) {
   1.788 +              assert.equal(msg, secondLocation,
   1.789 +                               "Worker url is equal to the 2nd document");
   1.790 +              tab.url = thirdLocation;
   1.791 +            },
   1.792 +            onDetach: function () {
   1.793 +              detachEventCount++;
   1.794 +              assert.pass("Got worker2 detach event");
   1.795 +              assert.throws(function () {
   1.796 +                  worker2.postMessage("ex-2");
   1.797 +                },
   1.798 +                /Couldn't find the worker/,
   1.799 +                "postMessage throw because worker2 is destroyed");
   1.800 +              checkEnd();
   1.801 +            }
   1.802 +          });
   1.803 +          worker2.postMessage("new-doc-2");
   1.804 +        }
   1.805 +        else if (onReadyCount == 3) {
   1.806 +          tab.close();
   1.807 +        }
   1.808 +      }
   1.809 +    });
   1.810 +
   1.811 +    function checkEnd() {
   1.812 +      if (detachEventCount != 2)
   1.813 +        return;
   1.814 +
   1.815 +      assert.pass("Got all detach events");
   1.816 +
   1.817 +      close(window).then(done).then(null, assert.fail);
   1.818 +    }
   1.819 +  }).then(null, assert.fail);
   1.820 +}
   1.821 +
   1.822 +
   1.823 +exports.testAttachWrappers = function (assert, done) {
   1.824 +  // Check that content script has access to wrapped values by default
   1.825 +  open().then(focus).then(window => {
   1.826 +    let document = "data:text/html;charset=utf-8,<script>var globalJSVar = true; " +
   1.827 +                   "                       document.getElementById = 3;</script>";
   1.828 +    let count = 0;
   1.829 +
   1.830 +    tabs.open({
   1.831 +      url: document,
   1.832 +      onReady: function (tab) {
   1.833 +        let worker = tab.attach({
   1.834 +          contentScript: 'try {' +
   1.835 +                         '  self.postMessage(!("globalJSVar" in window));' +
   1.836 +                         '  self.postMessage(typeof window.globalJSVar == "undefined");' +
   1.837 +                         '} catch(e) {' +
   1.838 +                         '  self.postMessage(e.message);' +
   1.839 +                         '}',
   1.840 +          onMessage: function (msg) {
   1.841 +            assert.equal(msg, true, "Worker has wrapped objects ("+count+")");
   1.842 +            if (count++ == 1)
   1.843 +              close(window).then(done).then(null, assert.fail);
   1.844 +          }
   1.845 +        });
   1.846 +      }
   1.847 +    });
   1.848 +  }).then(null, assert.fail);
   1.849 +}
   1.850 +
   1.851 +/*
   1.852 +// We do not offer unwrapped access to DOM since bug 601295 landed
   1.853 +// See 660780 to track progress of unwrap feature
   1.854 +exports.testAttachUnwrapped = function (assert, done) {
   1.855 +  // Check that content script has access to unwrapped values through unsafeWindow
   1.856 +  openBrowserWindow(function(window, browser) {
   1.857 +    let document = "data:text/html;charset=utf-8,<script>var globalJSVar=true;</script>";
   1.858 +    let count = 0;
   1.859 +
   1.860 +    tabs.open({
   1.861 +      url: document,
   1.862 +      onReady: function (tab) {
   1.863 +        let worker = tab.attach({
   1.864 +          contentScript: 'try {' +
   1.865 +                         '  self.postMessage(unsafeWindow.globalJSVar);' +
   1.866 +                         '} catch(e) {' +
   1.867 +                         '  self.postMessage(e.message);' +
   1.868 +                         '}',
   1.869 +          onMessage: function (msg) {
   1.870 +            assert.equal(msg, true, "Worker has access to javascript content globals ("+count+")");
   1.871 +            close(window).then(done);
   1.872 +          }
   1.873 +        });
   1.874 +      }
   1.875 +    });
   1.876 +
   1.877 +  });
   1.878 +}
   1.879 +*/
   1.880 +
   1.881 +exports['test window focus changes active tab'] = function(assert, done) {
   1.882 +  let url1 = "data:text/html;charset=utf-8," + encodeURIComponent("test window focus changes active tab</br><h1>Window #1");
   1.883 +
   1.884 +  let win1 = openBrowserWindow(function() {
   1.885 +    assert.pass("window 1 is open");
   1.886 +
   1.887 +    let win2 = openBrowserWindow(function() {
   1.888 +      assert.pass("window 2 is open");
   1.889 +
   1.890 +      focus(win2).then(function() {
   1.891 +        tabs.on("activate", function onActivate(tab) {
   1.892 +          tabs.removeListener("activate", onActivate);
   1.893 +          assert.pass("activate was called on windows focus change.");
   1.894 +          assert.equal(tab.url, url1, 'the activated tab url is correct');
   1.895 +
   1.896 +          return close(win2).then(function() {
   1.897 +            assert.pass('window 2 was closed');
   1.898 +            return close(win1);
   1.899 +          }).then(done).then(null, assert.fail);
   1.900 +        });
   1.901 +
   1.902 +        win1.focus();
   1.903 +      });
   1.904 +    }, "data:text/html;charset=utf-8,test window focus changes active tab</br><h1>Window #2");
   1.905 +  }, url1);
   1.906 +};
   1.907 +
   1.908 +exports['test ready event on new window tab'] = function(assert, done) {
   1.909 +  let uri = encodeURI("data:text/html;charset=utf-8,Waiting for ready event!");
   1.910 +
   1.911 +  require("sdk/tabs").on("ready", function onReady(tab) {
   1.912 +    if (tab.url === uri) {
   1.913 +      require("sdk/tabs").removeListener("ready", onReady);
   1.914 +      assert.pass("ready event was emitted");
   1.915 +      close(window).then(done).then(null, assert.fail);
   1.916 +    }
   1.917 +  });
   1.918 +
   1.919 +  let window = openBrowserWindow(function(){}, uri);
   1.920 +};
   1.921 +
   1.922 +exports['test unique tab ids'] = function(assert, done) {
   1.923 +  var windows = require('sdk/windows').browserWindows;
   1.924 +  var { all, defer } = require('sdk/core/promise');
   1.925 +
   1.926 +  function openWindow() {
   1.927 +    let deferred = defer();
   1.928 +    let win = windows.open({
   1.929 +      url: "data:text/html;charset=utf-8,<html>foo</html>",
   1.930 +    });
   1.931 +
   1.932 +    win.on('open', function(window) {
   1.933 +      assert.ok(window.tabs.length);
   1.934 +      assert.ok(window.tabs.activeTab);
   1.935 +      assert.ok(window.tabs.activeTab.id);
   1.936 +      deferred.resolve({
   1.937 +        id: window.tabs.activeTab.id,
   1.938 +        win: win
   1.939 +      });
   1.940 +    });
   1.941 +
   1.942 +    return deferred.promise;
   1.943 +  }
   1.944 +
   1.945 +  var one = openWindow(), two = openWindow();
   1.946 +  all([one, two]).then(function(results) {
   1.947 +    assert.notEqual(results[0].id, results[1].id, "tab Ids should not be equal.");
   1.948 +    results[0].win.close();
   1.949 +    results[1].win.close();
   1.950 +    done();
   1.951 +  });
   1.952 +}
   1.953 +
   1.954 +// related to Bug 671305
   1.955 +exports.testOnLoadEventWithDOM = function(assert, done) {
   1.956 +  let count = 0;
   1.957 +  let title = 'testOnLoadEventWithDOM';
   1.958 +
   1.959 +  // open a about: url
   1.960 +  tabs.open({
   1.961 +    url: 'data:text/html;charset=utf-8,<title>' + title + '</title>',
   1.962 +    inBackground: true,
   1.963 +    onLoad: function(tab) {
   1.964 +      assert.equal(tab.title, title, 'tab passed in as arg, load called');
   1.965 +
   1.966 +      if (++count > 1) {
   1.967 +        assert.pass('onLoad event called on reload');
   1.968 +        tab.close(done);
   1.969 +      }
   1.970 +      else {
   1.971 +        assert.pass('first onLoad event occured');
   1.972 +        tab.reload();
   1.973 +      }
   1.974 +    }
   1.975 +  });
   1.976 +};
   1.977 +
   1.978 +// related to Bug 671305
   1.979 +exports.testOnLoadEventWithImage = function(assert, done) {
   1.980 +  let count = 0;
   1.981 +
   1.982 +  tabs.open({
   1.983 +    url: fixtures.url('Firefox.jpg'),
   1.984 +    inBackground: true,
   1.985 +    onLoad: function(tab) {
   1.986 +      if (++count > 1) {
   1.987 +        assert.pass('onLoad event called on reload with image');
   1.988 +        tab.close(done);
   1.989 +      }
   1.990 +      else {
   1.991 +        assert.pass('first onLoad event occured');
   1.992 +        tab.reload();
   1.993 +      }
   1.994 +    }
   1.995 +  });
   1.996 +};
   1.997 +
   1.998 +exports.testFaviconGetterDeprecation = function (assert, done) {
   1.999 +  setPref(DEPRECATE_PREF, true);
  1.1000 +  const { LoaderWithHookedConsole } = require("sdk/test/loader");
  1.1001 +  let { loader, messages } = LoaderWithHookedConsole(module);
  1.1002 +  let tabs = loader.require('sdk/tabs');
  1.1003 +
  1.1004 +  tabs.open({
  1.1005 +    url: 'data:text/html;charset=utf-8,',
  1.1006 +    onOpen: function (tab) {
  1.1007 +      let favicon = tab.favicon;
  1.1008 +      assert.ok(messages.length === 1, 'only one error is dispatched');
  1.1009 +      assert.ok(messages[0].type, 'error', 'the console message is an error');
  1.1010 +
  1.1011 +      let msg = messages[0].msg;
  1.1012 +      assert.ok(msg.indexOf('tab.favicon is deprecated') !== -1,
  1.1013 +        'message contains the given message');
  1.1014 +      tab.close(done);
  1.1015 +      loader.unload();
  1.1016 +    }
  1.1017 +  });
  1.1018 +}
  1.1019 +
  1.1020 +/******************* helpers *********************/
  1.1021 +
  1.1022 +// Utility function to open a new browser window.
  1.1023 +function openBrowserWindow(callback, url) {
  1.1024 +  let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
  1.1025 +           getService(Ci.nsIWindowWatcher);
  1.1026 +  let urlString = Cc["@mozilla.org/supports-string;1"].
  1.1027 +                  createInstance(Ci.nsISupportsString);
  1.1028 +  urlString.data = url;
  1.1029 +  let window = ww.openWindow(null, "chrome://browser/content/browser.xul",
  1.1030 +                             "_blank", "chrome,all,dialog=no", urlString);
  1.1031 +
  1.1032 +  if (callback) {
  1.1033 +    window.addEventListener("load", function onLoad(event) {
  1.1034 +      if (event.target && event.target.defaultView == window) {
  1.1035 +        window.removeEventListener("load", onLoad, true);
  1.1036 +        let browsers = window.document.getElementsByTagName("tabbrowser");
  1.1037 +        try {
  1.1038 +          setTimeout(function () {
  1.1039 +            callback(window, browsers[0]);
  1.1040 +          }, 10);
  1.1041 +        }
  1.1042 +        catch (e) {
  1.1043 +          console.exception(e);
  1.1044 +        }
  1.1045 +      }
  1.1046 +    }, true);
  1.1047 +  }
  1.1048 +
  1.1049 +  return window;
  1.1050 +}
  1.1051 +
  1.1052 +require('sdk/test').run(exports);

mercurial