mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-10 01:07:31 +09:00
Remove browser tests - Part 1: The Tests (except for experiments)
This commit is contained in:
parent
fa08bd44f7
commit
261374f310
1697 changed files with 0 additions and 144364 deletions
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/mochitest/browser.eslintrc.js"
|
||||
]
|
||||
};
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[DEFAULT]
|
||||
support-files = head.js
|
||||
|
||||
[browser_sidebar_syncedtabslist.js]
|
||||
|
|
@ -1,410 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const FIXTURE = [
|
||||
{
|
||||
"id": "7cqCr77ptzX3",
|
||||
"type": "client",
|
||||
"name": "zcarter's Nightly on MacBook-Pro-25",
|
||||
"isMobile": false,
|
||||
"tabs": [
|
||||
{
|
||||
"type": "tab",
|
||||
"title": "Firefox for Android — Mobile Web browser — More ways to customize and protect your privacy — Mozilla",
|
||||
"url": "https://www.mozilla.org/en-US/firefox/android/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=synced-tabs-sidebar",
|
||||
"icon": "chrome://mozapps/skin/places/defaultFavicon.png",
|
||||
"client": "7cqCr77ptzX3",
|
||||
"lastUsed": 1452124677
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2xU5h-4bkWqA",
|
||||
"type": "client",
|
||||
"name": "laptop",
|
||||
"isMobile": false,
|
||||
"tabs": [
|
||||
{
|
||||
"type": "tab",
|
||||
"title": "Firefox for iOS — Mobile Web browser for your iPhone, iPad and iPod touch — Mozilla",
|
||||
"url": "https://www.mozilla.org/en-US/firefox/ios/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=synced-tabs-sidebar",
|
||||
"icon": "moz-anno:favicon:https://www.mozilla.org/media/img/firefox/favicon.dc6635050bf5.ico",
|
||||
"client": "2xU5h-4bkWqA",
|
||||
"lastUsed": 1451519425
|
||||
},
|
||||
{
|
||||
"type": "tab",
|
||||
"title": "Firefox Nightly First Run Page",
|
||||
"url": "https://www.mozilla.org/en-US/firefox/nightly/firstrun/?oldversion=45.0a1",
|
||||
"icon": "moz-anno:favicon:https://www.mozilla.org/media/img/firefox/favicon-nightly.560395bbb2e1.png",
|
||||
"client": "2xU5h-4bkWqA",
|
||||
"lastUsed": 1451519420
|
||||
},
|
||||
{
|
||||
// Should appear first for this client.
|
||||
"type": "tab",
|
||||
"title": "Mozilla Developer Network",
|
||||
"url": "https://developer.mozilla.org/en-US/",
|
||||
"icon": "moz-anno:favicon:https://developer.cdn.mozilla.net/static/img/favicon32.e02854fdcf73.png",
|
||||
"client": "2xU5h-4bkWqA",
|
||||
"lastUsed": 1451519725
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "OL3EJCsdb2JD",
|
||||
"type": "client",
|
||||
"name": "desktop",
|
||||
"isMobile": false,
|
||||
"tabs": []
|
||||
}
|
||||
];
|
||||
|
||||
let originalSyncedTabsInternal = null;
|
||||
|
||||
function* testClean() {
|
||||
let syncedTabsDeckComponent = window.SidebarUI.browser.contentWindow.syncedTabsDeckComponent;
|
||||
let SyncedTabs = window.SidebarUI.browser.contentWindow.SyncedTabs;
|
||||
syncedTabsDeckComponent._accountStatus.restore();
|
||||
SyncedTabs._internal.getTabClients.restore();
|
||||
SyncedTabs._internal = originalSyncedTabsInternal;
|
||||
|
||||
yield new Promise(resolve => {
|
||||
window.SidebarUI.browser.contentWindow.addEventListener("unload", function listener() {
|
||||
window.SidebarUI.browser.contentWindow.removeEventListener("unload", listener);
|
||||
resolve();
|
||||
});
|
||||
SidebarUI.hide();
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* testSyncedTabsSidebarList() {
|
||||
yield SidebarUI.show('viewTabsSidebar');
|
||||
|
||||
Assert.equal(SidebarUI.currentID, "viewTabsSidebar", "Sidebar should have SyncedTabs loaded");
|
||||
|
||||
let syncedTabsDeckComponent = SidebarUI.browser.contentWindow.syncedTabsDeckComponent;
|
||||
let SyncedTabs = SidebarUI.browser.contentWindow.SyncedTabs;
|
||||
|
||||
Assert.ok(syncedTabsDeckComponent, "component exists");
|
||||
|
||||
originalSyncedTabsInternal = SyncedTabs._internal;
|
||||
SyncedTabs._internal = {
|
||||
isConfiguredToSyncTabs: true,
|
||||
hasSyncedThisSession: true,
|
||||
getTabClients() { return Promise.resolve([]) },
|
||||
syncTabs() { return Promise.resolve(); },
|
||||
};
|
||||
|
||||
sinon.stub(syncedTabsDeckComponent, "_accountStatus", () => Promise.resolve(true));
|
||||
sinon.stub(SyncedTabs._internal, "getTabClients", () => Promise.resolve(Cu.cloneInto(FIXTURE, {})));
|
||||
|
||||
yield syncedTabsDeckComponent.updatePanel();
|
||||
// This is a hacky way of waiting for the view to render. The view renders
|
||||
// after the following promise (a different instance of which is triggered
|
||||
// in updatePanel) resolves, so we wait for it here as well
|
||||
yield syncedTabsDeckComponent.tabListComponent._store.getData();
|
||||
|
||||
Assert.ok(SyncedTabs._internal.getTabClients.called, "get clients called");
|
||||
|
||||
let selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
|
||||
|
||||
|
||||
Assert.ok(selectedPanel.classList.contains("tabs-container"),
|
||||
"tabs panel is selected");
|
||||
|
||||
Assert.equal(selectedPanel.querySelectorAll(".tab").length, 4,
|
||||
"four tabs listed");
|
||||
Assert.equal(selectedPanel.querySelectorAll(".client").length, 3,
|
||||
"three clients listed");
|
||||
Assert.equal(selectedPanel.querySelectorAll(".client")[2].querySelectorAll(".empty").length, 1,
|
||||
"third client is empty");
|
||||
|
||||
// Verify that the tabs are sorted by last used time.
|
||||
var expectedTabIndices = [[0], [2, 0, 1]];
|
||||
Array.prototype.forEach.call(selectedPanel.querySelectorAll(".client"), (clientNode, i) => {
|
||||
checkItem(clientNode, FIXTURE[i]);
|
||||
Array.prototype.forEach.call(clientNode.querySelectorAll(".tab"), (tabNode, j) => {
|
||||
let tabIndex = expectedTabIndices[i][j];
|
||||
checkItem(tabNode, FIXTURE[i].tabs[tabIndex]);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
add_task(testClean);
|
||||
|
||||
add_task(function* testSyncedTabsSidebarFilteredList() {
|
||||
yield SidebarUI.show('viewTabsSidebar');
|
||||
let syncedTabsDeckComponent = window.SidebarUI.browser.contentWindow.syncedTabsDeckComponent;
|
||||
let SyncedTabs = window.SidebarUI.browser.contentWindow.SyncedTabs;
|
||||
|
||||
Assert.ok(syncedTabsDeckComponent, "component exists");
|
||||
|
||||
originalSyncedTabsInternal = SyncedTabs._internal;
|
||||
SyncedTabs._internal = {
|
||||
isConfiguredToSyncTabs: true,
|
||||
hasSyncedThisSession: true,
|
||||
getTabClients() { return Promise.resolve([]) },
|
||||
syncTabs() { return Promise.resolve(); },
|
||||
};
|
||||
|
||||
sinon.stub(syncedTabsDeckComponent, "_accountStatus", () => Promise.resolve(true));
|
||||
sinon.stub(SyncedTabs._internal, "getTabClients", () => Promise.resolve(Cu.cloneInto(FIXTURE, {})));
|
||||
|
||||
yield syncedTabsDeckComponent.updatePanel();
|
||||
// This is a hacky way of waiting for the view to render. The view renders
|
||||
// after the following promise (a different instance of which is triggered
|
||||
// in updatePanel) resolves, so we wait for it here as well
|
||||
yield syncedTabsDeckComponent.tabListComponent._store.getData();
|
||||
|
||||
let filterInput = syncedTabsDeckComponent._window.document.querySelector(".tabsFilter");
|
||||
filterInput.value = "filter text";
|
||||
filterInput.blur();
|
||||
|
||||
yield syncedTabsDeckComponent.tabListComponent._store.getData("filter text");
|
||||
|
||||
let selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
|
||||
Assert.ok(selectedPanel.classList.contains("tabs-container"),
|
||||
"tabs panel is selected");
|
||||
|
||||
Assert.equal(selectedPanel.querySelectorAll(".tab").length, 4,
|
||||
"four tabs listed");
|
||||
Assert.equal(selectedPanel.querySelectorAll(".client").length, 0,
|
||||
"no clients are listed");
|
||||
|
||||
Assert.equal(filterInput.value, "filter text",
|
||||
"filter text box has correct value");
|
||||
|
||||
// Tabs should not be sorted when filter is active.
|
||||
let FIXTURE_TABS = FIXTURE.reduce((prev, client) => prev.concat(client.tabs), []);
|
||||
|
||||
Array.prototype.forEach.call(selectedPanel.querySelectorAll(".tab"), (tabNode, i) => {
|
||||
checkItem(tabNode, FIXTURE_TABS[i]);
|
||||
});
|
||||
|
||||
// Removing the filter should resort tabs.
|
||||
FIXTURE_TABS.sort((a, b) => b.lastUsed - a.lastUsed);
|
||||
yield syncedTabsDeckComponent.tabListComponent._store.getData();
|
||||
Array.prototype.forEach.call(selectedPanel.querySelectorAll(".tab"), (tabNode, i) => {
|
||||
checkItem(tabNode, FIXTURE_TABS[i]);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(testClean);
|
||||
|
||||
add_task(function* testSyncedTabsSidebarStatus() {
|
||||
let accountExists = false;
|
||||
|
||||
yield SidebarUI.show('viewTabsSidebar');
|
||||
let syncedTabsDeckComponent = window.SidebarUI.browser.contentWindow.syncedTabsDeckComponent;
|
||||
let SyncedTabs = window.SidebarUI.browser.contentWindow.SyncedTabs;
|
||||
|
||||
originalSyncedTabsInternal = SyncedTabs._internal;
|
||||
SyncedTabs._internal = {
|
||||
isConfiguredToSyncTabs: false,
|
||||
hasSyncedThisSession: false,
|
||||
getTabClients() {},
|
||||
syncTabs() { return Promise.resolve(); },
|
||||
};
|
||||
|
||||
Assert.ok(syncedTabsDeckComponent, "component exists");
|
||||
|
||||
sinon.spy(syncedTabsDeckComponent, "updatePanel");
|
||||
sinon.spy(syncedTabsDeckComponent, "observe");
|
||||
|
||||
sinon.stub(syncedTabsDeckComponent, "_accountStatus", () => Promise.reject("Test error"));
|
||||
yield syncedTabsDeckComponent.updatePanel();
|
||||
|
||||
let selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
|
||||
Assert.ok(selectedPanel.classList.contains("notAuthedInfo"),
|
||||
"not-authed panel is selected on auth error");
|
||||
|
||||
syncedTabsDeckComponent._accountStatus.restore();
|
||||
sinon.stub(syncedTabsDeckComponent, "_accountStatus", () => Promise.resolve(accountExists));
|
||||
yield syncedTabsDeckComponent.updatePanel();
|
||||
selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
|
||||
Assert.ok(selectedPanel.classList.contains("notAuthedInfo"),
|
||||
"not-authed panel is selected");
|
||||
|
||||
accountExists = true;
|
||||
yield syncedTabsDeckComponent.updatePanel();
|
||||
selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
|
||||
Assert.ok(selectedPanel.classList.contains("tabs-disabled"),
|
||||
"tabs disabled panel is selected");
|
||||
|
||||
SyncedTabs._internal.isConfiguredToSyncTabs = true;
|
||||
yield syncedTabsDeckComponent.updatePanel();
|
||||
selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
|
||||
Assert.ok(selectedPanel.classList.contains("tabs-fetching"),
|
||||
"tabs fetch panel is selected");
|
||||
|
||||
SyncedTabs._internal.hasSyncedThisSession = true;
|
||||
sinon.stub(SyncedTabs._internal, "getTabClients", () => Promise.resolve([]));
|
||||
yield syncedTabsDeckComponent.updatePanel();
|
||||
selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
|
||||
Assert.ok(selectedPanel.classList.contains("singleDeviceInfo"),
|
||||
"tabs fetch panel is selected");
|
||||
|
||||
SyncedTabs._internal.getTabClients.restore();
|
||||
sinon.stub(SyncedTabs._internal, "getTabClients", () => Promise.resolve([{id: "mock"}]));
|
||||
yield syncedTabsDeckComponent.updatePanel();
|
||||
selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
|
||||
Assert.ok(selectedPanel.classList.contains("tabs-container"),
|
||||
"tabs panel is selected");
|
||||
});
|
||||
|
||||
add_task(testClean);
|
||||
|
||||
add_task(function* testSyncedTabsSidebarContextMenu() {
|
||||
yield SidebarUI.show('viewTabsSidebar');
|
||||
let syncedTabsDeckComponent = window.SidebarUI.browser.contentWindow.syncedTabsDeckComponent;
|
||||
let SyncedTabs = window.SidebarUI.browser.contentWindow.SyncedTabs;
|
||||
|
||||
Assert.ok(syncedTabsDeckComponent, "component exists");
|
||||
|
||||
originalSyncedTabsInternal = SyncedTabs._internal;
|
||||
SyncedTabs._internal = {
|
||||
isConfiguredToSyncTabs: true,
|
||||
hasSyncedThisSession: true,
|
||||
getTabClients() { return Promise.resolve([]) },
|
||||
syncTabs() { return Promise.resolve(); },
|
||||
};
|
||||
|
||||
sinon.stub(syncedTabsDeckComponent, "_accountStatus", () => Promise.resolve(true));
|
||||
sinon.stub(SyncedTabs._internal, "getTabClients", () => Promise.resolve(Cu.cloneInto(FIXTURE, {})));
|
||||
|
||||
yield syncedTabsDeckComponent.updatePanel();
|
||||
// This is a hacky way of waiting for the view to render. The view renders
|
||||
// after the following promise (a different instance of which is triggered
|
||||
// in updatePanel) resolves, so we wait for it here as well
|
||||
yield syncedTabsDeckComponent.tabListComponent._store.getData();
|
||||
|
||||
info("Right-clicking the search box should show text-related actions");
|
||||
let filterMenuItems = [
|
||||
"menuitem[cmd=cmd_undo]",
|
||||
"menuseparator",
|
||||
// We don't check whether the commands are enabled due to platform
|
||||
// differences. On OS X and Windows, "cut" and "copy" are always enabled
|
||||
// for HTML inputs; on Linux, they're only enabled if text is selected.
|
||||
"menuitem[cmd=cmd_cut]",
|
||||
"menuitem[cmd=cmd_copy]",
|
||||
"menuitem[cmd=cmd_paste]",
|
||||
"menuitem[cmd=cmd_delete]",
|
||||
"menuseparator",
|
||||
"menuitem[cmd=cmd_selectAll]",
|
||||
"menuseparator",
|
||||
"menuitem#syncedTabsRefreshFilter",
|
||||
];
|
||||
yield* testContextMenu(syncedTabsDeckComponent,
|
||||
"#SyncedTabsSidebarTabsFilterContext",
|
||||
".tabsFilter",
|
||||
filterMenuItems);
|
||||
|
||||
info("Right-clicking a tab should show additional actions");
|
||||
let tabMenuItems = [
|
||||
["menuitem#syncedTabsOpenSelected", { hidden: false }],
|
||||
["menuitem#syncedTabsOpenSelectedInTab", { hidden: false }],
|
||||
["menuitem#syncedTabsOpenSelectedInWindow", { hidden: false }],
|
||||
["menuitem#syncedTabsOpenSelectedInPrivateWindow", { hidden: false }],
|
||||
["menuseparator", { hidden: false }],
|
||||
["menuitem#syncedTabsBookmarkSelected", { hidden: false }],
|
||||
["menuitem#syncedTabsCopySelected", { hidden: false }],
|
||||
["menuseparator", { hidden: false }],
|
||||
["menuitem#syncedTabsRefresh", { hidden: false }],
|
||||
];
|
||||
yield* testContextMenu(syncedTabsDeckComponent,
|
||||
"#SyncedTabsSidebarContext",
|
||||
"#tab-7cqCr77ptzX3-0",
|
||||
tabMenuItems);
|
||||
|
||||
info("Right-clicking a client shouldn't show any actions");
|
||||
let sidebarMenuItems = [
|
||||
["menuitem#syncedTabsOpenSelected", { hidden: true }],
|
||||
["menuitem#syncedTabsOpenSelectedInTab", { hidden: true }],
|
||||
["menuitem#syncedTabsOpenSelectedInWindow", { hidden: true }],
|
||||
["menuitem#syncedTabsOpenSelectedInPrivateWindow", { hidden: true }],
|
||||
["menuseparator", { hidden: true }],
|
||||
["menuitem#syncedTabsBookmarkSelected", { hidden: true }],
|
||||
["menuitem#syncedTabsCopySelected", { hidden: true }],
|
||||
["menuseparator", { hidden: true }],
|
||||
["menuitem#syncedTabsRefresh", { hidden: false }],
|
||||
];
|
||||
yield* testContextMenu(syncedTabsDeckComponent,
|
||||
"#SyncedTabsSidebarContext",
|
||||
"#item-OL3EJCsdb2JD",
|
||||
sidebarMenuItems);
|
||||
});
|
||||
|
||||
add_task(testClean);
|
||||
|
||||
function checkItem(node, item) {
|
||||
Assert.ok(node.classList.contains("item"),
|
||||
"Node should have .item class");
|
||||
if (item.client) {
|
||||
// tab items
|
||||
Assert.equal(node.querySelector(".item-title").textContent, item.title,
|
||||
"Node's title element's text should match item title");
|
||||
Assert.ok(node.classList.contains("tab"),
|
||||
"Node should have .tab class");
|
||||
Assert.equal(node.dataset.url, item.url,
|
||||
"Node's URL should match item URL");
|
||||
Assert.equal(node.getAttribute("title"), item.title + "\n" + item.url,
|
||||
"Tab node should have correct title attribute");
|
||||
} else {
|
||||
// client items
|
||||
Assert.equal(node.querySelector(".item-title").textContent, item.name,
|
||||
"Node's title element's text should match client name");
|
||||
Assert.ok(node.classList.contains("client"),
|
||||
"Node should have .client class");
|
||||
Assert.equal(node.dataset.id, item.id,
|
||||
"Node's ID should match item ID");
|
||||
}
|
||||
}
|
||||
|
||||
function* testContextMenu(syncedTabsDeckComponent, contextSelector, triggerSelector, menuSelectors) {
|
||||
let contextMenu = document.querySelector(contextSelector);
|
||||
let triggerElement = syncedTabsDeckComponent._window.document.querySelector(triggerSelector);
|
||||
let isClosed = triggerElement.classList.contains("closed");
|
||||
|
||||
let promisePopupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
|
||||
|
||||
let chromeWindow = triggerElement.ownerGlobal.top;
|
||||
let rect = triggerElement.getBoundingClientRect();
|
||||
let contentRect = chromeWindow.SidebarUI.browser.getBoundingClientRect();
|
||||
// The offsets in `rect` are relative to the content window, but
|
||||
// `synthesizeMouseAtPoint` calls `nsIDOMWindowUtils.sendMouseEvent`,
|
||||
// which interprets the offsets relative to the containing *chrome* window.
|
||||
// This means we need to account for the width and height of any elements
|
||||
// outside the `browser` element, like `sidebarheader`.
|
||||
let offsetX = contentRect.x + rect.x + (rect.width / 2);
|
||||
let offsetY = contentRect.y + rect.y + (rect.height / 4);
|
||||
|
||||
yield EventUtils.synthesizeMouseAtPoint(offsetX, offsetY, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
}, chromeWindow);
|
||||
yield promisePopupShown;
|
||||
is(triggerElement.classList.contains("closed"), isClosed,
|
||||
"Showing the context menu shouldn't toggle the tab list");
|
||||
checkChildren(contextMenu, menuSelectors);
|
||||
|
||||
let promisePopupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
|
||||
contextMenu.hidePopup();
|
||||
yield promisePopupHidden;
|
||||
}
|
||||
|
||||
function checkChildren(node, selectors) {
|
||||
is(node.children.length, selectors.length, "Menu item count doesn't match");
|
||||
for (let index = 0; index < node.children.length; index++) {
|
||||
let child = node.children[index];
|
||||
let [selector, props] = [].concat(selectors[index]);
|
||||
ok(selector, `Node at ${index} should have selector`);
|
||||
ok(child.matches(selector), `Node ${
|
||||
index} should match ${selector}`);
|
||||
if (props) {
|
||||
Object.keys(props).forEach(prop => {
|
||||
is(child[prop], props[prop], `${prop} value at ${index} should match`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
|
||||
// Load mocking/stubbing library, sinon
|
||||
// docs: http://sinonjs.org/docs/
|
||||
/* global sinon */
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("resource://testing-common/sinon-1.16.1.js");
|
||||
|
||||
registerCleanupFunction(function*() {
|
||||
// Cleanup window or the test runner will throw an error
|
||||
delete window.sinon;
|
||||
delete window.setImmediate;
|
||||
delete window.clearImmediate;
|
||||
});
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
]
|
||||
};
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () {
|
||||
return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {});
|
||||
});
|
||||
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
do_get_profile(); // fxa needs a profile directory for storage.
|
||||
|
||||
// Create a window polyfill so sinon can load
|
||||
let window = {
|
||||
document: {},
|
||||
location: {},
|
||||
setTimeout: setTimeout,
|
||||
setInterval: setInterval,
|
||||
clearTimeout: clearTimeout,
|
||||
clearinterval: clearInterval
|
||||
};
|
||||
let self = window;
|
||||
|
||||
// Load mocking/stubbing library, sinon
|
||||
// docs: http://sinonjs.org/docs/
|
||||
/* global sinon */
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("resource://testing-common/sinon-1.16.1.js");
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
let { EventEmitter } = Cu.import("resource:///modules/syncedtabs/EventEmitter.jsm", {});
|
||||
|
||||
add_task(function* testSingleListener() {
|
||||
let eventEmitter = new EventEmitter();
|
||||
let spy = sinon.spy();
|
||||
|
||||
eventEmitter.on("click", spy);
|
||||
eventEmitter.emit("click", "foo", "bar");
|
||||
Assert.ok(spy.calledOnce);
|
||||
Assert.ok(spy.calledWith("foo", "bar"));
|
||||
|
||||
eventEmitter.off("click", spy);
|
||||
eventEmitter.emit("click");
|
||||
Assert.ok(spy.calledOnce);
|
||||
});
|
||||
|
||||
add_task(function* testMultipleListeners() {
|
||||
let eventEmitter = new EventEmitter();
|
||||
let spy1 = sinon.spy();
|
||||
let spy2 = sinon.spy();
|
||||
|
||||
eventEmitter.on("some_event", spy1);
|
||||
eventEmitter.on("some_event", spy2);
|
||||
eventEmitter.emit("some_event");
|
||||
Assert.ok(spy1.calledOnce);
|
||||
Assert.ok(spy2.calledOnce);
|
||||
|
||||
eventEmitter.off("some_event", spy1);
|
||||
eventEmitter.emit("some_event");
|
||||
Assert.ok(spy1.calledOnce);
|
||||
Assert.ok(spy2.calledTwice);
|
||||
});
|
||||
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
let { SyncedTabs } = Cu.import("resource://services-sync/SyncedTabs.jsm", {});
|
||||
let { SyncedTabsDeckComponent } = Cu.import("resource:///modules/syncedtabs/SyncedTabsDeckComponent.js", {});
|
||||
let { TabListComponent } = Cu.import("resource:///modules/syncedtabs/TabListComponent.js", {});
|
||||
let { SyncedTabsListStore } = Cu.import("resource:///modules/syncedtabs/SyncedTabsListStore.js", {});
|
||||
let { SyncedTabsDeckStore } = Cu.import("resource:///modules/syncedtabs/SyncedTabsDeckStore.js", {});
|
||||
let { TabListView } = Cu.import("resource:///modules/syncedtabs/TabListView.js", {});
|
||||
let { DeckView } = Cu.import("resource:///modules/syncedtabs/SyncedTabsDeckView.js", {});
|
||||
|
||||
|
||||
add_task(function* testInitUninit() {
|
||||
let deckStore = new SyncedTabsDeckStore();
|
||||
let listComponent = {};
|
||||
|
||||
let ViewMock = sinon.stub();
|
||||
let view = {render: sinon.spy(), destroy: sinon.spy(), container: {}};
|
||||
ViewMock.returns(view);
|
||||
|
||||
sinon.stub(SyncedTabs, "syncTabs", () => Promise.resolve());
|
||||
|
||||
sinon.spy(deckStore, "on");
|
||||
sinon.stub(deckStore, "setPanels");
|
||||
|
||||
let component = new SyncedTabsDeckComponent({
|
||||
window,
|
||||
deckStore,
|
||||
listComponent,
|
||||
SyncedTabs,
|
||||
DeckView: ViewMock,
|
||||
});
|
||||
|
||||
sinon.stub(component, "updatePanel");
|
||||
|
||||
component.init();
|
||||
|
||||
Assert.ok(SyncedTabs.syncTabs.called);
|
||||
SyncedTabs.syncTabs.restore();
|
||||
|
||||
Assert.ok(ViewMock.calledWithNew(), "view is instantiated");
|
||||
Assert.equal(ViewMock.args[0][0], window);
|
||||
Assert.equal(ViewMock.args[0][1], listComponent);
|
||||
Assert.ok(ViewMock.args[0][2].onAndroidClick,
|
||||
"view is passed onAndroidClick prop");
|
||||
Assert.ok(ViewMock.args[0][2].oniOSClick,
|
||||
"view is passed oniOSClick prop");
|
||||
Assert.ok(ViewMock.args[0][2].onSyncPrefClick,
|
||||
"view is passed onSyncPrefClick prop");
|
||||
|
||||
Assert.equal(component.container, view.container,
|
||||
"component returns view's container");
|
||||
|
||||
Assert.ok(deckStore.on.calledOnce, "listener is added to store");
|
||||
Assert.equal(deckStore.on.args[0][0], "change");
|
||||
// Object.values only in nightly
|
||||
let values = Object.keys(component.PANELS).map(k => component.PANELS[k]);
|
||||
Assert.ok(deckStore.setPanels.calledWith(values),
|
||||
"panels are set on deck store");
|
||||
|
||||
Assert.ok(component.updatePanel.called);
|
||||
|
||||
deckStore.emit("change", "mock state");
|
||||
Assert.ok(view.render.calledWith("mock state"),
|
||||
"view.render is called on state change");
|
||||
|
||||
component.uninit();
|
||||
|
||||
Assert.ok(view.destroy.calledOnce, "view is destroyed on uninit");
|
||||
});
|
||||
|
||||
|
||||
function waitForObserver() {
|
||||
return new Promise((resolve, reject) => {
|
||||
Services.obs.addObserver((subject, topic) => {
|
||||
resolve();
|
||||
}, SyncedTabs.TOPIC_TABS_CHANGED, false);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* testObserver() {
|
||||
let deckStore = new SyncedTabsDeckStore();
|
||||
let listStore = new SyncedTabsListStore(SyncedTabs);
|
||||
let listComponent = {};
|
||||
|
||||
let ViewMock = sinon.stub();
|
||||
let view = {render: sinon.spy(), destroy: sinon.spy(), container: {}};
|
||||
ViewMock.returns(view);
|
||||
|
||||
sinon.stub(SyncedTabs, "syncTabs", () => Promise.resolve());
|
||||
|
||||
sinon.spy(deckStore, "on");
|
||||
sinon.stub(deckStore, "setPanels");
|
||||
|
||||
sinon.stub(listStore, "getData");
|
||||
|
||||
let component = new SyncedTabsDeckComponent({
|
||||
window,
|
||||
deckStore,
|
||||
listStore,
|
||||
listComponent,
|
||||
SyncedTabs,
|
||||
DeckView: ViewMock,
|
||||
});
|
||||
|
||||
sinon.spy(component, "observe");
|
||||
sinon.stub(component, "updatePanel");
|
||||
|
||||
component.init();
|
||||
SyncedTabs.syncTabs.restore();
|
||||
Assert.ok(component.updatePanel.called, "triggers panel update during init");
|
||||
|
||||
Services.obs.notifyObservers(null, SyncedTabs.TOPIC_TABS_CHANGED, "");
|
||||
|
||||
Assert.ok(component.observe.calledWith(null, SyncedTabs.TOPIC_TABS_CHANGED, ""),
|
||||
"component is notified");
|
||||
|
||||
Assert.ok(listStore.getData.called, "gets list data");
|
||||
Assert.ok(component.updatePanel.calledTwice, "triggers panel update");
|
||||
|
||||
Services.obs.notifyObservers(null, FxAccountsCommon.ONLOGIN_NOTIFICATION, "");
|
||||
|
||||
Assert.ok(component.observe.calledWith(null, FxAccountsCommon.ONLOGIN_NOTIFICATION, ""),
|
||||
"component is notified of login");
|
||||
Assert.equal(component.updatePanel.callCount, 3, "triggers panel update again");
|
||||
});
|
||||
|
||||
add_task(function* testPanelStatus() {
|
||||
let deckStore = new SyncedTabsDeckStore();
|
||||
let listStore = new SyncedTabsListStore();
|
||||
let listComponent = {};
|
||||
let fxAccounts = {
|
||||
accountStatus() {}
|
||||
};
|
||||
let SyncedTabsMock = {
|
||||
getTabClients() {}
|
||||
};
|
||||
|
||||
sinon.stub(listStore, "getData");
|
||||
|
||||
|
||||
let component = new SyncedTabsDeckComponent({
|
||||
fxAccounts,
|
||||
deckStore,
|
||||
listComponent,
|
||||
SyncedTabs: SyncedTabsMock,
|
||||
});
|
||||
|
||||
let isAuthed = false;
|
||||
sinon.stub(fxAccounts, "accountStatus", () => Promise.resolve(isAuthed));
|
||||
let result = yield component.getPanelStatus();
|
||||
Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
|
||||
|
||||
isAuthed = true;
|
||||
|
||||
SyncedTabsMock.isConfiguredToSyncTabs = false;
|
||||
result = yield component.getPanelStatus();
|
||||
Assert.equal(result, component.PANELS.TABS_DISABLED);
|
||||
|
||||
SyncedTabsMock.isConfiguredToSyncTabs = true;
|
||||
|
||||
SyncedTabsMock.hasSyncedThisSession = false;
|
||||
result = yield component.getPanelStatus();
|
||||
Assert.equal(result, component.PANELS.TABS_FETCHING);
|
||||
|
||||
SyncedTabsMock.hasSyncedThisSession = true;
|
||||
|
||||
let clients = [];
|
||||
sinon.stub(SyncedTabsMock, "getTabClients", () => Promise.resolve(clients));
|
||||
result = yield component.getPanelStatus();
|
||||
Assert.equal(result, component.PANELS.SINGLE_DEVICE_INFO);
|
||||
|
||||
clients = ["mock-client"];
|
||||
result = yield component.getPanelStatus();
|
||||
Assert.equal(result, component.PANELS.TABS_CONTAINER);
|
||||
|
||||
fxAccounts.accountStatus.restore();
|
||||
sinon.stub(fxAccounts, "accountStatus", () => Promise.reject("err"));
|
||||
result = yield component.getPanelStatus();
|
||||
Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
|
||||
|
||||
sinon.stub(component, "getPanelStatus", () => Promise.resolve("mock-panelId"));
|
||||
sinon.spy(deckStore, "selectPanel");
|
||||
yield component.updatePanel();
|
||||
Assert.ok(deckStore.selectPanel.calledWith("mock-panelId"));
|
||||
});
|
||||
|
||||
add_task(function* testActions() {
|
||||
let windowMock = {
|
||||
openUILink() {},
|
||||
};
|
||||
let chromeWindowMock = {
|
||||
gSyncUI: {
|
||||
openSetup() {}
|
||||
}
|
||||
};
|
||||
sinon.spy(windowMock, "openUILink");
|
||||
sinon.spy(chromeWindowMock.gSyncUI, "openSetup");
|
||||
|
||||
let getChromeWindowMock = sinon.stub();
|
||||
getChromeWindowMock.returns(chromeWindowMock);
|
||||
|
||||
let component = new SyncedTabsDeckComponent({
|
||||
window: windowMock,
|
||||
getChromeWindowMock
|
||||
});
|
||||
|
||||
let href = Services.prefs.getCharPref("identity.mobilepromo.android") + "synced-tabs-sidebar";
|
||||
component.openAndroidLink("mock-event");
|
||||
Assert.ok(windowMock.openUILink.calledWith(href, "mock-event"));
|
||||
|
||||
href = Services.prefs.getCharPref("identity.mobilepromo.ios") + "synced-tabs-sidebar";
|
||||
component.openiOSLink("mock-event");
|
||||
Assert.ok(windowMock.openUILink.calledWith(href, "mock-event"));
|
||||
|
||||
component.openSyncPrefs();
|
||||
Assert.ok(getChromeWindowMock.calledWith(windowMock));
|
||||
Assert.ok(chromeWindowMock.gSyncUI.openSetup.called);
|
||||
});
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
let { SyncedTabsDeckStore } = Cu.import("resource:///modules/syncedtabs/SyncedTabsDeckStore.js", {});
|
||||
|
||||
add_task(function* testSelectUnkownPanel() {
|
||||
let deckStore = new SyncedTabsDeckStore();
|
||||
let spy = sinon.spy();
|
||||
|
||||
deckStore.on("change", spy);
|
||||
deckStore.selectPanel("foo");
|
||||
|
||||
Assert.ok(!spy.called);
|
||||
});
|
||||
|
||||
add_task(function* testSetPanels() {
|
||||
let deckStore = new SyncedTabsDeckStore();
|
||||
let spy = sinon.spy();
|
||||
|
||||
deckStore.on("change", spy);
|
||||
deckStore.setPanels(["panel1", "panel2"]);
|
||||
|
||||
Assert.ok(spy.calledWith({
|
||||
panels: [
|
||||
{ id: "panel1", selected: false },
|
||||
{ id: "panel2", selected: false },
|
||||
],
|
||||
isUpdatable: false
|
||||
}));
|
||||
});
|
||||
|
||||
add_task(function* testSelectPanel() {
|
||||
let deckStore = new SyncedTabsDeckStore();
|
||||
let spy = sinon.spy();
|
||||
|
||||
deckStore.setPanels(["panel1", "panel2"]);
|
||||
|
||||
deckStore.on("change", spy);
|
||||
deckStore.selectPanel("panel2");
|
||||
|
||||
Assert.ok(spy.calledWith({
|
||||
panels: [
|
||||
{ id: "panel1", selected: false },
|
||||
{ id: "panel2", selected: true },
|
||||
],
|
||||
isUpdatable: true
|
||||
}));
|
||||
|
||||
deckStore.selectPanel("panel2");
|
||||
Assert.ok(spy.calledOnce, "doesn't trigger unless panel changes");
|
||||
});
|
||||
|
||||
add_task(function* testSetPanelsSameArray() {
|
||||
let deckStore = new SyncedTabsDeckStore();
|
||||
let spy = sinon.spy();
|
||||
deckStore.on("change", spy);
|
||||
|
||||
let panels = ["panel1", "panel2"];
|
||||
|
||||
deckStore.setPanels(panels);
|
||||
deckStore.setPanels(panels);
|
||||
|
||||
Assert.ok(spy.calledOnce, "doesn't trigger unless set of panels changes");
|
||||
});
|
||||
|
||||
|
|
@ -1,266 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
let { SyncedTabs } = Cu.import("resource://services-sync/SyncedTabs.jsm", {});
|
||||
let { SyncedTabsListStore } = Cu.import("resource:///modules/syncedtabs/SyncedTabsListStore.js", {});
|
||||
|
||||
const FIXTURE = [
|
||||
{
|
||||
"id": "2xU5h-4bkWqA",
|
||||
"type": "client",
|
||||
"name": "laptop",
|
||||
"isMobile": false,
|
||||
"tabs": [
|
||||
{
|
||||
"type": "tab",
|
||||
"title": "Firefox for iOS — Mobile Web browser for your iPhone, iPad and iPod touch — Mozilla",
|
||||
"url": "https://www.mozilla.org/en-US/firefox/ios/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=synced-tabs-sidebar",
|
||||
"icon": "moz-anno:favicon:https://www.mozilla.org/media/img/firefox/favicon.dc6635050bf5.ico",
|
||||
"client": "2xU5h-4bkWqA",
|
||||
"lastUsed": 1451519425
|
||||
},
|
||||
{
|
||||
"type": "tab",
|
||||
"title": "Firefox Nightly First Run Page",
|
||||
"url": "https://www.mozilla.org/en-US/firefox/nightly/firstrun/?oldversion=45.0a1",
|
||||
"icon": "moz-anno:favicon:https://www.mozilla.org/media/img/firefox/favicon-nightly.560395bbb2e1.png",
|
||||
"client": "2xU5h-4bkWqA",
|
||||
"lastUsed": 1451519420
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "OL3EJCsdb2JD",
|
||||
"type": "client",
|
||||
"name": "desktop",
|
||||
"isMobile": false,
|
||||
"tabs": []
|
||||
}
|
||||
];
|
||||
|
||||
add_task(function* testGetDataEmpty() {
|
||||
let store = new SyncedTabsListStore(SyncedTabs);
|
||||
let spy = sinon.spy();
|
||||
|
||||
sinon.stub(SyncedTabs, "getTabClients", () => {
|
||||
return Promise.resolve([]);
|
||||
});
|
||||
store.on("change", spy);
|
||||
|
||||
yield store.getData();
|
||||
|
||||
Assert.ok(SyncedTabs.getTabClients.calledWith(""));
|
||||
Assert.ok(spy.calledWith({
|
||||
clients: [],
|
||||
canUpdateAll: false,
|
||||
canUpdateInput: false,
|
||||
filter: "",
|
||||
inputFocused: false
|
||||
}));
|
||||
|
||||
yield store.getData("filter");
|
||||
|
||||
Assert.ok(SyncedTabs.getTabClients.calledWith("filter"));
|
||||
Assert.ok(spy.calledWith({
|
||||
clients: [],
|
||||
canUpdateAll: false,
|
||||
canUpdateInput: true,
|
||||
filter: "filter",
|
||||
inputFocused: false
|
||||
}));
|
||||
|
||||
SyncedTabs.getTabClients.restore();
|
||||
});
|
||||
|
||||
add_task(function* testRowSelectionWithoutFilter() {
|
||||
let store = new SyncedTabsListStore(SyncedTabs);
|
||||
let spy = sinon.spy();
|
||||
|
||||
sinon.stub(SyncedTabs, "getTabClients", () => {
|
||||
return Promise.resolve(FIXTURE);
|
||||
});
|
||||
|
||||
yield store.getData();
|
||||
SyncedTabs.getTabClients.restore();
|
||||
|
||||
store.on("change", spy);
|
||||
|
||||
store.selectRow(0, -1);
|
||||
Assert.ok(spy.args[0][0].canUpdateAll, "can update the whole view");
|
||||
Assert.ok(spy.args[0][0].clients[0].selected, "first client is selected");
|
||||
|
||||
store.moveSelectionUp();
|
||||
Assert.ok(spy.calledOnce,
|
||||
"can't move up past first client, no change triggered");
|
||||
|
||||
store.selectRow(0, 0);
|
||||
Assert.ok(spy.args[1][0].clients[0].tabs[0].selected,
|
||||
"first tab of first client is selected");
|
||||
|
||||
store.selectRow(0, 0);
|
||||
Assert.ok(spy.calledTwice, "selecting same row doesn't trigger change");
|
||||
|
||||
store.selectRow(0, 1);
|
||||
Assert.ok(spy.args[2][0].clients[0].tabs[1].selected,
|
||||
"second tab of first client is selected");
|
||||
|
||||
store.selectRow(1);
|
||||
Assert.ok(spy.args[3][0].clients[1].selected, "second client is selected");
|
||||
|
||||
store.moveSelectionDown();
|
||||
Assert.equal(spy.callCount, 4,
|
||||
"can't move selection down past last client, no change triggered");
|
||||
|
||||
store.moveSelectionUp();
|
||||
Assert.equal(spy.callCount, 5,
|
||||
"changed");
|
||||
Assert.ok(spy.args[4][0].clients[0].tabs[FIXTURE[0].tabs.length - 1].selected,
|
||||
"move selection up from client selects last tab of previous client");
|
||||
|
||||
store.moveSelectionUp();
|
||||
Assert.ok(spy.args[5][0].clients[0].tabs[FIXTURE[0].tabs.length - 2].selected,
|
||||
"move selection up from tab selects previous tab of client");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* testToggleBranches() {
|
||||
let store = new SyncedTabsListStore(SyncedTabs);
|
||||
let spy = sinon.spy();
|
||||
|
||||
sinon.stub(SyncedTabs, "getTabClients", () => {
|
||||
return Promise.resolve(FIXTURE);
|
||||
});
|
||||
|
||||
yield store.getData();
|
||||
SyncedTabs.getTabClients.restore();
|
||||
|
||||
store.selectRow(0);
|
||||
store.on("change", spy);
|
||||
|
||||
let clientId = FIXTURE[0].id;
|
||||
store.closeBranch(clientId);
|
||||
Assert.ok(spy.args[0][0].clients[0].closed, "first client is closed");
|
||||
|
||||
store.openBranch(clientId);
|
||||
Assert.ok(!spy.args[1][0].clients[0].closed, "first client is open");
|
||||
|
||||
store.toggleBranch(clientId);
|
||||
Assert.ok(spy.args[2][0].clients[0].closed, "first client is toggled closed");
|
||||
|
||||
store.moveSelectionDown();
|
||||
Assert.ok(spy.args[3][0].clients[1].selected,
|
||||
"selection skips tabs if client is closed");
|
||||
|
||||
store.moveSelectionUp();
|
||||
Assert.ok(spy.args[4][0].clients[0].selected,
|
||||
"selection skips tabs if client is closed");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* testRowSelectionWithFilter() {
|
||||
let store = new SyncedTabsListStore(SyncedTabs);
|
||||
let spy = sinon.spy();
|
||||
|
||||
sinon.stub(SyncedTabs, "getTabClients", () => {
|
||||
return Promise.resolve(FIXTURE);
|
||||
});
|
||||
|
||||
yield store.getData("filter");
|
||||
SyncedTabs.getTabClients.restore();
|
||||
|
||||
store.on("change", spy);
|
||||
|
||||
store.selectRow(0);
|
||||
Assert.ok(spy.args[0][0].clients[0].tabs[0].selected, "first tab is selected");
|
||||
|
||||
store.moveSelectionUp();
|
||||
Assert.ok(spy.calledOnce,
|
||||
"can't move up past first tab, no change triggered");
|
||||
|
||||
store.moveSelectionDown();
|
||||
Assert.ok(spy.args[1][0].clients[0].tabs[1].selected,
|
||||
"selection skips tabs if client is closed");
|
||||
|
||||
store.moveSelectionDown();
|
||||
Assert.equal(spy.callCount, 2,
|
||||
"can't move selection down past last tab, no change triggered");
|
||||
|
||||
store.selectRow(1);
|
||||
Assert.equal(spy.callCount, 2,
|
||||
"doesn't trigger change if same row selected");
|
||||
|
||||
});
|
||||
|
||||
|
||||
add_task(function* testFilterAndClearFilter() {
|
||||
let store = new SyncedTabsListStore(SyncedTabs);
|
||||
let spy = sinon.spy();
|
||||
|
||||
sinon.stub(SyncedTabs, "getTabClients", () => {
|
||||
return Promise.resolve(FIXTURE);
|
||||
});
|
||||
store.on("change", spy);
|
||||
|
||||
yield store.getData("filter");
|
||||
|
||||
Assert.ok(SyncedTabs.getTabClients.calledWith("filter"));
|
||||
Assert.ok(!spy.args[0][0].canUpdateAll, "can't update all");
|
||||
Assert.ok(spy.args[0][0].canUpdateInput, "can update just input");
|
||||
|
||||
store.selectRow(0);
|
||||
|
||||
Assert.equal(spy.args[1][0].filter, "filter");
|
||||
Assert.ok(spy.args[1][0].clients[0].tabs[0].selected,
|
||||
"tab is selected");
|
||||
|
||||
yield store.clearFilter();
|
||||
|
||||
Assert.ok(SyncedTabs.getTabClients.calledWith(""));
|
||||
Assert.ok(!spy.args[2][0].canUpdateAll, "can't update all");
|
||||
Assert.ok(!spy.args[2][0].canUpdateInput, "can't just update input");
|
||||
|
||||
Assert.equal(spy.args[2][0].filter, "");
|
||||
Assert.ok(!spy.args[2][0].clients[0].tabs[0].selected,
|
||||
"tab is no longer selected");
|
||||
|
||||
SyncedTabs.getTabClients.restore();
|
||||
});
|
||||
|
||||
add_task(function* testFocusBlurInput() {
|
||||
let store = new SyncedTabsListStore(SyncedTabs);
|
||||
let spy = sinon.spy();
|
||||
|
||||
sinon.stub(SyncedTabs, "getTabClients", () => {
|
||||
return Promise.resolve(FIXTURE);
|
||||
});
|
||||
store.on("change", spy);
|
||||
|
||||
yield store.getData();
|
||||
SyncedTabs.getTabClients.restore();
|
||||
|
||||
Assert.ok(!spy.args[0][0].canUpdateAll, "must rerender all");
|
||||
|
||||
store.selectRow(0);
|
||||
Assert.ok(!spy.args[1][0].inputFocused,
|
||||
"input is not focused");
|
||||
Assert.ok(spy.args[1][0].clients[0].selected,
|
||||
"client is selected");
|
||||
Assert.ok(spy.args[1][0].clients[0].focused,
|
||||
"client is focused");
|
||||
|
||||
store.focusInput();
|
||||
Assert.ok(spy.args[2][0].inputFocused,
|
||||
"input is focused");
|
||||
Assert.ok(spy.args[2][0].clients[0].selected,
|
||||
"client is still selected");
|
||||
Assert.ok(!spy.args[2][0].clients[0].focused,
|
||||
"client is no longer focused");
|
||||
|
||||
store.blurInput();
|
||||
Assert.ok(!spy.args[3][0].inputFocused,
|
||||
"input is not focused");
|
||||
Assert.ok(spy.args[3][0].clients[0].selected,
|
||||
"client is selected");
|
||||
Assert.ok(spy.args[3][0].clients[0].focused,
|
||||
"client is focused");
|
||||
});
|
||||
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
let { SyncedTabs } = Cu.import("resource://services-sync/SyncedTabs.jsm", {});
|
||||
let { TabListComponent } = Cu.import("resource:///modules/syncedtabs/TabListComponent.js", {});
|
||||
let { SyncedTabsListStore } = Cu.import("resource:///modules/syncedtabs/SyncedTabsListStore.js", {});
|
||||
let { View } = Cu.import("resource:///modules/syncedtabs/TabListView.js", {});
|
||||
|
||||
const ACTION_METHODS = [
|
||||
"onSelectRow",
|
||||
"onOpenTab",
|
||||
"onOpenTabs",
|
||||
"onMoveSelectionDown",
|
||||
"onMoveSelectionUp",
|
||||
"onToggleBranch",
|
||||
"onBookmarkTab",
|
||||
"onSyncRefresh",
|
||||
"onFilter",
|
||||
"onClearFilter",
|
||||
"onFilterFocus",
|
||||
"onFilterBlur",
|
||||
];
|
||||
|
||||
add_task(function* testInitUninit() {
|
||||
let store = new SyncedTabsListStore();
|
||||
let ViewMock = sinon.stub();
|
||||
let view = {render() {}, destroy() {}};
|
||||
|
||||
ViewMock.returns(view);
|
||||
|
||||
sinon.spy(view, 'render');
|
||||
sinon.spy(view, 'destroy');
|
||||
|
||||
sinon.spy(store, "on");
|
||||
sinon.stub(store, "getData");
|
||||
sinon.stub(store, "focusInput");
|
||||
|
||||
let component = new TabListComponent({window, store, View: ViewMock, SyncedTabs});
|
||||
|
||||
for (let action of ACTION_METHODS) {
|
||||
sinon.stub(component, action);
|
||||
}
|
||||
|
||||
component.init();
|
||||
|
||||
Assert.ok(ViewMock.calledWithNew(), "view is instantiated");
|
||||
Assert.ok(store.on.calledOnce, "listener is added to store");
|
||||
Assert.equal(store.on.args[0][0], "change");
|
||||
Assert.ok(view.render.calledWith({clients: []}),
|
||||
"render is called on view instance");
|
||||
Assert.ok(store.getData.calledOnce, "store gets initial data");
|
||||
Assert.ok(store.focusInput.calledOnce, "input field is focused");
|
||||
|
||||
for (let method of ACTION_METHODS) {
|
||||
let action = ViewMock.args[0][1][method];
|
||||
Assert.ok(action, method + " action is passed to View");
|
||||
action("foo", "bar");
|
||||
Assert.ok(component[method].calledWith("foo", "bar"),
|
||||
method + " action passed to View triggers the component method with args");
|
||||
}
|
||||
|
||||
store.emit("change", "mock state");
|
||||
Assert.ok(view.render.secondCall.calledWith("mock state"),
|
||||
"view.render is called on state change");
|
||||
|
||||
component.uninit();
|
||||
Assert.ok(view.destroy.calledOnce, "view is destroyed on uninit");
|
||||
});
|
||||
|
||||
add_task(function* testActions() {
|
||||
let store = new SyncedTabsListStore();
|
||||
let chromeWindowMock = {
|
||||
gBrowser: {
|
||||
loadTabs() {},
|
||||
},
|
||||
};
|
||||
let getChromeWindowMock = sinon.stub();
|
||||
getChromeWindowMock.returns(chromeWindowMock);
|
||||
let clipboardHelperMock = {
|
||||
copyString() {},
|
||||
};
|
||||
let windowMock = {
|
||||
top: {
|
||||
PlacesCommandHook: {
|
||||
bookmarkLink() { return Promise.resolve(); }
|
||||
},
|
||||
PlacesUtils: { bookmarksMenuFolderId: "id" }
|
||||
},
|
||||
getBrowserURL() {},
|
||||
openDialog() {},
|
||||
openUILinkIn() {}
|
||||
};
|
||||
let component = new TabListComponent({
|
||||
window: windowMock, store, View: null, SyncedTabs,
|
||||
clipboardHelper: clipboardHelperMock,
|
||||
getChromeWindow: getChromeWindowMock });
|
||||
|
||||
sinon.stub(store, "getData");
|
||||
component.onFilter("query");
|
||||
Assert.ok(store.getData.calledWith("query"));
|
||||
|
||||
sinon.stub(store, "clearFilter");
|
||||
component.onClearFilter();
|
||||
Assert.ok(store.clearFilter.called);
|
||||
|
||||
sinon.stub(store, "focusInput");
|
||||
component.onFilterFocus();
|
||||
Assert.ok(store.focusInput.called);
|
||||
|
||||
sinon.stub(store, "blurInput");
|
||||
component.onFilterBlur();
|
||||
Assert.ok(store.blurInput.called);
|
||||
|
||||
sinon.stub(store, "selectRow");
|
||||
component.onSelectRow([-1, -1]);
|
||||
Assert.ok(store.selectRow.calledWith(-1, -1));
|
||||
|
||||
sinon.stub(store, "moveSelectionDown");
|
||||
component.onMoveSelectionDown();
|
||||
Assert.ok(store.moveSelectionDown.called);
|
||||
|
||||
sinon.stub(store, "moveSelectionUp");
|
||||
component.onMoveSelectionUp();
|
||||
Assert.ok(store.moveSelectionUp.called);
|
||||
|
||||
sinon.stub(store, "toggleBranch");
|
||||
component.onToggleBranch("foo-id");
|
||||
Assert.ok(store.toggleBranch.calledWith("foo-id"));
|
||||
|
||||
sinon.spy(windowMock.top.PlacesCommandHook, "bookmarkLink");
|
||||
component.onBookmarkTab("uri", "title");
|
||||
Assert.equal(windowMock.top.PlacesCommandHook.bookmarkLink.args[0][1], "uri");
|
||||
Assert.equal(windowMock.top.PlacesCommandHook.bookmarkLink.args[0][2], "title");
|
||||
|
||||
sinon.spy(windowMock, "openUILinkIn");
|
||||
component.onOpenTab("uri", "where", "params");
|
||||
Assert.ok(windowMock.openUILinkIn.calledWith("uri", "where", "params"));
|
||||
|
||||
sinon.spy(chromeWindowMock.gBrowser, "loadTabs");
|
||||
let tabsToOpen = ["uri1", "uri2"];
|
||||
component.onOpenTabs(tabsToOpen, "where");
|
||||
Assert.ok(getChromeWindowMock.calledWith(windowMock));
|
||||
Assert.ok(chromeWindowMock.gBrowser.loadTabs.calledWith(tabsToOpen, false, false));
|
||||
component.onOpenTabs(tabsToOpen, "tabshifted");
|
||||
Assert.ok(chromeWindowMock.gBrowser.loadTabs.calledWith(tabsToOpen, true, false));
|
||||
|
||||
sinon.spy(clipboardHelperMock, "copyString");
|
||||
component.onCopyTabLocation("uri");
|
||||
Assert.ok(clipboardHelperMock.copyString.calledWith("uri"));
|
||||
|
||||
sinon.stub(SyncedTabs, "syncTabs");
|
||||
component.onSyncRefresh();
|
||||
Assert.ok(SyncedTabs.syncTabs.calledWith(true));
|
||||
SyncedTabs.syncTabs.restore();
|
||||
});
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
[DEFAULT]
|
||||
head = head.js
|
||||
tail =
|
||||
firefox-appdir = browser
|
||||
|
||||
[test_EventEmitter.js]
|
||||
[test_SyncedTabsDeckStore.js]
|
||||
[test_SyncedTabsListStore.js]
|
||||
[test_SyncedTabsDeckComponent.js]
|
||||
[test_TabListComponent.js]
|
||||
Loading…
Add table
Add a link
Reference in a new issue