/* vim: set ts=2 sw=2 sts=2 et : */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const { TaskbarTabsRegistry, TaskbarTabsRegistryStorage } = ChromeUtils.importESModule( "resource:///modules/taskbartabs/TaskbarTabsRegistry.sys.mjs" ); function testFile() { let path = do_get_tempdir(); let filename = Services.uuid.generateUUID().toString().slice(1, -1); path.append(filename + ".json"); registerCleanupFunction(() => { if (path.exists()) { path.remove(false); } }); return path; } add_task(async function test_create_taskbar_tab() { const url = Services.io.newURI("https://www.test.com/start"); const userContextId = 0; // Default container. const registry = new TaskbarTabsRegistry(); Assert.ok( !registry.findTaskbarTab(url, userContextId), "Initially, no Taskbar Tab should exist for the given URL and container." ); const taskbarTab = createTaskbarTab(registry, url, userContextId); Assert.ok(taskbarTab, "Taskbar Tab should be created."); Assert.deepEqual( registry.findTaskbarTab(url, userContextId), taskbarTab, "Found Taskbar Tab should match the one returned on creation." ); const secondUrl = Services.io.newURI("https://www.another-test.com/start"); const secondUserContextId = 1; const secondTaskbarTab = createTaskbarTab( registry, secondUrl, secondUserContextId ); Assert.deepEqual( registry.findTaskbarTab(url, userContextId), taskbarTab, "First Taskbar Tab created should still be present." ); Assert.deepEqual( registry.findTaskbarTab(secondUrl, secondUserContextId), secondTaskbarTab, "Second Taskbar Tab created should still be present." ); const repeated = registry.findOrCreateTaskbarTab( secondUrl, secondUserContextId ); Assert.equal( repeated.created, false, "The existing taskbar tab should have been found, not created" ); Assert.deepEqual( repeated.taskbarTab, secondTaskbarTab, "Should have found the second created Taskbar Tab instead of creating a new Taskbar Tab." ); }); add_task(async function test_remove_taskbar_tab() { const url = Services.io.newURI("https://www.test.com/start"); const userContextId = 0; const registry = new TaskbarTabsRegistry(); const taskbarTab = createTaskbarTab(registry, url, userContextId); Assert.deepEqual( registry.findTaskbarTab(url, userContextId), taskbarTab, "Taskbar Tab ID should match the ID returned on creation." ); Assert.deepEqual( registry.removeTaskbarTab(taskbarTab.id), taskbarTab, "The removed Taskbar Tab was removed" ); Assert.ok( !registry.findTaskbarTab(url, userContextId), "Taskbar Tab ID should be removed." ); Assert.strictEqual( registry.removeTaskbarTab(taskbarTab.id), null, "Null was returned since no Taskbar Tab with that ID exists" ); }); add_task(async function test_container_mismatch() { const url = Services.io.newURI("https://www.test.com/start"); const userContextId = 0; const mismatchedUserContextId = 1; const registry = new TaskbarTabsRegistry(); const taskbarTab = createTaskbarTab(registry, url, userContextId); Assert.ok(taskbarTab, "Taskbar Tab ID should be created."); Assert.ok( !registry.findTaskbarTab(url, mismatchedUserContextId), `${mismatchedUserContextId} should not match a Taskbar Tab created with container ${userContextId}.` ); }); add_task(async function test_scope_navigable() { const url = Services.io.newURI("https://www.test.com/start"); const validNavigationDomain = Services.io.newURI("https://www.test.com/test"); const validNavigationSubdomain = Services.io.newURI( "https://www.subdomain.test.com" ); const invalidNavigationDomain = Services.io.newURI( "https://www.anothertest.com" ); const userContextId = 0; const registry = new TaskbarTabsRegistry(); const taskbarTab = createTaskbarTab(registry, url, userContextId); Assert.ok( taskbarTab.isScopeNavigable(validNavigationDomain), `${validNavigationDomain} should be a valid navigation target for ${taskbarTab.scopes[0].hostname}.` ); Assert.ok( taskbarTab.isScopeNavigable(validNavigationSubdomain), `${validNavigationSubdomain} should be a valid navigation target for ${taskbarTab.scopes[0].hostname}.` ); Assert.ok( !taskbarTab.isScopeNavigable(invalidNavigationDomain), `${invalidNavigationDomain} should be a valid navigation target for ${taskbarTab.scopes[0].hostname}.` ); }); add_task(async function test_psl_navigable() { const url = Services.io.newURI("https://www.bmoattachments.org/start"); const invalidNavigationPublicSuffixList = Services.io.newURI( "https://www.invalid.bmoattachments.org" ); const userContextId = 0; const registry = new TaskbarTabsRegistry(); const taskbarTab = createTaskbarTab(registry, url, userContextId); Assert.ok( !taskbarTab.isScopeNavigable(invalidNavigationPublicSuffixList), `bmoattachments.org is on the Public Suffix List, therefore ${invalidNavigationPublicSuffixList} should not be a valid navigation target for ${taskbarTab.scopes[0].hostname}.` ); }); add_task(async function test_save_and_load_consistency() { const url = Services.io.newURI("https://www.test.com/start"); const userContextId = 0; let saveRegistry = new TaskbarTabsRegistry(); const saveTaskbarTab = createTaskbarTab(saveRegistry, url, userContextId); let file = testFile(); let storage = new TaskbarTabsRegistryStorage(saveRegistry, file); await storage.save(); const loadRegistry = await TaskbarTabsRegistry.create({ loadFile: file }); let loadTaskbarTab = loadRegistry.getTaskbarTab(saveTaskbarTab.id); Assert.deepEqual( saveTaskbarTab, loadTaskbarTab, "Taskbar Tab object should be identical after save and load." ); }); add_task(async function test_load_and_save_consistency() { const loadFile = do_get_file("test_taskbarTabs.json"); // Test loading from the mock file const registry = await TaskbarTabsRegistry.create({ loadFile }); Assert.equal( registry.findTaskbarTab(Services.io.newURI("https://www.test.com"), 0).id, "4186657a-0fe5-492a-af64-dc628c232c4c", "Taskbar Tab ID should match the one in the test JSON file." ); // Test saving to a new file let file = testFile(); let storage = new TaskbarTabsRegistryStorage(registry, file); await storage.save(); // Verify the output against the original file on disk. const originalData = await IOUtils.readJSON(loadFile.path); const outputData = await IOUtils.readJSON(file.path); // Even though the Taskbar Tabs are kept in a map, entries remember their // insertion orders. Assert.deepEqual( outputData, originalData, "The in-memory mock file output should match the original file on disk." ); }); add_task(async function test_load_and_save_migrates_name() { const loadFile = do_get_file("test_taskbarTabs_nonames.json"); const registry = await TaskbarTabsRegistry.create({ loadFile }); const tt = registry.findTaskbarTab( Services.io.newURI("https://www.test.com"), 0 ); equal( tt.id, "4186657a-0fe5-492a-af64-dc628c232c4c", "Taskbar Tab ID should match the one in the test JSON file." ); equal(typeof tt.name, "string", "A name should be present in-memory."); let file = testFile(); let storage = new TaskbarTabsRegistryStorage(registry, file); await storage.save(); const outputData = await IOUtils.readJSON(file.path); equal( typeof outputData.taskbarTabs[0].name, "string", "A name should be saved to storage." ); }); add_task(async function test_guards_against_commandline_strings() { const validUrl = Services.io.newURI("https://www.test.com/start"); const invalidUrl = "https://www.test.com/start"; const validUserContextId = 0; const invalidUserContextId = "0"; const registry = new TaskbarTabsRegistry(); Assert.throws( () => registry.findTaskbarTab(invalidUrl, validUserContextId), /Invalid argument, `aUrl` should be instance of `nsIURL`/, "Should reject URLs provided as a string." ); Assert.throws( () => registry.findTaskbarTab(validUrl, invalidUserContextId), /Invalid argument, `aUserContextId` should be type of `number`/, "Should reject userContextId provided as a string." ); }); add_task(async function test_guards_against_non_urls() { // about:blank is a URI, but not a URL. const url = Services.io.newURI("about:blank"); const userContextId = 0; const registry = new TaskbarTabsRegistry(); throws( () => createTaskbarTab(registry, url, userContextId), /Invalid argument, `aUrl` should be instance of `nsIURL`/, "Should reject URIs that are not URLs." ); }); add_task(async function test_patch_becomes_visible() { const registry = new TaskbarTabsRegistry(); const tt = createTaskbarTab( registry, Services.io.newURI("https://www.test.com/start"), 0 ); let called = 0; registry.on(TaskbarTabsRegistry.events.patched, () => { called += 1; }); Assert.equal( tt.shortcutRelativePath, null, "Should not start with a relative path" ); registry.patchTaskbarTab(tt, { shortcutRelativePath: "some\\path\\string.lnk", }); Assert.equal( tt.shortcutRelativePath, "some\\path\\string.lnk", "Should update to the new value" ); Assert.equal(called, 1, "Should emit the callback function once"); }); add_task(async function test_shortcutRelativePath_is_saved() { const registry = new TaskbarTabsRegistry(); const tt = createTaskbarTab( registry, Services.io.newURI("https://www.test.com/start"), 0 ); registry.patchTaskbarTab(tt, { shortcutRelativePath: "some\\path\\string.lnk", }); const file = testFile(); const storage = new TaskbarTabsRegistryStorage(registry, file); await storage.save(); const data = await IOUtils.readJSON(file.path); Assert.equal( data.taskbarTabs[0].shortcutRelativePath, "some\\path\\string.lnk", "Shortcut relative path should be saved" ); }); add_task(async function test_multiple_match_longest_prefix() { const registry = new TaskbarTabsRegistry(); const uriWithPrefix = prefix => Services.io.newURI("https://example.com" + prefix); const createWithScope = uri => createTaskbarTab(registry, uri, 0, { manifest: { scope: uri.spec, }, }); const find = prefix => registry.findTaskbarTab(uriWithPrefix(prefix), 0); // Register them in an arbitrary order. const ttAB = createWithScope(uriWithPrefix("/ab")); const ttA = createWithScope(uriWithPrefix("/a")); const ttABC = createWithScope(uriWithPrefix("/abc")); const ttABCD = createWithScope(uriWithPrefix("/abc/d/")); equal(find("/q"), null, "/q does not exist"); equal(find("/a").id, ttA.id, "/a matches /a"); equal(find("/az").id, ttA.id, "/a matches /az"); equal(find("/ab").id, ttAB.id, "/ab matches /ab"); equal(find("/abq").id, ttAB.id, "/abq matches /ab"); equal(find("/abc").id, ttABC.id, "/abc matches /abc"); equal(find("/abc/").id, ttABC.id, "/abc/ matches /abc"); equal(find("/abc/d").id, ttABC.id, "/abc/d matches /abc (not /abc/d/)"); equal(find("/abc/d/").id, ttABCD.id, "/abc/d/ matches /abc/d/"); equal(find("/abc/d/efgh").id, ttABCD.id, "/abc/d/efgh matches /abc/d/"); }).skip(); // TODO bug 2000948