diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /services/sync/tests/unit/test_syncedtabs.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | services/sync/tests/unit/test_syncedtabs.js | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/services/sync/tests/unit/test_syncedtabs.js b/services/sync/tests/unit/test_syncedtabs.js new file mode 100644 index 0000000000..79ab3e0686 --- /dev/null +++ b/services/sync/tests/unit/test_syncedtabs.js @@ -0,0 +1,342 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + * vim:set ts=2 sw=2 sts=2 et: + */ +"use strict"; + +const { Weave } = ChromeUtils.importESModule( + "resource://services-sync/main.sys.mjs" +); +const { SyncedTabs } = ChromeUtils.importESModule( + "resource://services-sync/SyncedTabs.sys.mjs" +); + +Log.repository.getLogger("Sync.RemoteTabs").addAppender(new Log.DumpAppender()); + +// A mock "Tabs" engine which the SyncedTabs module will use instead of the real +// engine. We pass a constructor that Sync creates. +function MockTabsEngine() { + this.clients = {}; // We'll set this dynamically + // Mock fxAccounts + recentDeviceList as if we hit the FxA server + this.fxAccounts = { + device: { + recentDeviceList: [ + { + id: 1, + name: "updated desktop name", + availableCommands: { + "https://identity.mozilla.com/cmd/open-uri": "baz", + }, + }, + { + id: 2, + name: "updated mobile name", + availableCommands: { + "https://identity.mozilla.com/cmd/open-uri": "boo", + }, + }, + ], + }, + }; +} + +MockTabsEngine.prototype = { + name: "tabs", + enabled: true, + + getAllClients() { + return Object.values(this.clients); + }, + + getOpenURLs() { + return new Set(); + }, +}; + +let tabsEngine; + +// A clients engine that doesn't need to be a constructor. +let MockClientsEngine = { + clientSettings: null, // Set in `configureClients`. + + isMobile(guid) { + if (!guid.endsWith("desktop") && !guid.endsWith("mobile")) { + throw new Error( + "this module expected guids to end with 'desktop' or 'mobile'" + ); + } + return guid.endsWith("mobile"); + }, + remoteClientExists(id) { + return this.clientSettings[id] !== false; + }, + getClientName(id) { + if (this.clientSettings[id]) { + return this.clientSettings[id]; + } + let client = tabsEngine.clients[id]; + let fxaDevice = tabsEngine.fxAccounts.device.recentDeviceList.find( + device => device.id === client.fxaDeviceId + ); + return fxaDevice ? fxaDevice.name : client.clientName; + }, + + getClientFxaDeviceId(id) { + if (this.clientSettings[id]) { + return this.clientSettings[id]; + } + return tabsEngine.clients[id].fxaDeviceId; + }, + + getClientType(id) { + return "desktop"; + }, +}; + +function configureClients(clients, clientSettings = {}) { + // each client record is expected to have an id. + for (let [guid, client] of Object.entries(clients)) { + client.id = guid; + } + tabsEngine.clients = clients; + // Apply clients collection overrides. + MockClientsEngine.clientSettings = clientSettings; + // Send an observer that pretends the engine just finished a sync. + Services.obs.notifyObservers(null, "weave:engine:sync:finish", "tabs"); +} + +add_task(async function setup() { + await Weave.Service.promiseInitialized; + // Configure Sync with our mock tabs engine and force it to become initialized. + await Weave.Service.engineManager.unregister("tabs"); + await Weave.Service.engineManager.register(MockTabsEngine); + Weave.Service.clientsEngine = MockClientsEngine; + tabsEngine = Weave.Service.engineManager.get("tabs"); + + // Tell the Sync XPCOM service it is initialized. + let weaveXPCService = Cc["@mozilla.org/weave/service;1"].getService( + Ci.nsISupports + ).wrappedJSObject; + weaveXPCService.ready = true; +}); + +// The tests. +add_task(async function test_noClients() { + // no clients, can't be tabs. + await configureClients({}); + + let tabs = await SyncedTabs.getTabClients(); + equal(Object.keys(tabs).length, 0); +}); + +add_task(async function test_clientWithTabs() { + await configureClients({ + guid_desktop: { + clientName: "My Desktop", + tabs: [ + { + urlHistory: ["http://foo.com/"], + icon: "http://foo.com/favicon", + lastUsed: 1655745700, // Mon, 20 Jun 2022 17:21:40 GMT + }, + ], + }, + guid_mobile: { + clientName: "My Phone", + tabs: [], + }, + }); + + let clients = await SyncedTabs.getTabClients(); + equal(clients.length, 2); + clients.sort((a, b) => { + return a.name.localeCompare(b.name); + }); + equal(clients[0].tabs.length, 1); + equal(clients[0].tabs[0].url, "http://foo.com/"); + equal(clients[0].tabs[0].icon, "http://foo.com/favicon"); + equal(clients[0].tabs[0].lastUsed, 1655745700); + // second client has no tabs. + equal(clients[1].tabs.length, 0); +}); + +add_task(async function test_staleClientWithTabs() { + await configureClients( + { + guid_desktop: { + clientName: "My Desktop", + tabs: [ + { + urlHistory: ["http://foo.com/"], + icon: "http://foo.com/favicon", + lastUsed: 1655745750, + }, + ], + }, + guid_mobile: { + clientName: "My Phone", + tabs: [], + }, + guid_stale_mobile: { + clientName: "My Deleted Phone", + tabs: [], + }, + guid_stale_desktop: { + clientName: "My Deleted Laptop", + tabs: [ + { + urlHistory: ["https://bar.com/"], + icon: "https://bar.com/favicon", + lastUsed: 1655745700, + }, + ], + }, + guid_stale_name_desktop: { + clientName: "My Generic Device", + tabs: [ + { + urlHistory: ["https://example.edu/"], + icon: "https://example.edu/favicon", + lastUsed: 1655745800, + }, + ], + }, + }, + { + guid_stale_mobile: false, + guid_stale_desktop: false, + // We should always use the device name from the clients collection, instead + // of the possibly stale tabs collection. + guid_stale_name_desktop: "My Laptop", + } + ); + let clients = await SyncedTabs.getTabClients(); + clients.sort((a, b) => { + return a.name.localeCompare(b.name); + }); + equal(clients.length, 3); + equal(clients[0].name, "My Desktop"); + equal(clients[0].tabs.length, 1); + equal(clients[0].tabs[0].url, "http://foo.com/"); + equal(clients[0].tabs[0].lastUsed, 1655745750); + equal(clients[1].name, "My Laptop"); + equal(clients[1].tabs.length, 1); + equal(clients[1].tabs[0].url, "https://example.edu/"); + equal(clients[1].tabs[0].lastUsed, 1655745800); + equal(clients[2].name, "My Phone"); + equal(clients[2].tabs.length, 0); +}); + +add_task(async function test_clientWithTabsIconsDisabled() { + Services.prefs.setBoolPref("services.sync.syncedTabs.showRemoteIcons", false); + await configureClients({ + guid_desktop: { + clientName: "My Desktop", + tabs: [ + { + urlHistory: ["http://foo.com/"], + icon: "http://foo.com/favicon", + }, + ], + }, + }); + + let clients = await SyncedTabs.getTabClients(); + equal(clients.length, 1); + clients.sort((a, b) => { + return a.name.localeCompare(b.name); + }); + equal(clients[0].tabs.length, 1); + equal(clients[0].tabs[0].url, "http://foo.com/"); + // Expect the default favicon due to the pref being false. + equal(clients[0].tabs[0].icon, "page-icon:http://foo.com/"); + Services.prefs.clearUserPref("services.sync.syncedTabs.showRemoteIcons"); +}); + +add_task(async function test_filter() { + // Nothing matches. + await configureClients({ + guid_desktop: { + clientName: "My Desktop", + tabs: [ + { + urlHistory: ["http://foo.com/"], + title: "A test page.", + }, + { + urlHistory: ["http://bar.com/"], + title: "Another page.", + }, + ], + }, + }); + + let clients = await SyncedTabs.getTabClients("foo"); + equal(clients.length, 1); + equal(clients[0].tabs.length, 1); + equal(clients[0].tabs[0].url, "http://foo.com/"); + // check it matches the title. + clients = await SyncedTabs.getTabClients("test"); + equal(clients.length, 1); + equal(clients[0].tabs.length, 1); + equal(clients[0].tabs[0].url, "http://foo.com/"); +}); + +add_task(async function test_duplicatesTabsAcrossClients() { + await configureClients({ + guid_desktop: { + clientName: "My Desktop", + tabs: [ + { + urlHistory: ["http://foo.com/"], + title: "A test page.", + }, + ], + }, + guid_mobile: { + clientName: "My Phone", + tabs: [ + { + urlHistory: ["http://foo.com/"], + title: "A test page.", + }, + ], + }, + }); + + let clients = await SyncedTabs.getTabClients(); + equal(clients.length, 2); + equal(clients[0].tabs.length, 1); + equal(clients[1].tabs.length, 1); + equal(clients[0].tabs[0].url, "http://foo.com/"); + equal(clients[1].tabs[0].url, "http://foo.com/"); +}); + +add_task(async function test_clientsTabUpdatedName() { + // See the "fxAccounts" object in the MockEngine above for the device list + await configureClients({ + guid_desktop: { + clientName: "My Desktop", + tabs: [ + { + urlHistory: ["http://foo.com/"], + icon: "http://foo.com/favicon", + }, + ], + fxaDeviceId: 1, + }, + guid_mobile: { + clientName: "My Phone", + tabs: [ + { + urlHistory: ["http://bar.com/"], + icon: "http://bar.com/favicon", + }, + ], + fxaDeviceId: 2, + }, + }); + let clients = await SyncedTabs.getTabClients(); + equal(clients.length, 2); + equal(clients[0].name, "updated desktop name"); + equal(clients[1].name, "updated mobile name"); +}); |