"use strict"; let { SyncedTabs } = ChromeUtils.importESModule( "resource://services-sync/SyncedTabs.sys.mjs" ); let { TabListComponent } = ChromeUtils.importESModule( "resource:///modules/syncedtabs/TabListComponent.sys.mjs" ); let { SyncedTabsListStore } = ChromeUtils.importESModule( "resource:///modules/syncedtabs/SyncedTabsListStore.sys.mjs" ); const ACTION_METHODS = [ "onSelectRow", "onOpenTab", "onOpenTabs", "onMoveSelectionDown", "onMoveSelectionUp", "onToggleBranch", "onBookmarkTab", "onSyncRefresh", "onFilter", "onClearFilter", "onFilterFocus", "onFilterBlur", ]; add_task(async function testInitUninit() { let store = new SyncedTabsListStore(); let ViewMock = sinon.stub(); let view = { render() {}, destroy() {} }; let mockWindow = {}; 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: mockWindow, 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(async 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(); }, }, }, openDialog() {}, openTrustedLinkIn() {}, }; 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][0], "uri"); Assert.equal( windowMock.top.PlacesCommandHook.bookmarkLink.args[0][1], "title" ); sinon.spy(windowMock, "openTrustedLinkIn"); component.onOpenTab("uri", "where", "params"); Assert.ok(windowMock.openTrustedLinkIn.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, { inBackground: false, replace: false, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), }) ); component.onOpenTabs(tabsToOpen, "tabshifted"); Assert.ok( chromeWindowMock.gBrowser.loadTabs.calledWith(tabsToOpen, { inBackground: true, replace: false, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), }) ); 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(); });