test_TabListComponent.js (5239B)
1 "use strict"; 2 3 let { SyncedTabs } = ChromeUtils.importESModule( 4 "resource://services-sync/SyncedTabs.sys.mjs" 5 ); 6 let { TabListComponent } = ChromeUtils.importESModule( 7 "resource:///modules/syncedtabs/TabListComponent.sys.mjs" 8 ); 9 let { SyncedTabsListStore } = ChromeUtils.importESModule( 10 "resource:///modules/syncedtabs/SyncedTabsListStore.sys.mjs" 11 ); 12 13 const ACTION_METHODS = [ 14 "onSelectRow", 15 "onOpenTab", 16 "onOpenTabs", 17 "onMoveSelectionDown", 18 "onMoveSelectionUp", 19 "onToggleBranch", 20 "onBookmarkTab", 21 "onSyncRefresh", 22 "onFilter", 23 "onClearFilter", 24 "onFilterFocus", 25 "onFilterBlur", 26 ]; 27 28 add_task(async function testInitUninit() { 29 let store = new SyncedTabsListStore(); 30 let ViewMock = sinon.stub(); 31 let view = { render() {}, destroy() {} }; 32 let mockWindow = {}; 33 34 ViewMock.returns(view); 35 36 sinon.spy(view, "render"); 37 sinon.spy(view, "destroy"); 38 39 sinon.spy(store, "on"); 40 sinon.stub(store, "getData"); 41 sinon.stub(store, "focusInput"); 42 43 let component = new TabListComponent({ 44 window: mockWindow, 45 store, 46 View: ViewMock, 47 SyncedTabs, 48 }); 49 50 for (let action of ACTION_METHODS) { 51 sinon.stub(component, action); 52 } 53 54 component.init(); 55 56 Assert.ok(ViewMock.calledWithNew(), "view is instantiated"); 57 Assert.ok(store.on.calledOnce, "listener is added to store"); 58 Assert.equal(store.on.args[0][0], "change"); 59 Assert.ok( 60 view.render.calledWith({ clients: [] }), 61 "render is called on view instance" 62 ); 63 Assert.ok(store.getData.calledOnce, "store gets initial data"); 64 Assert.ok(store.focusInput.calledOnce, "input field is focused"); 65 66 for (let method of ACTION_METHODS) { 67 let action = ViewMock.args[0][1][method]; 68 Assert.ok(action, method + " action is passed to View"); 69 action("foo", "bar"); 70 Assert.ok( 71 component[method].calledWith("foo", "bar"), 72 method + " action passed to View triggers the component method with args" 73 ); 74 } 75 76 store.emit("change", "mock state"); 77 Assert.ok( 78 view.render.secondCall.calledWith("mock state"), 79 "view.render is called on state change" 80 ); 81 82 component.uninit(); 83 Assert.ok(view.destroy.calledOnce, "view is destroyed on uninit"); 84 }); 85 86 add_task(async function testActions() { 87 let store = new SyncedTabsListStore(); 88 let chromeWindowMock = { 89 gBrowser: { 90 loadTabs() {}, 91 }, 92 }; 93 let getChromeWindowMock = sinon.stub(); 94 getChromeWindowMock.returns(chromeWindowMock); 95 let clipboardHelperMock = { 96 copyString() {}, 97 }; 98 let windowMock = { 99 top: { 100 PlacesCommandHook: { 101 bookmarkLink() { 102 return Promise.resolve(); 103 }, 104 }, 105 }, 106 openDialog() {}, 107 openTrustedLinkIn() {}, 108 }; 109 let component = new TabListComponent({ 110 window: windowMock, 111 store, 112 View: null, 113 SyncedTabs, 114 clipboardHelper: clipboardHelperMock, 115 getChromeWindow: getChromeWindowMock, 116 }); 117 118 sinon.stub(store, "getData"); 119 component.onFilter("query"); 120 Assert.ok(store.getData.calledWith("query")); 121 122 sinon.stub(store, "clearFilter"); 123 component.onClearFilter(); 124 Assert.ok(store.clearFilter.called); 125 126 sinon.stub(store, "focusInput"); 127 component.onFilterFocus(); 128 Assert.ok(store.focusInput.called); 129 130 sinon.stub(store, "blurInput"); 131 component.onFilterBlur(); 132 Assert.ok(store.blurInput.called); 133 134 sinon.stub(store, "selectRow"); 135 component.onSelectRow([-1, -1]); 136 Assert.ok(store.selectRow.calledWith(-1, -1)); 137 138 sinon.stub(store, "moveSelectionDown"); 139 component.onMoveSelectionDown(); 140 Assert.ok(store.moveSelectionDown.called); 141 142 sinon.stub(store, "moveSelectionUp"); 143 component.onMoveSelectionUp(); 144 Assert.ok(store.moveSelectionUp.called); 145 146 sinon.stub(store, "toggleBranch"); 147 component.onToggleBranch("foo-id"); 148 Assert.ok(store.toggleBranch.calledWith("foo-id")); 149 150 sinon.spy(windowMock.top.PlacesCommandHook, "bookmarkLink"); 151 component.onBookmarkTab("uri", "title"); 152 Assert.equal(windowMock.top.PlacesCommandHook.bookmarkLink.args[0][0], "uri"); 153 Assert.equal( 154 windowMock.top.PlacesCommandHook.bookmarkLink.args[0][1], 155 "title" 156 ); 157 158 sinon.spy(windowMock, "openTrustedLinkIn"); 159 component.onOpenTab("uri", "where", "params"); 160 Assert.ok(windowMock.openTrustedLinkIn.calledWith("uri", "where", "params")); 161 162 sinon.spy(chromeWindowMock.gBrowser, "loadTabs"); 163 let tabsToOpen = ["uri1", "uri2"]; 164 component.onOpenTabs(tabsToOpen, "where"); 165 Assert.ok(getChromeWindowMock.calledWith(windowMock)); 166 Assert.ok( 167 chromeWindowMock.gBrowser.loadTabs.calledWith(tabsToOpen, { 168 inBackground: false, 169 replace: false, 170 triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), 171 }) 172 ); 173 component.onOpenTabs(tabsToOpen, "tabshifted"); 174 Assert.ok( 175 chromeWindowMock.gBrowser.loadTabs.calledWith(tabsToOpen, { 176 inBackground: true, 177 replace: false, 178 triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), 179 }) 180 ); 181 182 sinon.spy(clipboardHelperMock, "copyString"); 183 component.onCopyTabLocation("uri"); 184 Assert.ok(clipboardHelperMock.copyString.calledWith("uri")); 185 186 sinon.stub(SyncedTabs, "syncTabs"); 187 component.onSyncRefresh(); 188 Assert.ok(SyncedTabs.syncTabs.calledWith(true)); 189 SyncedTabs.syncTabs.restore(); 190 });