596 lines
17 KiB
JavaScript
596 lines
17 KiB
JavaScript
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||
|
'use strict';
|
||
|
|
||
|
const { Cc, Ci } = require('chrome');
|
||
|
const { Loader, LoaderWithHookedConsole } = require('sdk/test/loader');
|
||
|
const timer = require('sdk/timers');
|
||
|
const tabs = require('sdk/tabs');
|
||
|
const windows = require('sdk/windows');
|
||
|
const { set: setPref } = require("sdk/preferences/service");
|
||
|
const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
|
||
|
|
||
|
const tabsLen = tabs.length;
|
||
|
const URL = 'data:text/html;charset=utf-8,<html><head><title>#title#</title></head></html>';
|
||
|
|
||
|
// Fennec error message dispatched on all currently unimplement tab features,
|
||
|
// that match LoaderWithHookedConsole messages object pattern
|
||
|
const ERR_FENNEC_MSG = {
|
||
|
type: "error",
|
||
|
msg: "This method is not yet supported by Fennec"
|
||
|
};
|
||
|
|
||
|
// TEST: tab unloader
|
||
|
exports.testAutomaticDestroy = function(assert, done) {
|
||
|
let called = false;
|
||
|
|
||
|
let loader2 = Loader(module);
|
||
|
let loader3 = Loader(module);
|
||
|
let tabs2 = loader2.require('sdk/tabs');
|
||
|
let tabs3 = loader3.require('sdk/tabs');
|
||
|
let tabs2Len = tabs2.length;
|
||
|
|
||
|
tabs2.on('open', function onOpen(tab) {
|
||
|
assert.fail("an onOpen listener was called that should not have been");
|
||
|
called = true;
|
||
|
});
|
||
|
tabs2.on('ready', function onReady(tab) {
|
||
|
assert.fail("an onReady listener was called that should not have been");
|
||
|
called = true;
|
||
|
});
|
||
|
tabs2.on('select', function onSelect(tab) {
|
||
|
assert.fail("an onSelect listener was called that should not have been");
|
||
|
called = true;
|
||
|
});
|
||
|
tabs2.on('close', function onClose(tab) {
|
||
|
assert.fail("an onClose listener was called that should not have been");
|
||
|
called = true;
|
||
|
});
|
||
|
loader2.unload();
|
||
|
|
||
|
tabs3.on('open', function onOpen(tab) {
|
||
|
assert.pass("an onOpen listener was called for tabs3");
|
||
|
|
||
|
tab.on('ready', function onReady(tab) {
|
||
|
assert.fail("an onReady listener was called that should not have been");
|
||
|
called = true;
|
||
|
});
|
||
|
tab.on('select', function onSelect(tab) {
|
||
|
assert.fail("an onSelect listener was called that should not have been");
|
||
|
called = true;
|
||
|
});
|
||
|
tab.on('close', function onClose(tab) {
|
||
|
assert.fail("an onClose listener was called that should not have been");
|
||
|
called = true;
|
||
|
});
|
||
|
});
|
||
|
tabs3.open(URL.replace(/#title#/, 'tabs3'));
|
||
|
loader3.unload();
|
||
|
|
||
|
// Fire a tab event and ensure that the destroyed tab is inactive
|
||
|
tabs.once('open', function(tab) {
|
||
|
assert.pass('tabs.once("open") works!');
|
||
|
|
||
|
assert.equal(tabs2Len, tabs2.length, "tabs2 length was not changed");
|
||
|
assert.equal(tabs.length, (tabs2.length+2), "tabs.length > tabs2.length");
|
||
|
|
||
|
tab.once('ready', function() {
|
||
|
assert.pass('tab.once("ready") works!');
|
||
|
|
||
|
tab.once('close', function() {
|
||
|
assert.pass('tab.once("close") works!');
|
||
|
|
||
|
timer.setTimeout(function () {
|
||
|
assert.ok(!called, "Unloaded tab module is destroyed and inactive");
|
||
|
|
||
|
// end test
|
||
|
done();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
tab.close();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
tabs.open('data:text/html;charset=utf-8,foo');
|
||
|
};
|
||
|
|
||
|
// TEST: tab properties
|
||
|
exports.testTabProperties = function(assert, done) {
|
||
|
let url = "data:text/html;charset=utf-8,<html><head><title>foo</title></head><body>foo</body></html>";
|
||
|
let tabsLen = tabs.length;
|
||
|
tabs.open({
|
||
|
url: url,
|
||
|
onReady: function(tab) {
|
||
|
assert.equal(tab.title, "foo", "title of the new tab matches");
|
||
|
assert.equal(tab.url, url, "URL of the new tab matches");
|
||
|
assert.equal(tab.style, null, "style of the new tab matches");
|
||
|
assert.equal(tab.index, tabsLen, "index of the new tab matches");
|
||
|
assert.notEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
|
||
|
assert.notEqual(tab.id, null, "a tab object always has an id property");
|
||
|
|
||
|
tab.close(function() {
|
||
|
loader.unload();
|
||
|
|
||
|
// end test
|
||
|
done();
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// TEST: tabs iterator and length property
|
||
|
exports.testTabsIteratorAndLength = function(assert, done) {
|
||
|
let newTabs = [];
|
||
|
let startCount = 0;
|
||
|
for (let t of tabs) startCount++;
|
||
|
|
||
|
assert.equal(startCount, tabs.length, "length property is correct");
|
||
|
|
||
|
let url = "data:text/html;charset=utf-8,testTabsIteratorAndLength";
|
||
|
tabs.open({url: url, onOpen: tab => newTabs.push(tab)});
|
||
|
tabs.open({url: url, onOpen: tab => newTabs.push(tab)});
|
||
|
tabs.open({
|
||
|
url: url,
|
||
|
onOpen: function(tab) {
|
||
|
let count = 0;
|
||
|
for (let t of tabs) count++;
|
||
|
assert.equal(count, startCount + 3, "iterated tab count matches");
|
||
|
assert.equal(startCount + 3, tabs.length, "iterated tab count matches length property");
|
||
|
|
||
|
let newTabsLength = newTabs.length;
|
||
|
newTabs.forEach(t => t.close(function() {
|
||
|
if (--newTabsLength > 0) return;
|
||
|
|
||
|
tab.close(done);
|
||
|
}));
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// TEST: tab.url setter
|
||
|
exports.testTabLocation = function(assert, done) {
|
||
|
let url1 = "data:text/html;charset=utf-8,foo";
|
||
|
let url2 = "data:text/html;charset=utf-8,bar";
|
||
|
|
||
|
tabs.on('ready', function onReady(tab) {
|
||
|
if (tab.url != url2)
|
||
|
return;
|
||
|
|
||
|
tabs.removeListener('ready', onReady);
|
||
|
assert.pass("tab loaded the correct url");
|
||
|
|
||
|
tab.close(done);
|
||
|
});
|
||
|
|
||
|
tabs.open({
|
||
|
url: url1,
|
||
|
onOpen: function(tab) {
|
||
|
tab.url = url2;
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// TEST: tab.move()
|
||
|
exports.testTabMove = function(assert, done) {
|
||
|
let { loader, messages } = LoaderWithHookedConsole();
|
||
|
let tabs = loader.require('sdk/tabs');
|
||
|
|
||
|
let url = "data:text/html;charset=utf-8,testTabMove";
|
||
|
|
||
|
tabs.open({
|
||
|
url: url,
|
||
|
onOpen: function(tab1) {
|
||
|
assert.ok(tab1.index >= 0, "opening a tab returns a tab w/ valid index");
|
||
|
|
||
|
tabs.open({
|
||
|
url: url,
|
||
|
onOpen: function(tab) {
|
||
|
let i = tab.index;
|
||
|
assert.ok(tab.index > tab1.index, "2nd tab has valid index");
|
||
|
tab.index = 0;
|
||
|
assert.equal(tab.index, i, "tab index after move matches");
|
||
|
assert.equal(JSON.stringify(messages),
|
||
|
JSON.stringify([ERR_FENNEC_MSG]),
|
||
|
"setting tab.index logs error");
|
||
|
// end test
|
||
|
tab1.close(() => tab.close(function() {
|
||
|
loader.unload();
|
||
|
done();
|
||
|
}));
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// TEST: open tab with default options
|
||
|
exports.testTabsOpen_alt = function(assert, done) {
|
||
|
let { loader, messages } = LoaderWithHookedConsole();
|
||
|
let tabs = loader.require('sdk/tabs');
|
||
|
let url = "data:text/html;charset=utf-8,default";
|
||
|
|
||
|
tabs.open({
|
||
|
url: url,
|
||
|
onReady: function(tab) {
|
||
|
assert.equal(tab.url, url, "URL of the new tab matches");
|
||
|
assert.equal(tabs.activeTab, tab, "URL of active tab in the current window matches");
|
||
|
assert.equal(tab.isPinned, false, "The new tab is not pinned");
|
||
|
assert.equal(messages.length, 1, "isPinned logs error");
|
||
|
|
||
|
// end test
|
||
|
tab.close(function() {
|
||
|
loader.unload();
|
||
|
done();
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// TEST: open pinned tab
|
||
|
exports.testOpenPinned_alt = function(assert, done) {
|
||
|
let { loader, messages } = LoaderWithHookedConsole();
|
||
|
let tabs = loader.require('sdk/tabs');
|
||
|
let url = "about:blank";
|
||
|
|
||
|
tabs.open({
|
||
|
url: url,
|
||
|
isPinned: true,
|
||
|
onOpen: function(tab) {
|
||
|
assert.equal(tab.isPinned, false, "The new tab is pinned");
|
||
|
// We get two error message: one for tabs.open's isPinned argument
|
||
|
// and another one for tab.isPinned
|
||
|
assert.equal(JSON.stringify(messages),
|
||
|
JSON.stringify([ERR_FENNEC_MSG, ERR_FENNEC_MSG]),
|
||
|
"isPinned logs error");
|
||
|
|
||
|
// end test
|
||
|
tab.close(function() {
|
||
|
loader.unload();
|
||
|
done();
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// TEST: pin/unpin opened tab
|
||
|
exports.testPinUnpin_alt = function(assert, done) {
|
||
|
let { loader, messages } = LoaderWithHookedConsole();
|
||
|
let tabs = loader.require('sdk/tabs');
|
||
|
let url = "data:text/html;charset=utf-8,default";
|
||
|
|
||
|
tabs.open({
|
||
|
url: url,
|
||
|
onOpen: function(tab) {
|
||
|
tab.pin();
|
||
|
assert.equal(tab.isPinned, false, "The tab was pinned correctly");
|
||
|
assert.equal(JSON.stringify(messages),
|
||
|
JSON.stringify([ERR_FENNEC_MSG, ERR_FENNEC_MSG]),
|
||
|
"tab.pin() logs error");
|
||
|
|
||
|
// Clear console messages for the following test
|
||
|
messages.length = 0;
|
||
|
|
||
|
tab.unpin();
|
||
|
assert.equal(tab.isPinned, false, "The tab was unpinned correctly");
|
||
|
assert.equal(JSON.stringify(messages),
|
||
|
JSON.stringify([ERR_FENNEC_MSG, ERR_FENNEC_MSG]),
|
||
|
"tab.unpin() logs error");
|
||
|
|
||
|
// end test
|
||
|
tab.close(function() {
|
||
|
loader.unload();
|
||
|
done();
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// TEST: open tab in background
|
||
|
exports.testInBackground = function(assert, done) {
|
||
|
let activeUrl = tabs.activeTab.url;
|
||
|
let url = "data:text/html;charset=utf-8,background";
|
||
|
let window = windows.browserWindows.activeWindow;
|
||
|
tabs.once('ready', function onReady(tab) {
|
||
|
assert.equal(tabs.activeTab.url, activeUrl, "URL of active tab has not changed");
|
||
|
assert.equal(tab.url, url, "URL of the new background tab matches");
|
||
|
assert.equal(windows.browserWindows.activeWindow, window, "a new window was not opened");
|
||
|
assert.notEqual(tabs.activeTab.url, url, "URL of active tab is not the new URL");
|
||
|
|
||
|
// end test
|
||
|
tab.close(done);
|
||
|
});
|
||
|
|
||
|
tabs.open({
|
||
|
url: url,
|
||
|
inBackground: true
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// TEST: open tab in new window
|
||
|
exports.testOpenInNewWindow = function(assert, done) {
|
||
|
let url = "data:text/html;charset=utf-8,newwindow";
|
||
|
let window = windows.browserWindows.activeWindow;
|
||
|
|
||
|
tabs.open({
|
||
|
url: url,
|
||
|
inNewWindow: true,
|
||
|
onReady: function(tab) {
|
||
|
assert.equal(windows.browserWindows.length, 1, "a new window was not opened");
|
||
|
assert.equal(windows.browserWindows.activeWindow, window, "old window is active");
|
||
|
assert.equal(tab.url, url, "URL of the new tab matches");
|
||
|
assert.equal(tabs.activeTab, tab, "tab is the activeTab");
|
||
|
|
||
|
tab.close(done);
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// TEST: onOpen event handler
|
||
|
exports.testTabsEvent_onOpen = function(assert, done) {
|
||
|
let url = URL.replace('#title#', 'testTabsEvent_onOpen');
|
||
|
let eventCount = 0;
|
||
|
|
||
|
// add listener via property assignment
|
||
|
function listener1(tab) {
|
||
|
eventCount++;
|
||
|
};
|
||
|
tabs.on('open', listener1);
|
||
|
|
||
|
// add listener via collection add
|
||
|
tabs.on('open', function listener2(tab) {
|
||
|
assert.equal(++eventCount, 2, "both listeners notified");
|
||
|
tabs.removeListener('open', listener1);
|
||
|
tabs.removeListener('open', listener2);
|
||
|
|
||
|
// ends test
|
||
|
tab.close(done);
|
||
|
});
|
||
|
|
||
|
tabs.open(url);
|
||
|
};
|
||
|
|
||
|
// TEST: onClose event handler
|
||
|
exports.testTabsEvent_onClose = function(assert, done) {
|
||
|
let url = "data:text/html;charset=utf-8,onclose";
|
||
|
let eventCount = 0;
|
||
|
|
||
|
// add listener via property assignment
|
||
|
function listener1(tab) {
|
||
|
eventCount++;
|
||
|
}
|
||
|
tabs.on('close', listener1);
|
||
|
|
||
|
// add listener via collection add
|
||
|
tabs.on('close', function listener2(tab) {
|
||
|
assert.equal(++eventCount, 2, "both listeners notified");
|
||
|
tabs.removeListener('close', listener1);
|
||
|
tabs.removeListener('close', listener2);
|
||
|
|
||
|
// end test
|
||
|
done();
|
||
|
});
|
||
|
|
||
|
tabs.on('ready', function onReady(tab) {
|
||
|
tabs.removeListener('ready', onReady);
|
||
|
tab.close();
|
||
|
});
|
||
|
|
||
|
tabs.open(url);
|
||
|
};
|
||
|
|
||
|
// TEST: onClose event handler when a window is closed
|
||
|
exports.testTabsEvent_onCloseWindow = function(assert, done) {
|
||
|
let closeCount = 0, individualCloseCount = 0;
|
||
|
function listener() {
|
||
|
closeCount++;
|
||
|
}
|
||
|
tabs.on('close', listener);
|
||
|
|
||
|
// One tab is already open with the window
|
||
|
let openTabs = 0;
|
||
|
function testCasePossiblyLoaded(tab) {
|
||
|
tab.close(function() {
|
||
|
if (++openTabs == 3) {
|
||
|
tabs.removeListener("close", listener);
|
||
|
|
||
|
assert.equal(closeCount, 3, "Correct number of close events received");
|
||
|
assert.equal(individualCloseCount, 3,
|
||
|
"Each tab with an attached onClose listener received a close " +
|
||
|
"event when the window was closed");
|
||
|
|
||
|
done();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
tabs.open({
|
||
|
url: "data:text/html;charset=utf-8,tab2",
|
||
|
onOpen: testCasePossiblyLoaded,
|
||
|
onClose: () => individualCloseCount++
|
||
|
});
|
||
|
|
||
|
tabs.open({
|
||
|
url: "data:text/html;charset=utf-8,tab3",
|
||
|
onOpen: testCasePossiblyLoaded,
|
||
|
onClose: () => individualCloseCount++
|
||
|
});
|
||
|
|
||
|
tabs.open({
|
||
|
url: "data:text/html;charset=utf-8,tab4",
|
||
|
onOpen: testCasePossiblyLoaded,
|
||
|
onClose: () => individualCloseCount++
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// TEST: onReady event handler
|
||
|
exports.testTabsEvent_onReady = function(assert, done) {
|
||
|
let url = "data:text/html;charset=utf-8,onready";
|
||
|
let eventCount = 0;
|
||
|
|
||
|
// add listener via property assignment
|
||
|
function listener1(tab) {
|
||
|
eventCount++;
|
||
|
};
|
||
|
tabs.on('ready', listener1);
|
||
|
|
||
|
// add listener via collection add
|
||
|
tabs.on('ready', function listener2(tab) {
|
||
|
assert.equal(++eventCount, 2, "both listeners notified");
|
||
|
tabs.removeListener('ready', listener1);
|
||
|
tabs.removeListener('ready', listener2);
|
||
|
|
||
|
// end test
|
||
|
tab.close(done);
|
||
|
});
|
||
|
|
||
|
tabs.open(url);
|
||
|
};
|
||
|
|
||
|
// TEST: onActivate event handler
|
||
|
exports.testTabsEvent_onActivate = function(assert, done) {
|
||
|
let url = "data:text/html;charset=utf-8,onactivate";
|
||
|
let eventCount = 0;
|
||
|
|
||
|
// add listener via property assignment
|
||
|
function listener1(tab) {
|
||
|
eventCount++;
|
||
|
};
|
||
|
tabs.on('activate', listener1);
|
||
|
|
||
|
// add listener via collection add
|
||
|
tabs.on('activate', function listener2(tab) {
|
||
|
assert.equal(++eventCount, 2, "both listeners notified");
|
||
|
assert.equal(tab, tabs.activeTab, 'the active tab is correct');
|
||
|
tabs.removeListener('activate', listener1);
|
||
|
tabs.removeListener('activate', listener2);
|
||
|
|
||
|
// end test
|
||
|
tab.close(done);
|
||
|
});
|
||
|
|
||
|
tabs.open(url);
|
||
|
};
|
||
|
|
||
|
// TEST: onDeactivate event handler
|
||
|
exports.testTabsEvent_onDeactivate = function(assert, done) {
|
||
|
let url = "data:text/html;charset=utf-8,ondeactivate";
|
||
|
let eventCount = 0;
|
||
|
|
||
|
// add listener via property assignment
|
||
|
function listener1(tab) {
|
||
|
eventCount++;
|
||
|
};
|
||
|
tabs.on('deactivate', listener1);
|
||
|
|
||
|
// add listener via collection add
|
||
|
tabs.on('deactivate', function listener2(tab) {
|
||
|
assert.equal(++eventCount, 2, 'both listeners notified');
|
||
|
assert.notEqual(tab, tabs.activeTab, 'the active tab is not the deactivated tab');
|
||
|
tabs.removeListener('deactivate', listener1);
|
||
|
tabs.removeListener('deactivate', listener2);
|
||
|
|
||
|
// end test
|
||
|
tab.close(done);
|
||
|
});
|
||
|
|
||
|
tabs.on('activate', function onActivate(tab) {
|
||
|
tabs.removeListener('activate', onActivate);
|
||
|
tabs.open("data:text/html;charset=utf-8,foo");
|
||
|
tab.close();
|
||
|
});
|
||
|
|
||
|
tabs.open(url);
|
||
|
};
|
||
|
|
||
|
// TEST: per-tab event handlers
|
||
|
exports.testPerTabEvents = function(assert, done) {
|
||
|
let eventCount = 0;
|
||
|
|
||
|
tabs.open({
|
||
|
url: "data:text/html;charset=utf-8,foo",
|
||
|
onOpen: function(tab) {
|
||
|
// add listener via property assignment
|
||
|
function listener1() {
|
||
|
eventCount++;
|
||
|
};
|
||
|
tab.on('ready', listener1);
|
||
|
|
||
|
// add listener via collection add
|
||
|
tab.on('ready', function listener2() {
|
||
|
assert.equal(eventCount, 1, "both listeners notified");
|
||
|
tab.removeListener('ready', listener1);
|
||
|
tab.removeListener('ready', listener2);
|
||
|
|
||
|
// end test
|
||
|
tab.close(done);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
exports.testUniqueTabIds = function(assert, done) {
|
||
|
var tabs = require('sdk/tabs');
|
||
|
var tabIds = {};
|
||
|
var steps = [
|
||
|
function (index) {
|
||
|
tabs.open({
|
||
|
url: "data:text/html;charset=utf-8,foo",
|
||
|
onOpen: function(tab) {
|
||
|
tabIds['tab1'] = tab.id;
|
||
|
next(index);
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
function (index) {
|
||
|
tabs.open({
|
||
|
url: "data:text/html;charset=utf-8,bar",
|
||
|
onOpen: function(tab) {
|
||
|
tabIds['tab2'] = tab.id;
|
||
|
next(index);
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
function (index) {
|
||
|
assert.notEqual(tabIds.tab1, tabIds.tab2, "Tab ids should be unique.");
|
||
|
done();
|
||
|
}
|
||
|
];
|
||
|
|
||
|
function next(index) {
|
||
|
if (index === steps.length) {
|
||
|
return;
|
||
|
}
|
||
|
let fn = steps[index];
|
||
|
index++;
|
||
|
fn(index);
|
||
|
}
|
||
|
|
||
|
next(0);
|
||
|
}
|
||
|
|
||
|
exports.testOnLoadEventWithDOM = function(assert, done) {
|
||
|
let count = 0;
|
||
|
let title = 'testOnLoadEventWithDOM';
|
||
|
|
||
|
tabs.open({
|
||
|
url: 'data:text/html;charset=utf-8,<title>' + title + '</title>',
|
||
|
inBackground: true,
|
||
|
onLoad: function(tab) {
|
||
|
assert.equal(tab.title, title, 'tab passed in as arg, load called');
|
||
|
|
||
|
if (++count > 1) {
|
||
|
assert.pass('onLoad event called on reload');
|
||
|
tab.close(done);
|
||
|
}
|
||
|
else {
|
||
|
assert.pass('first onLoad event occured');
|
||
|
tab.reload();
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
require("sdk/test").run(exports);
|