summaryrefslogtreecommitdiffstats
path: root/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js')
-rw-r--r--browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js263
1 files changed, 263 insertions, 0 deletions
diff --git a/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js b/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
new file mode 100644
index 0000000000..9162325081
--- /dev/null
+++ b/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
@@ -0,0 +1,263 @@
+"use strict";
+
+let { SyncedTabs } = ChromeUtils.importESModule(
+ "resource://services-sync/SyncedTabs.sys.mjs"
+);
+let { SyncedTabsDeckComponent } = ChromeUtils.importESModule(
+ "resource:///modules/syncedtabs/SyncedTabsDeckComponent.sys.mjs"
+);
+let { SyncedTabsListStore } = ChromeUtils.importESModule(
+ "resource:///modules/syncedtabs/SyncedTabsListStore.sys.mjs"
+);
+let { SyncedTabsDeckStore } = ChromeUtils.importESModule(
+ "resource:///modules/syncedtabs/SyncedTabsDeckStore.sys.mjs"
+);
+const { UIState } = ChromeUtils.importESModule(
+ "resource://services-sync/UIState.sys.mjs"
+);
+
+add_task(async function testInitUninit() {
+ let deckStore = new SyncedTabsDeckStore();
+ let listComponent = {};
+ let mockWindow = {};
+
+ let ViewMock = sinon.stub();
+ let view = { render: sinon.spy(), destroy: sinon.spy(), container: {} };
+ ViewMock.returns(view);
+
+ sinon.stub(SyncedTabs, "syncTabs").callsFake(() => Promise.resolve());
+
+ sinon.spy(deckStore, "on");
+ sinon.stub(deckStore, "setPanels");
+
+ let component = new SyncedTabsDeckComponent({
+ window: mockWindow,
+ deckStore,
+ listComponent,
+ SyncedTabs,
+ DeckView: ViewMock,
+ });
+
+ sinon.stub(component, "updatePanel");
+
+ component.init();
+
+ Assert.ok(SyncedTabs.syncTabs.called);
+ SyncedTabs.syncTabs.restore();
+
+ Assert.ok(ViewMock.calledWithNew(), "view is instantiated");
+ Assert.equal(ViewMock.args[0][0], mockWindow);
+ Assert.equal(ViewMock.args[0][1], listComponent);
+ Assert.ok(
+ ViewMock.args[0][2].onConnectDeviceClick,
+ "view is passed onConnectDeviceClick prop"
+ );
+ Assert.ok(
+ ViewMock.args[0][2].onSyncPrefClick,
+ "view is passed onSyncPrefClick prop"
+ );
+
+ Assert.equal(
+ component.container,
+ view.container,
+ "component returns view's container"
+ );
+
+ Assert.ok(deckStore.on.calledOnce, "listener is added to store");
+ Assert.equal(deckStore.on.args[0][0], "change");
+ // Object.values only in nightly
+ let values = Object.keys(component.PANELS).map(k => component.PANELS[k]);
+ Assert.ok(
+ deckStore.setPanels.calledWith(values),
+ "panels are set on deck store"
+ );
+
+ Assert.ok(component.updatePanel.called);
+
+ deckStore.emit("change", "mock state");
+ Assert.ok(
+ view.render.calledWith("mock state"),
+ "view.render is called on state change"
+ );
+
+ component.uninit();
+
+ Assert.ok(view.destroy.calledOnce, "view is destroyed on uninit");
+});
+
+add_task(async function testObserver() {
+ let deckStore = new SyncedTabsDeckStore();
+ let listStore = new SyncedTabsListStore(SyncedTabs);
+ let listComponent = {};
+ let mockWindow = {};
+
+ let ViewMock = sinon.stub();
+ let view = { render: sinon.spy(), destroy: sinon.spy(), container: {} };
+ ViewMock.returns(view);
+
+ sinon.stub(SyncedTabs, "syncTabs").callsFake(() => Promise.resolve());
+
+ sinon.spy(deckStore, "on");
+ sinon.stub(deckStore, "setPanels");
+
+ sinon.stub(listStore, "getData");
+
+ let component = new SyncedTabsDeckComponent({
+ window: mockWindow,
+ deckStore,
+ listStore,
+ listComponent,
+ SyncedTabs,
+ DeckView: ViewMock,
+ });
+
+ sinon.spy(component, "observe");
+ sinon.stub(component, "updatePanel");
+ sinon.stub(component, "updateDir");
+
+ component.init();
+ SyncedTabs.syncTabs.restore();
+ Assert.ok(component.updatePanel.called, "triggers panel update during init");
+ Assert.ok(
+ component.updateDir.called,
+ "triggers UI direction update during init"
+ );
+
+ Services.obs.notifyObservers(null, SyncedTabs.TOPIC_TABS_CHANGED);
+
+ Assert.ok(
+ component.observe.calledWith(null, SyncedTabs.TOPIC_TABS_CHANGED),
+ "component is notified"
+ );
+
+ Assert.ok(listStore.getData.called, "gets list data");
+ Assert.ok(component.updatePanel.calledTwice, "triggers panel update");
+
+ Services.obs.notifyObservers(null, UIState.ON_UPDATE);
+
+ Assert.ok(
+ component.observe.calledWith(null, UIState.ON_UPDATE),
+ "component is notified of FxA/Sync UI Update"
+ );
+ Assert.equal(
+ component.updatePanel.callCount,
+ 3,
+ "triggers panel update again"
+ );
+
+ Services.locale.availableLocales = ["ab-CD"];
+ Services.locale.requestedLocales = ["ab-CD"];
+
+ Assert.ok(
+ component.updateDir.calledTwice,
+ "locale change triggers UI direction update"
+ );
+
+ Services.prefs.setStringPref("intl.l10n.pseudo", "bidi");
+
+ Assert.equal(
+ component.updateDir.callCount,
+ 3,
+ "pref change triggers UI direction update"
+ );
+});
+
+add_task(async function testPanelStatus() {
+ let deckStore = new SyncedTabsDeckStore();
+ let listStore = new SyncedTabsListStore();
+ let listComponent = {};
+ let SyncedTabsMock = {
+ getTabClients() {},
+ };
+
+ sinon.stub(listStore, "getData");
+
+ let component = new SyncedTabsDeckComponent({
+ deckStore,
+ listComponent,
+ SyncedTabs: SyncedTabsMock,
+ });
+
+ sinon.stub(UIState, "get").returns({ status: UIState.STATUS_NOT_CONFIGURED });
+ let result = await component.getPanelStatus();
+ Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
+ UIState.get.restore();
+
+ sinon.stub(UIState, "get").returns({ status: UIState.STATUS_NOT_VERIFIED });
+ result = await component.getPanelStatus();
+ Assert.equal(result, component.PANELS.UNVERIFIED);
+ UIState.get.restore();
+
+ sinon.stub(UIState, "get").returns({ status: UIState.STATUS_LOGIN_FAILED });
+ result = await component.getPanelStatus();
+ Assert.equal(result, component.PANELS.LOGIN_FAILED);
+ UIState.get.restore();
+
+ sinon
+ .stub(UIState, "get")
+ .returns({ status: UIState.STATUS_SIGNED_IN, syncEnabled: false });
+ SyncedTabsMock.isConfiguredToSyncTabs = true;
+ result = await component.getPanelStatus();
+ Assert.equal(result, component.PANELS.SYNC_DISABLED);
+ UIState.get.restore();
+
+ sinon
+ .stub(UIState, "get")
+ .returns({ status: UIState.STATUS_SIGNED_IN, syncEnabled: true });
+ SyncedTabsMock.isConfiguredToSyncTabs = false;
+ result = await component.getPanelStatus();
+ Assert.equal(result, component.PANELS.TABS_DISABLED);
+
+ SyncedTabsMock.isConfiguredToSyncTabs = true;
+
+ SyncedTabsMock.hasSyncedThisSession = false;
+ result = await component.getPanelStatus();
+ Assert.equal(result, component.PANELS.TABS_FETCHING);
+
+ SyncedTabsMock.hasSyncedThisSession = true;
+
+ let clients = [];
+ sinon
+ .stub(SyncedTabsMock, "getTabClients")
+ .callsFake(() => Promise.resolve(clients));
+ result = await component.getPanelStatus();
+ Assert.equal(result, component.PANELS.SINGLE_DEVICE_INFO);
+
+ clients = ["mock-client"];
+ result = await component.getPanelStatus();
+ Assert.equal(result, component.PANELS.TABS_CONTAINER);
+
+ sinon
+ .stub(component, "getPanelStatus")
+ .callsFake(() => Promise.resolve("mock-panelId"));
+ sinon.spy(deckStore, "selectPanel");
+ await component.updatePanel();
+ Assert.ok(deckStore.selectPanel.calledWith("mock-panelId"));
+});
+
+add_task(async function testActions() {
+ let windowMock = {};
+ let chromeWindowMock = {
+ gSync: {
+ openPrefs() {},
+ openConnectAnotherDevice() {},
+ },
+ };
+ sinon.spy(chromeWindowMock.gSync, "openPrefs");
+ sinon.spy(chromeWindowMock.gSync, "openConnectAnotherDevice");
+
+ let getChromeWindowMock = sinon.stub();
+ getChromeWindowMock.returns(chromeWindowMock);
+
+ let component = new SyncedTabsDeckComponent({
+ window: windowMock,
+ getChromeWindowMock,
+ });
+
+ component.openConnectDevice();
+ Assert.ok(chromeWindowMock.gSync.openConnectAnotherDevice.called);
+
+ component.openSyncPrefs();
+ Assert.ok(getChromeWindowMock.calledWith(windowMock));
+ Assert.ok(chromeWindowMock.gSync.openPrefs.called);
+});