summaryrefslogtreecommitdiffstats
path: root/services/sync/tests/unit/test_syncedtabs.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /services/sync/tests/unit/test_syncedtabs.js
parentInitial commit. (diff)
downloadfirefox-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.js342
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");
+});