test_SyncedTabsListStore.js (7900B)
1 "use strict"; 2 3 let { SyncedTabs } = ChromeUtils.importESModule( 4 "resource://services-sync/SyncedTabs.sys.mjs" 5 ); 6 let { SyncedTabsListStore } = ChromeUtils.importESModule( 7 "resource:///modules/syncedtabs/SyncedTabsListStore.sys.mjs" 8 ); 9 10 const FIXTURE = [ 11 { 12 id: "2xU5h-4bkWqA", 13 type: "client", 14 lastModified: 1492201200, 15 name: "laptop", 16 isMobile: false, 17 tabs: [ 18 { 19 type: "tab", 20 title: 21 "Firefox for iOS — Mobile Web browser for your iPhone, iPad and iPod touch — Mozilla", 22 url: "https://www.mozilla.org/en-US/firefox/ios/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=synced-tabs-sidebar", 23 icon: "cached-favicon:https://www.mozilla.org/media/img/firefox/favicon.dc6635050bf5.ico", 24 client: "2xU5h-4bkWqA", 25 lastUsed: 1451519425, 26 }, 27 { 28 type: "tab", 29 title: "Firefox Nightly First Run Page", 30 url: "https://www.mozilla.org/en-US/firefox/nightly/firstrun/?oldversion=45.0a1", 31 icon: "cached-favicon:https://www.mozilla.org/media/img/firefox/favicon-nightly.560395bbb2e1.png", 32 client: "2xU5h-4bkWqA", 33 lastUsed: 1451519420, 34 }, 35 ], 36 }, 37 { 38 id: "OL3EJCsdb2JD", 39 type: "client", 40 lastModified: 1492201200, 41 name: "desktop", 42 isMobile: false, 43 tabs: [], 44 }, 45 ]; 46 47 add_task(async function testGetDataEmpty() { 48 let store = new SyncedTabsListStore(SyncedTabs); 49 let spy = sinon.spy(); 50 51 sinon.stub(SyncedTabs, "getTabClients").callsFake(() => { 52 return Promise.resolve([]); 53 }); 54 store.on("change", spy); 55 56 await store.getData(); 57 58 Assert.ok(SyncedTabs.getTabClients.calledWith("")); 59 Assert.ok( 60 spy.calledWith({ 61 clients: [], 62 canUpdateAll: false, 63 canUpdateInput: false, 64 filter: "", 65 inputFocused: false, 66 }) 67 ); 68 69 await store.getData("filter"); 70 71 Assert.ok(SyncedTabs.getTabClients.calledWith("filter")); 72 Assert.ok( 73 spy.calledWith({ 74 clients: [], 75 canUpdateAll: false, 76 canUpdateInput: true, 77 filter: "filter", 78 inputFocused: false, 79 }) 80 ); 81 82 SyncedTabs.getTabClients.restore(); 83 }); 84 85 add_task(async function testRowSelectionWithoutFilter() { 86 let store = new SyncedTabsListStore(SyncedTabs); 87 let spy = sinon.spy(); 88 89 sinon.stub(SyncedTabs, "getTabClients").callsFake(() => { 90 return Promise.resolve(FIXTURE); 91 }); 92 93 await store.getData(); 94 SyncedTabs.getTabClients.restore(); 95 96 store.on("change", spy); 97 98 store.selectRow(0, -1); 99 Assert.ok(spy.args[0][0].canUpdateAll, "can update the whole view"); 100 Assert.ok(spy.args[0][0].clients[0].selected, "first client is selected"); 101 102 store.moveSelectionUp(); 103 Assert.ok( 104 spy.calledOnce, 105 "can't move up past first client, no change triggered" 106 ); 107 108 store.selectRow(0, 0); 109 Assert.ok( 110 spy.args[1][0].clients[0].tabs[0].selected, 111 "first tab of first client is selected" 112 ); 113 114 store.selectRow(0, 0); 115 Assert.ok(spy.calledTwice, "selecting same row doesn't trigger change"); 116 117 store.selectRow(0, 1); 118 Assert.ok( 119 spy.args[2][0].clients[0].tabs[1].selected, 120 "second tab of first client is selected" 121 ); 122 123 store.selectRow(1); 124 Assert.ok(spy.args[3][0].clients[1].selected, "second client is selected"); 125 126 store.moveSelectionDown(); 127 Assert.equal( 128 spy.callCount, 129 4, 130 "can't move selection down past last client, no change triggered" 131 ); 132 133 store.moveSelectionUp(); 134 Assert.equal(spy.callCount, 5, "changed"); 135 Assert.ok( 136 spy.args[4][0].clients[0].tabs[FIXTURE[0].tabs.length - 1].selected, 137 "move selection up from client selects last tab of previous client" 138 ); 139 140 store.moveSelectionUp(); 141 Assert.ok( 142 spy.args[5][0].clients[0].tabs[FIXTURE[0].tabs.length - 2].selected, 143 "move selection up from tab selects previous tab of client" 144 ); 145 }); 146 147 add_task(async function testToggleBranches() { 148 let store = new SyncedTabsListStore(SyncedTabs); 149 let spy = sinon.spy(); 150 151 sinon.stub(SyncedTabs, "getTabClients").callsFake(() => { 152 return Promise.resolve(FIXTURE); 153 }); 154 155 await store.getData(); 156 SyncedTabs.getTabClients.restore(); 157 158 store.selectRow(0); 159 store.on("change", spy); 160 161 let clientId = FIXTURE[0].id; 162 store.closeBranch(clientId); 163 Assert.ok(spy.args[0][0].clients[0].closed, "first client is closed"); 164 165 store.openBranch(clientId); 166 Assert.ok(!spy.args[1][0].clients[0].closed, "first client is open"); 167 168 store.toggleBranch(clientId); 169 Assert.ok(spy.args[2][0].clients[0].closed, "first client is toggled closed"); 170 171 store.moveSelectionDown(); 172 Assert.ok( 173 spy.args[3][0].clients[1].selected, 174 "selection skips tabs if client is closed" 175 ); 176 177 store.moveSelectionUp(); 178 Assert.ok( 179 spy.args[4][0].clients[0].selected, 180 "selection skips tabs if client is closed" 181 ); 182 }); 183 184 add_task(async function testRowSelectionWithFilter() { 185 let store = new SyncedTabsListStore(SyncedTabs); 186 let spy = sinon.spy(); 187 188 sinon.stub(SyncedTabs, "getTabClients").callsFake(() => { 189 return Promise.resolve(FIXTURE); 190 }); 191 192 await store.getData("filter"); 193 SyncedTabs.getTabClients.restore(); 194 195 store.on("change", spy); 196 197 store.selectRow(0); 198 Assert.ok( 199 spy.args[0][0].clients[0].tabs[0].selected, 200 "first tab is selected" 201 ); 202 203 store.moveSelectionUp(); 204 Assert.ok( 205 spy.calledOnce, 206 "can't move up past first tab, no change triggered" 207 ); 208 209 store.moveSelectionDown(); 210 Assert.ok( 211 spy.args[1][0].clients[0].tabs[1].selected, 212 "selection skips tabs if client is closed" 213 ); 214 215 store.moveSelectionDown(); 216 Assert.equal( 217 spy.callCount, 218 2, 219 "can't move selection down past last tab, no change triggered" 220 ); 221 222 store.selectRow(1); 223 Assert.equal(spy.callCount, 2, "doesn't trigger change if same row selected"); 224 }); 225 226 add_task(async function testFilterAndClearFilter() { 227 let store = new SyncedTabsListStore(SyncedTabs); 228 let spy = sinon.spy(); 229 230 sinon.stub(SyncedTabs, "getTabClients").callsFake(() => { 231 return Promise.resolve(FIXTURE); 232 }); 233 store.on("change", spy); 234 235 await store.getData("filter"); 236 237 Assert.ok(SyncedTabs.getTabClients.calledWith("filter")); 238 Assert.ok(!spy.args[0][0].canUpdateAll, "can't update all"); 239 Assert.ok(spy.args[0][0].canUpdateInput, "can update just input"); 240 241 store.selectRow(0); 242 243 Assert.equal(spy.args[1][0].filter, "filter"); 244 Assert.ok(spy.args[1][0].clients[0].tabs[0].selected, "tab is selected"); 245 246 await store.clearFilter(); 247 248 Assert.ok(SyncedTabs.getTabClients.calledWith("")); 249 Assert.ok(!spy.args[2][0].canUpdateAll, "can't update all"); 250 Assert.ok(!spy.args[2][0].canUpdateInput, "can't just update input"); 251 252 Assert.equal(spy.args[2][0].filter, ""); 253 Assert.ok( 254 !spy.args[2][0].clients[0].tabs[0].selected, 255 "tab is no longer selected" 256 ); 257 258 SyncedTabs.getTabClients.restore(); 259 }); 260 261 add_task(async function testFocusBlurInput() { 262 let store = new SyncedTabsListStore(SyncedTabs); 263 let spy = sinon.spy(); 264 265 sinon.stub(SyncedTabs, "getTabClients").callsFake(() => { 266 return Promise.resolve(FIXTURE); 267 }); 268 store.on("change", spy); 269 270 await store.getData(); 271 SyncedTabs.getTabClients.restore(); 272 273 Assert.ok(!spy.args[0][0].canUpdateAll, "must rerender all"); 274 275 store.selectRow(0); 276 Assert.ok(!spy.args[1][0].inputFocused, "input is not focused"); 277 Assert.ok(spy.args[1][0].clients[0].selected, "client is selected"); 278 Assert.ok(spy.args[1][0].clients[0].focused, "client is focused"); 279 280 store.focusInput(); 281 Assert.ok(spy.args[2][0].inputFocused, "input is focused"); 282 Assert.ok(spy.args[2][0].clients[0].selected, "client is still selected"); 283 Assert.ok(!spy.args[2][0].clients[0].focused, "client is no longer focused"); 284 285 store.blurInput(); 286 Assert.ok(!spy.args[3][0].inputFocused, "input is not focused"); 287 Assert.ok(spy.args[3][0].clients[0].selected, "client is selected"); 288 Assert.ok(spy.args[3][0].clients[0].focused, "client is focused"); 289 });