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

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial