test_TaskbarTabsRegistry.js (11560B)
1 /* vim: set ts=2 sw=2 sts=2 et : */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 "use strict"; 7 8 const { TaskbarTabsRegistry, TaskbarTabsRegistryStorage } = 9 ChromeUtils.importESModule( 10 "resource:///modules/taskbartabs/TaskbarTabsRegistry.sys.mjs" 11 ); 12 13 function testFile() { 14 let path = do_get_tempdir(); 15 let filename = Services.uuid.generateUUID().toString().slice(1, -1); 16 path.append(filename + ".json"); 17 18 registerCleanupFunction(() => { 19 if (path.exists()) { 20 path.remove(false); 21 } 22 }); 23 24 return path; 25 } 26 27 add_task(async function test_create_taskbar_tab() { 28 const url = Services.io.newURI("https://www.test.com/start"); 29 const userContextId = 0; // Default container. 30 31 const registry = new TaskbarTabsRegistry(); 32 33 Assert.ok( 34 !registry.findTaskbarTab(url, userContextId), 35 "Initially, no Taskbar Tab should exist for the given URL and container." 36 ); 37 38 const taskbarTab = createTaskbarTab(registry, url, userContextId); 39 40 Assert.ok(taskbarTab, "Taskbar Tab should be created."); 41 Assert.deepEqual( 42 registry.findTaskbarTab(url, userContextId), 43 taskbarTab, 44 "Found Taskbar Tab should match the one returned on creation." 45 ); 46 47 const secondUrl = Services.io.newURI("https://www.another-test.com/start"); 48 const secondUserContextId = 1; 49 const secondTaskbarTab = createTaskbarTab( 50 registry, 51 secondUrl, 52 secondUserContextId 53 ); 54 Assert.deepEqual( 55 registry.findTaskbarTab(url, userContextId), 56 taskbarTab, 57 "First Taskbar Tab created should still be present." 58 ); 59 Assert.deepEqual( 60 registry.findTaskbarTab(secondUrl, secondUserContextId), 61 secondTaskbarTab, 62 "Second Taskbar Tab created should still be present." 63 ); 64 65 const repeated = registry.findOrCreateTaskbarTab( 66 secondUrl, 67 secondUserContextId 68 ); 69 Assert.equal( 70 repeated.created, 71 false, 72 "The existing taskbar tab should have been found, not created" 73 ); 74 Assert.deepEqual( 75 repeated.taskbarTab, 76 secondTaskbarTab, 77 "Should have found the second created Taskbar Tab instead of creating a new Taskbar Tab." 78 ); 79 }); 80 81 add_task(async function test_remove_taskbar_tab() { 82 const url = Services.io.newURI("https://www.test.com/start"); 83 const userContextId = 0; 84 85 const registry = new TaskbarTabsRegistry(); 86 const taskbarTab = createTaskbarTab(registry, url, userContextId); 87 88 Assert.deepEqual( 89 registry.findTaskbarTab(url, userContextId), 90 taskbarTab, 91 "Taskbar Tab ID should match the ID returned on creation." 92 ); 93 94 Assert.deepEqual( 95 registry.removeTaskbarTab(taskbarTab.id), 96 taskbarTab, 97 "The removed Taskbar Tab was removed" 98 ); 99 100 Assert.ok( 101 !registry.findTaskbarTab(url, userContextId), 102 "Taskbar Tab ID should be removed." 103 ); 104 105 Assert.strictEqual( 106 registry.removeTaskbarTab(taskbarTab.id), 107 null, 108 "Null was returned since no Taskbar Tab with that ID exists" 109 ); 110 }); 111 112 add_task(async function test_container_mismatch() { 113 const url = Services.io.newURI("https://www.test.com/start"); 114 const userContextId = 0; 115 const mismatchedUserContextId = 1; 116 117 const registry = new TaskbarTabsRegistry(); 118 const taskbarTab = createTaskbarTab(registry, url, userContextId); 119 Assert.ok(taskbarTab, "Taskbar Tab ID should be created."); 120 121 Assert.ok( 122 !registry.findTaskbarTab(url, mismatchedUserContextId), 123 `${mismatchedUserContextId} should not match a Taskbar Tab created with container ${userContextId}.` 124 ); 125 }); 126 127 add_task(async function test_scope_navigable() { 128 const url = Services.io.newURI("https://www.test.com/start"); 129 const validNavigationDomain = Services.io.newURI("https://www.test.com/test"); 130 const validNavigationSubdomain = Services.io.newURI( 131 "https://www.subdomain.test.com" 132 ); 133 const invalidNavigationDomain = Services.io.newURI( 134 "https://www.anothertest.com" 135 ); 136 const userContextId = 0; 137 138 const registry = new TaskbarTabsRegistry(); 139 const taskbarTab = createTaskbarTab(registry, url, userContextId); 140 141 Assert.ok( 142 taskbarTab.isScopeNavigable(validNavigationDomain), 143 `${validNavigationDomain} should be a valid navigation target for ${taskbarTab.scopes[0].hostname}.` 144 ); 145 146 Assert.ok( 147 taskbarTab.isScopeNavigable(validNavigationSubdomain), 148 `${validNavigationSubdomain} should be a valid navigation target for ${taskbarTab.scopes[0].hostname}.` 149 ); 150 Assert.ok( 151 !taskbarTab.isScopeNavigable(invalidNavigationDomain), 152 `${invalidNavigationDomain} should be a valid navigation target for ${taskbarTab.scopes[0].hostname}.` 153 ); 154 }); 155 156 add_task(async function test_psl_navigable() { 157 const url = Services.io.newURI("https://www.bmoattachments.org/start"); 158 const invalidNavigationPublicSuffixList = Services.io.newURI( 159 "https://www.invalid.bmoattachments.org" 160 ); 161 const userContextId = 0; 162 163 const registry = new TaskbarTabsRegistry(); 164 const taskbarTab = createTaskbarTab(registry, url, userContextId); 165 166 Assert.ok( 167 !taskbarTab.isScopeNavigable(invalidNavigationPublicSuffixList), 168 `bmoattachments.org is on the Public Suffix List, therefore ${invalidNavigationPublicSuffixList} should not be a valid navigation target for ${taskbarTab.scopes[0].hostname}.` 169 ); 170 }); 171 172 add_task(async function test_save_and_load_consistency() { 173 const url = Services.io.newURI("https://www.test.com/start"); 174 const userContextId = 0; 175 176 let saveRegistry = new TaskbarTabsRegistry(); 177 const saveTaskbarTab = createTaskbarTab(saveRegistry, url, userContextId); 178 179 let file = testFile(); 180 let storage = new TaskbarTabsRegistryStorage(saveRegistry, file); 181 await storage.save(); 182 183 const loadRegistry = await TaskbarTabsRegistry.create({ loadFile: file }); 184 let loadTaskbarTab = loadRegistry.getTaskbarTab(saveTaskbarTab.id); 185 186 Assert.deepEqual( 187 saveTaskbarTab, 188 loadTaskbarTab, 189 "Taskbar Tab object should be identical after save and load." 190 ); 191 }); 192 193 add_task(async function test_load_and_save_consistency() { 194 const loadFile = do_get_file("test_taskbarTabs.json"); 195 196 // Test loading from the mock file 197 const registry = await TaskbarTabsRegistry.create({ loadFile }); 198 Assert.equal( 199 registry.findTaskbarTab(Services.io.newURI("https://www.test.com"), 0).id, 200 "4186657a-0fe5-492a-af64-dc628c232c4c", 201 "Taskbar Tab ID should match the one in the test JSON file." 202 ); 203 204 // Test saving to a new file 205 let file = testFile(); 206 let storage = new TaskbarTabsRegistryStorage(registry, file); 207 await storage.save(); 208 209 // Verify the output against the original file on disk. 210 const originalData = await IOUtils.readJSON(loadFile.path); 211 const outputData = await IOUtils.readJSON(file.path); 212 213 // Even though the Taskbar Tabs are kept in a map, entries remember their 214 // insertion orders. 215 Assert.deepEqual( 216 outputData, 217 originalData, 218 "The in-memory mock file output should match the original file on disk." 219 ); 220 }); 221 222 add_task(async function test_load_and_save_migrates_name() { 223 const loadFile = do_get_file("test_taskbarTabs_nonames.json"); 224 225 const registry = await TaskbarTabsRegistry.create({ loadFile }); 226 const tt = registry.findTaskbarTab( 227 Services.io.newURI("https://www.test.com"), 228 0 229 ); 230 equal( 231 tt.id, 232 "4186657a-0fe5-492a-af64-dc628c232c4c", 233 "Taskbar Tab ID should match the one in the test JSON file." 234 ); 235 236 equal(typeof tt.name, "string", "A name should be present in-memory."); 237 238 let file = testFile(); 239 let storage = new TaskbarTabsRegistryStorage(registry, file); 240 await storage.save(); 241 242 const outputData = await IOUtils.readJSON(file.path); 243 equal( 244 typeof outputData.taskbarTabs[0].name, 245 "string", 246 "A name should be saved to storage." 247 ); 248 }); 249 250 add_task(async function test_guards_against_commandline_strings() { 251 const validUrl = Services.io.newURI("https://www.test.com/start"); 252 const invalidUrl = "https://www.test.com/start"; 253 254 const validUserContextId = 0; 255 const invalidUserContextId = "0"; 256 257 const registry = new TaskbarTabsRegistry(); 258 259 Assert.throws( 260 () => registry.findTaskbarTab(invalidUrl, validUserContextId), 261 /Invalid argument, `aUrl` should be instance of `nsIURL`/, 262 "Should reject URLs provided as a string." 263 ); 264 Assert.throws( 265 () => registry.findTaskbarTab(validUrl, invalidUserContextId), 266 /Invalid argument, `aUserContextId` should be type of `number`/, 267 "Should reject userContextId provided as a string." 268 ); 269 }); 270 271 add_task(async function test_guards_against_non_urls() { 272 // about:blank is a URI, but not a URL. 273 const url = Services.io.newURI("about:blank"); 274 const userContextId = 0; 275 276 const registry = new TaskbarTabsRegistry(); 277 278 throws( 279 () => createTaskbarTab(registry, url, userContextId), 280 /Invalid argument, `aUrl` should be instance of `nsIURL`/, 281 "Should reject URIs that are not URLs." 282 ); 283 }); 284 285 add_task(async function test_patch_becomes_visible() { 286 const registry = new TaskbarTabsRegistry(); 287 const tt = createTaskbarTab( 288 registry, 289 Services.io.newURI("https://www.test.com/start"), 290 0 291 ); 292 293 let called = 0; 294 registry.on(TaskbarTabsRegistry.events.patched, () => { 295 called += 1; 296 }); 297 298 Assert.equal( 299 tt.shortcutRelativePath, 300 null, 301 "Should not start with a relative path" 302 ); 303 registry.patchTaskbarTab(tt, { 304 shortcutRelativePath: "some\\path\\string.lnk", 305 }); 306 Assert.equal( 307 tt.shortcutRelativePath, 308 "some\\path\\string.lnk", 309 "Should update to the new value" 310 ); 311 Assert.equal(called, 1, "Should emit the callback function once"); 312 }); 313 314 add_task(async function test_shortcutRelativePath_is_saved() { 315 const registry = new TaskbarTabsRegistry(); 316 const tt = createTaskbarTab( 317 registry, 318 Services.io.newURI("https://www.test.com/start"), 319 0 320 ); 321 322 registry.patchTaskbarTab(tt, { 323 shortcutRelativePath: "some\\path\\string.lnk", 324 }); 325 326 const file = testFile(); 327 const storage = new TaskbarTabsRegistryStorage(registry, file); 328 await storage.save(); 329 330 const data = await IOUtils.readJSON(file.path); 331 Assert.equal( 332 data.taskbarTabs[0].shortcutRelativePath, 333 "some\\path\\string.lnk", 334 "Shortcut relative path should be saved" 335 ); 336 }); 337 338 add_task(async function test_multiple_match_longest_prefix() { 339 const registry = new TaskbarTabsRegistry(); 340 341 const uriWithPrefix = prefix => 342 Services.io.newURI("https://example.com" + prefix); 343 344 const createWithScope = uri => 345 createTaskbarTab(registry, uri, 0, { 346 manifest: { 347 scope: uri.spec, 348 }, 349 }); 350 const find = prefix => registry.findTaskbarTab(uriWithPrefix(prefix), 0); 351 352 // Register them in an arbitrary order. 353 const ttAB = createWithScope(uriWithPrefix("/ab")); 354 const ttA = createWithScope(uriWithPrefix("/a")); 355 const ttABC = createWithScope(uriWithPrefix("/abc")); 356 const ttABCD = createWithScope(uriWithPrefix("/abc/d/")); 357 358 equal(find("/q"), null, "/q does not exist"); 359 equal(find("/a").id, ttA.id, "/a matches /a"); 360 equal(find("/az").id, ttA.id, "/a matches /az"); 361 362 equal(find("/ab").id, ttAB.id, "/ab matches /ab"); 363 equal(find("/abq").id, ttAB.id, "/abq matches /ab"); 364 365 equal(find("/abc").id, ttABC.id, "/abc matches /abc"); 366 equal(find("/abc/").id, ttABC.id, "/abc/ matches /abc"); 367 equal(find("/abc/d").id, ttABC.id, "/abc/d matches /abc (not /abc/d/)"); 368 369 equal(find("/abc/d/").id, ttABCD.id, "/abc/d/ matches /abc/d/"); 370 equal(find("/abc/d/efgh").id, ttABCD.id, "/abc/d/efgh matches /abc/d/"); 371 }).skip(); // TODO bug 2000948