/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ const tabsList1 = syncedTabsData1[0].tabs; const tabsList2 = syncedTabsData1[1].tabs; const BADGE_TOP_RIGHT = "75% 25%"; const { SyncedTabs } = ChromeUtils.importESModule( "resource://services-sync/SyncedTabs.sys.mjs" ); function setupRecentDeviceListMocks() { const sandbox = sinon.createSandbox(); sandbox.stub(fxAccounts.device, "recentDeviceList").get(() => [ { id: 1, name: "My desktop", isCurrentDevice: true, type: "desktop", }, { id: 2, name: "My iphone", type: "mobile", }, ]); sandbox.stub(UIState, "get").returns({ status: UIState.STATUS_SIGNED_IN, syncEnabled: true, }); return sandbox; } function waitForWindowActive(win, active) { info("Waiting for window activation"); return Promise.all([ BrowserTestUtils.waitForEvent(win, active ? "focus" : "blur"), BrowserTestUtils.waitForEvent(win, active ? "activate" : "deactivate"), ]); } async function waitForNotificationBadgeToBeShowing(fxViewButton) { info("Waiting for attention attribute to be set"); await BrowserTestUtils.waitForMutationCondition( fxViewButton, { attributes: true }, () => fxViewButton.hasAttribute("attention") ); return fxViewButton.hasAttribute("attention"); } async function waitForNotificationBadgeToBeHidden(fxViewButton) { info("Waiting for attention attribute to be removed"); await BrowserTestUtils.waitForMutationCondition( fxViewButton, { attributes: true }, () => !fxViewButton.hasAttribute("attention") ); return !fxViewButton.hasAttribute("attention"); } async function clickFirefoxViewButton(win) { await BrowserTestUtils.synthesizeMouseAtCenter( "#firefox-view-button", { type: "mousedown" }, win.browsingContext ); } function getBackgroundPositionForElement(ele) { let style = ele.ownerGlobal.getComputedStyle(ele); return style.getPropertyValue("background-position"); } let previousFetchTime = 0; async function resetSyncedTabsLastFetched() { Services.prefs.clearUserPref("services.sync.lastTabFetch"); previousFetchTime = 0; await TestUtils.waitForTick(); } async function initTabSync() { let recentFetchTime = Math.floor(Date.now() / 1000); // ensure we don't try to set the pref with the same value, which will not produce // the expected pref change effects while (recentFetchTime == previousFetchTime) { await TestUtils.waitForTick(); recentFetchTime = Math.floor(Date.now() / 1000); } ok( recentFetchTime > previousFetchTime, "The new lastTabFetch value is greater than the previous" ); info("initTabSync, updating lastFetch:" + recentFetchTime); Services.prefs.setIntPref("services.sync.lastTabFetch", recentFetchTime); previousFetchTime = recentFetchTime; await TestUtils.waitForTick(); } add_setup(async function () { await resetSyncedTabsLastFetched(); await SpecialPowers.pushPrefEnv({ set: [["browser.tabs.firefox-view.notify-for-tabs", true]], }); // Clear any synced tabs from previous tests FirefoxViewNotificationManager.syncedTabs = null; Services.obs.notifyObservers( null, "firefoxview-notification-dot-update", "false" ); }); /** * Test that the notification badge will show and hide in the correct cases */ add_task(async function testNotificationDot() { const sandbox = setupRecentDeviceListMocks(); const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs"); sandbox.spy(SyncedTabs, "syncTabs"); let win = await BrowserTestUtils.openNewBrowserWindow(); let fxViewBtn = win.document.getElementById("firefox-view-button"); ok(fxViewBtn, "Got the Firefox View button"); // Initiate a synced tabs update with new tabs syncedTabsMock.returns(tabsList1); await initTabSync(); ok( BrowserTestUtils.is_visible(fxViewBtn), "The Firefox View button is showing" ); info( "testNotificationDot, button is showing, badge should be initially hidden" ); ok( await waitForNotificationBadgeToBeHidden(fxViewBtn), "The notification badge is not showing initially" ); // Initiate a synced tabs update with new tabs syncedTabsMock.returns(tabsList2); await initTabSync(); ok( await waitForNotificationBadgeToBeShowing(fxViewBtn), "The notification badge is showing after first tab sync" ); // check that switching to the firefoxviewtab removes the badge await clickFirefoxViewButton(win); info( "testNotificationDot, after clicking the button, badge should become hidden" ); ok( await waitForNotificationBadgeToBeHidden(fxViewBtn), "The notification badge is not showing after going to Firefox View" ); await BrowserTestUtils.waitForCondition(() => { return SyncedTabs.syncTabs.calledOnce; }); ok(SyncedTabs.syncTabs.calledOnce, "SyncedTabs.syncTabs() was called once"); syncedTabsMock.returns(tabsList1); // Initiate a synced tabs update with new tabs await initTabSync(); // The noti badge would show but we are on a Firefox View page so no need to show the noti badge info( "testNotificationDot, after updating the recent tabs, badge should be hidden" ); ok( await waitForNotificationBadgeToBeHidden(fxViewBtn), "The notification badge is not showing after tab sync while Firefox View is focused" ); let newTab = await BrowserTestUtils.openNewForegroundTab(win.gBrowser); syncedTabsMock.returns(tabsList2); await initTabSync(); ok( await waitForNotificationBadgeToBeShowing(fxViewBtn), "The notification badge is showing after navigation to a new tab" ); // check that switching back to the Firefox View tab removes the badge await clickFirefoxViewButton(win); info( "testNotificationDot, after switching back to fxview, badge should be hidden" ); ok( await waitForNotificationBadgeToBeHidden(fxViewBtn), "The notification badge is not showing after focusing the Firefox View tab" ); await BrowserTestUtils.switchTab(win.gBrowser, newTab); // Initiate a synced tabs update with no new tabs await initTabSync(); info( "testNotificationDot, after switching back to fxview with no new tabs, badge should be hidden" ); ok( await waitForNotificationBadgeToBeHidden(fxViewBtn), "The notification badge is not showing after a tab sync with the same tabs" ); await BrowserTestUtils.closeWindow(win); sandbox.restore(); }); /** * Tests the notification badge with multiple windows */ add_task(async function testNotificationDotOnMultipleWindows() { const sandbox = setupRecentDeviceListMocks(); await resetSyncedTabsLastFetched(); const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs"); // Create a new window let win1 = await BrowserTestUtils.openNewBrowserWindow(); await win1.delayedStartupPromise; let fxViewBtn = win1.document.getElementById("firefox-view-button"); ok(fxViewBtn, "Got the Firefox View button"); syncedTabsMock.returns(tabsList1); // Initiate a synced tabs update await initTabSync(); // Create another window let win2 = await BrowserTestUtils.openNewBrowserWindow(); await win2.delayedStartupPromise; let fxViewBtn2 = win2.document.getElementById("firefox-view-button"); await clickFirefoxViewButton(win2); // Make sure the badge doesn't show on any window info( "testNotificationDotOnMultipleWindows, badge is initially hidden on window 1" ); ok( await waitForNotificationBadgeToBeHidden(fxViewBtn), "The notification badge is not showing in the inital window" ); info( "testNotificationDotOnMultipleWindows, badge is initially hidden on window 2" ); ok( await waitForNotificationBadgeToBeHidden(fxViewBtn2), "The notification badge is not showing in the second window" ); // Minimize the window. win2.minimize(); await TestUtils.waitForCondition( () => !win2.gBrowser.selectedBrowser.docShellIsActive, "Waiting for docshell to be marked as inactive after minimizing the window" ); syncedTabsMock.returns(tabsList2); info("Initiate a synced tabs update with new tabs"); await initTabSync(); // The badge will show because the View tab is minimized // Make sure the badge shows on all windows info( "testNotificationDotOnMultipleWindows, after new synced tabs and minimized win2, badge is visible on window 1" ); ok( await waitForNotificationBadgeToBeShowing(fxViewBtn), "The notification badge is showing in the initial window" ); info( "testNotificationDotOnMultipleWindows, after new synced tabs and minimized win2, badge is visible on window 2" ); ok( await waitForNotificationBadgeToBeShowing(fxViewBtn2), "The notification badge is showing in the second window" ); win2.restore(); await TestUtils.waitForCondition( () => win2.gBrowser.selectedBrowser.docShellIsActive, "Waiting for docshell to be marked as active after restoring the window" ); await BrowserTestUtils.closeWindow(win1); await BrowserTestUtils.closeWindow(win2); sandbox.restore(); }); /** * Tests the notification badge is in the correct spot and that the badge shows when opening a new window * if another window is showing the badge */ add_task(async function testNotificationDotLocation() { const sandbox = setupRecentDeviceListMocks(); await resetSyncedTabsLastFetched(); const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs"); syncedTabsMock.returns(tabsList1); let win1 = await BrowserTestUtils.openNewBrowserWindow(); let fxViewBtn = win1.document.getElementById("firefox-view-button"); ok(fxViewBtn, "Got the Firefox View button"); // Initiate a synced tabs update await initTabSync(); syncedTabsMock.returns(tabsList2); // Initiate another synced tabs update await initTabSync(); ok( await waitForNotificationBadgeToBeShowing(fxViewBtn), "The notification badge is showing initially" ); // Create a new window let win2 = await BrowserTestUtils.openNewBrowserWindow(); await win2.delayedStartupPromise; // Make sure the badge is showing on the new window let fxViewBtn2 = win2.document.getElementById("firefox-view-button"); ok( await waitForNotificationBadgeToBeShowing(fxViewBtn2), "The notification badge is showing in the second window after opening" ); // Make sure the badge is below and center now isnot( getBackgroundPositionForElement(fxViewBtn), BADGE_TOP_RIGHT, "The notification badge is not showing in the top right in the initial window" ); isnot( getBackgroundPositionForElement(fxViewBtn2), BADGE_TOP_RIGHT, "The notification badge is not showing in the top right in the second window" ); CustomizableUI.addWidgetToArea( "firefox-view-button", CustomizableUI.AREA_NAVBAR ); // Make sure both windows still have the notification badge ok( await waitForNotificationBadgeToBeShowing(fxViewBtn), "The notification badge is showing in the initial window" ); ok( await waitForNotificationBadgeToBeShowing(fxViewBtn2), "The notification badge is showing in the second window" ); // Make sure the badge is in the top right now is( getBackgroundPositionForElement(fxViewBtn), BADGE_TOP_RIGHT, "The notification badge is showing in the top right in the initial window" ); is( getBackgroundPositionForElement(fxViewBtn2), BADGE_TOP_RIGHT, "The notification badge is showing in the top right in the second window" ); CustomizableUI.reset(); await BrowserTestUtils.closeWindow(win1); await BrowserTestUtils.closeWindow(win2); sandbox.restore(); });