diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /browser/base/content/test/sync | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'browser/base/content/test/sync')
-rw-r--r-- | browser/base/content/test/sync/.eslintrc.js | 5 | ||||
-rw-r--r-- | browser/base/content/test/sync/browser.ini | 11 | ||||
-rw-r--r-- | browser/base/content/test/sync/browser_contextmenu_sendpage.js | 428 | ||||
-rw-r--r-- | browser/base/content/test/sync/browser_contextmenu_sendtab.js | 267 | ||||
-rw-r--r-- | browser/base/content/test/sync/browser_fxa_badge.js | 71 | ||||
-rw-r--r-- | browser/base/content/test/sync/browser_fxa_web_channel.html | 138 | ||||
-rw-r--r-- | browser/base/content/test/sync/browser_fxa_web_channel.js | 248 | ||||
-rw-r--r-- | browser/base/content/test/sync/browser_sync.js | 608 | ||||
-rw-r--r-- | browser/base/content/test/sync/head.js | 24 |
9 files changed, 1800 insertions, 0 deletions
diff --git a/browser/base/content/test/sync/.eslintrc.js b/browser/base/content/test/sync/.eslintrc.js new file mode 100644 index 0000000000..1779fd7f1c --- /dev/null +++ b/browser/base/content/test/sync/.eslintrc.js @@ -0,0 +1,5 @@ +"use strict"; + +module.exports = { + extends: ["plugin:mozilla/browser-test"], +}; diff --git a/browser/base/content/test/sync/browser.ini b/browser/base/content/test/sync/browser.ini new file mode 100644 index 0000000000..88576cf836 --- /dev/null +++ b/browser/base/content/test/sync/browser.ini @@ -0,0 +1,11 @@ +[DEFAULT] +support-files = + head.js + +[browser_sync.js] +[browser_contextmenu_sendtab.js] +[browser_contextmenu_sendpage.js] +[browser_fxa_web_channel.js] +support-files= + browser_fxa_web_channel.html +[browser_fxa_badge.js] diff --git a/browser/base/content/test/sync/browser_contextmenu_sendpage.js b/browser/base/content/test/sync/browser_contextmenu_sendpage.js new file mode 100644 index 0000000000..9233dfae39 --- /dev/null +++ b/browser/base/content/test/sync/browser_contextmenu_sendpage.js @@ -0,0 +1,428 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const fxaDevices = [ + { + id: 1, + name: "Foo", + availableCommands: { "https://identity.mozilla.com/cmd/open-uri": "baz" }, + }, + { id: 2, name: "Bar", clientRecord: "bar" }, // Legacy send tab target (no availableCommands). + { id: 3, name: "Homer" }, // Incompatible target. +]; + +add_task(async function setup() { + await promiseSyncReady(); + await Services.search.init(); + // gSync.init() is called in a requestIdleCallback. Force its initialization. + gSync.init(); + sinon + .stub(Weave.Service.clientsEngine, "getClientByFxaDeviceId") + .callsFake(fxaDeviceId => { + let target = fxaDevices.find(c => c.id == fxaDeviceId); + return target ? target.clientRecord : null; + }); + sinon.stub(Weave.Service.clientsEngine, "getClientType").returns("desktop"); + await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla"); +}); + +add_task(async function test_page_contextmenu() { + const sandbox = setupSendTabMocks({ fxaDevices }); + + await openContentContextMenu("#moztext", "context-sendpagetodevice"); + is( + document.getElementById("context-sendpagetodevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context-sendpagetodevice").disabled, + false, + "Send tab to device is enabled" + ); + checkPopup([ + { label: "Bar" }, + { label: "Foo" }, + "----", + { label: "Send to All Devices" }, + { label: "Manage Devices..." }, + ]); + await hideContentContextMenu(); + + sandbox.restore(); +}); + +add_task(async function test_link_contextmenu() { + const sandbox = setupSendTabMocks({ fxaDevices }); + let expectation = sandbox + .mock(gSync) + .expects("sendTabToDevice") + .once() + .withExactArgs( + "https://www.example.org/", + [fxaDevices[1]], + "Click on me!!" + ); + + // Add a link to the page + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => { + let a = content.document.createElement("a"); + a.href = "https://www.example.org"; + a.id = "testingLink"; + a.textContent = "Click on me!!"; + content.document.body.appendChild(a); + }); + + await openContentContextMenu( + "#testingLink", + "context-sendlinktodevice", + "context-sendlinktodevice-popup" + ); + is( + document.getElementById("context-sendlinktodevice").hidden, + false, + "Send link to device is shown" + ); + is( + document.getElementById("context-sendlinktodevice").disabled, + false, + "Send link to device is enabled" + ); + document + .getElementById("context-sendlinktodevice-popup") + .querySelector("menuitem") + .click(); + await hideContentContextMenu(); + + expectation.verify(); + sandbox.restore(); +}); + +add_task(async function test_page_contextmenu_no_remote_clients() { + const sandbox = setupSendTabMocks({ fxaDevices: [] }); + + await openContentContextMenu("#moztext", "context-sendpagetodevice"); + is( + document.getElementById("context-sendpagetodevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context-sendpagetodevice").disabled, + false, + "Send tab to device is enabled" + ); + checkPopup([ + { label: "No Devices Connected", disabled: true }, + "----", + { label: "Connect Another Device..." }, + { label: "Learn About Sending Tabs..." }, + ]); + await hideContentContextMenu(); + + sandbox.restore(); +}); + +add_task(async function test_page_contextmenu_one_remote_client() { + const sandbox = setupSendTabMocks({ + fxaDevices: [ + { + id: 1, + name: "Foo", + availableCommands: { + "https://identity.mozilla.com/cmd/open-uri": "baz", + }, + }, + ], + }); + + await openContentContextMenu("#moztext", "context-sendpagetodevice"); + is( + document.getElementById("context-sendpagetodevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context-sendpagetodevice").disabled, + false, + "Send tab to device is enabled" + ); + checkPopup([{ label: "Foo" }]); + await hideContentContextMenu(); + + sandbox.restore(); +}); + +add_task(async function test_page_contextmenu_not_sendable() { + const sandbox = setupSendTabMocks({ fxaDevices, isSendableURI: false }); + + await openContentContextMenu("#moztext"); + is( + document.getElementById("context-sendpagetodevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context-sendpagetodevice").disabled, + true, + "Send tab to device is disabled" + ); + checkPopup(); + await hideContentContextMenu(); + + sandbox.restore(); +}); + +add_task(async function test_page_contextmenu_not_synced_yet() { + const sandbox = setupSendTabMocks({ fxaDevices: null }); + + await openContentContextMenu("#moztext"); + is( + document.getElementById("context-sendpagetodevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context-sendpagetodevice").disabled, + true, + "Send tab to device is disabled" + ); + checkPopup(); + await hideContentContextMenu(); + + sandbox.restore(); +}); + +add_task(async function test_page_contextmenu_sync_not_ready_configured() { + const sandbox = setupSendTabMocks({ syncReady: false }); + + await openContentContextMenu("#moztext"); + is( + document.getElementById("context-sendpagetodevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context-sendpagetodevice").disabled, + true, + "Send tab to device is disabled" + ); + checkPopup(); + await hideContentContextMenu(); + + sandbox.restore(); +}); + +add_task(async function test_page_contextmenu_sync_not_ready_other_state() { + const sandbox = setupSendTabMocks({ + syncReady: false, + state: UIState.STATUS_NOT_VERIFIED, + }); + + await openContentContextMenu("#moztext", "context-sendpagetodevice"); + is( + document.getElementById("context-sendpagetodevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context-sendpagetodevice").disabled, + false, + "Send tab to device is enabled" + ); + checkPopup([ + { label: "Account Not Verified", disabled: true }, + "----", + { label: "Verify Your Account..." }, + ]); + await hideContentContextMenu(); + + sandbox.restore(); +}); + +add_task(async function test_page_contextmenu_unconfigured() { + const sandbox = setupSendTabMocks({ state: UIState.STATUS_NOT_CONFIGURED }); + + await openContentContextMenu("#moztext", "context-sendpagetodevice"); + is( + document.getElementById("context-sendpagetodevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context-sendpagetodevice").disabled, + false, + "Send tab to device is enabled" + ); + checkPopup([ + { label: "Not Signed In", disabled: true }, + "----", + { label: "Sign in to Firefox..." }, + { label: "Learn About Sending Tabs..." }, + ]); + + await hideContentContextMenu(); + + sandbox.restore(); +}); + +add_task(async function test_page_contextmenu_not_verified() { + const sandbox = setupSendTabMocks({ state: UIState.STATUS_NOT_VERIFIED }); + + await openContentContextMenu("#moztext", "context-sendpagetodevice"); + is( + document.getElementById("context-sendpagetodevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context-sendpagetodevice").disabled, + false, + "Send tab to device is enabled" + ); + checkPopup([ + { label: "Account Not Verified", disabled: true }, + "----", + { label: "Verify Your Account..." }, + ]); + + await hideContentContextMenu(); + + sandbox.restore(); +}); + +add_task(async function test_page_contextmenu_login_failed() { + const sandbox = setupSendTabMocks({ state: UIState.STATUS_LOGIN_FAILED }); + + await openContentContextMenu("#moztext", "context-sendpagetodevice"); + is( + document.getElementById("context-sendpagetodevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context-sendpagetodevice").disabled, + false, + "Send tab to device is enabled" + ); + checkPopup([ + { label: "Account Not Verified", disabled: true }, + "----", + { label: "Verify Your Account..." }, + ]); + + await hideContentContextMenu(); + + sandbox.restore(); +}); + +add_task(async function test_page_contextmenu_fxa_disabled() { + const getter = sinon.stub(gSync, "FXA_ENABLED").get(() => false); + gSync.onFxaDisabled(); // Would have been called on gSync initialization if FXA_ENABLED had been set. + await openContentContextMenu("#moztext"); + is( + document.getElementById("context-sendpagetodevice").hidden, + true, + "Send tab to device is hidden" + ); + is( + document.getElementById("context-sep-sendpagetodevice").hidden, + true, + "Separator is also hidden" + ); + await hideContentContextMenu(); + getter.restore(); + [...document.querySelectorAll(".sync-ui-item")].forEach( + e => (e.hidden = false) + ); +}); + +// We are not going to bother testing the visibility of context-sendlinktodevice +// since it uses the exact same code. +// However, browser_contextmenu.js contains tests that verify its presence. + +add_task(async function teardown() { + Weave.Service.clientsEngine.getClientByFxaDeviceId.restore(); + Weave.Service.clientsEngine.getClientType.restore(); + gBrowser.removeCurrentTab(); +}); + +function checkPopup(expectedItems = null) { + const popup = document.getElementById("context-sendpagetodevice-popup"); + if (!expectedItems) { + is(popup.state, "closed", "Popup should be hidden."); + return; + } + const menuItems = popup.children; + for (let i = 0; i < menuItems.length; i++) { + const menuItem = menuItems[i]; + const expectedItem = expectedItems[i]; + if (expectedItem === "----") { + is(menuItem.nodeName, "menuseparator", "Found a separator"); + continue; + } + is(menuItem.nodeName, "menuitem", "Found a menu item"); + // Bug workaround, menuItem.label "…" encoding is different than ours. + is( + menuItem.label.normalize("NFKC"), + expectedItem.label, + "Correct menu item label" + ); + is( + menuItem.disabled, + !!expectedItem.disabled, + "Correct menu item disabled state" + ); + } + // check the length last - the above loop might have given us other clues... + is( + menuItems.length, + expectedItems.length, + "Popup has the expected children count." + ); +} + +async function openContentContextMenu(selector, openSubmenuId = null) { + const contextMenu = document.getElementById("contentAreaContextMenu"); + is(contextMenu.state, "closed", "checking if popup is closed"); + + const awaitPopupShown = BrowserTestUtils.waitForEvent( + contextMenu, + "popupshown" + ); + await BrowserTestUtils.synthesizeMouse( + selector, + 0, + 0, + { + type: "contextmenu", + button: 2, + shiftkey: false, + centered: true, + }, + gBrowser.selectedBrowser + ); + await awaitPopupShown; + + if (openSubmenuId) { + const menuPopup = document.getElementById(openSubmenuId).menupopup; + const menuPopupPromise = BrowserTestUtils.waitForEvent( + menuPopup, + "popupshown" + ); + menuPopup.openPopup(); + await menuPopupPromise; + } +} + +async function hideContentContextMenu() { + const contextMenu = document.getElementById("contentAreaContextMenu"); + const awaitPopupHidden = BrowserTestUtils.waitForEvent( + contextMenu, + "popuphidden" + ); + contextMenu.hidePopup(); + await awaitPopupHidden; +} diff --git a/browser/base/content/test/sync/browser_contextmenu_sendtab.js b/browser/base/content/test/sync/browser_contextmenu_sendtab.js new file mode 100644 index 0000000000..cecc738aac --- /dev/null +++ b/browser/base/content/test/sync/browser_contextmenu_sendtab.js @@ -0,0 +1,267 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const chrome_base = + "chrome://mochitests/content/browser/browser/base/content/test/general/"; +Services.scriptloader.loadSubScript(chrome_base + "head.js", this); +/* import-globals-from ../general/head.js */ + +const fxaDevices = [ + { + id: 1, + name: "Foo", + availableCommands: { "https://identity.mozilla.com/cmd/open-uri": "baz" }, + }, + { id: 2, name: "Bar", clientRecord: "bar" }, // Legacy send tab target (no availableCommands). + { id: 3, name: "Homer" }, // Incompatible target. +]; + +let [testTab] = gBrowser.visibleTabs; + +function updateTabContextMenu(tab = gBrowser.selectedTab) { + let menu = document.getElementById("tabContextMenu"); + var evt = new Event(""); + tab.dispatchEvent(evt); + // The TabContextMenu initializes its strings only on a focus or mouseover event. + // Calls focus event on the TabContextMenu early in the test + gBrowser.selectedTab.focus(); + menu.openPopup(tab, "end_after", 0, 0, true, false, evt); + is( + window.TabContextMenu.contextTab, + tab, + "TabContextMenu context is the expected tab" + ); + menu.hidePopup(); +} + +add_task(async function setup() { + await promiseSyncReady(); + await Services.search.init(); + // gSync.init() is called in a requestIdleCallback. Force its initialization. + gSync.init(); + sinon + .stub(Weave.Service.clientsEngine, "getClientByFxaDeviceId") + .callsFake(fxaDeviceId => { + let target = fxaDevices.find(c => c.id == fxaDeviceId); + return target ? target.clientRecord : null; + }); + sinon.stub(Weave.Service.clientsEngine, "getClientType").returns("desktop"); + await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla"); + registerCleanupFunction(() => { + gBrowser.removeCurrentTab(); + }); + is(gBrowser.visibleTabs.length, 2, "there are two visible tabs"); +}); + +add_task(async function test_sendTabToDevice_callsFlushLogFile() { + const sandbox = setupSendTabMocks({ fxaDevices }); + updateTabContextMenu(testTab); + await openTabContextMenu("context_sendTabToDevice"); + let promiseObserved = promiseObserver("service:log-manager:flush-log-file"); + document + .getElementById("context_sendTabToDevicePopupMenu") + .querySelector("menuitem") + .click(); + + await promiseObserved; + await hideTabContextMenu(); + sandbox.restore(); +}); + +add_task(async function test_tab_contextmenu() { + const sandbox = setupSendTabMocks({ fxaDevices }); + let expectation = sandbox + .mock(gSync) + .expects("sendTabToDevice") + .once() + .withExactArgs( + "about:mozilla", + [fxaDevices[1]], + "The Book of Mozilla, 6:27" + ); + + updateTabContextMenu(testTab); + await openTabContextMenu("context_sendTabToDevice"); + is( + document.getElementById("context_sendTabToDevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context_sendTabToDevice").disabled, + false, + "Send tab to device is enabled" + ); + + document + .getElementById("context_sendTabToDevicePopupMenu") + .querySelector("menuitem") + .click(); + + await hideTabContextMenu(); + expectation.verify(); + sandbox.restore(); +}); + +add_task(async function test_tab_contextmenu_unconfigured() { + const sandbox = setupSendTabMocks({ state: UIState.STATUS_NOT_CONFIGURED }); + + updateTabContextMenu(testTab); + is( + document.getElementById("context_sendTabToDevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context_sendTabToDevice").disabled, + false, + "Send tab to device is enabled" + ); + + sandbox.restore(); +}); + +add_task(async function test_tab_contextmenu_not_sendable() { + const sandbox = setupSendTabMocks({ fxaDevices, isSendableURI: false }); + + updateTabContextMenu(testTab); + is( + document.getElementById("context_sendTabToDevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context_sendTabToDevice").disabled, + true, + "Send tab to device is disabled" + ); + + sandbox.restore(); +}); + +add_task(async function test_tab_contextmenu_not_synced_yet() { + const sandbox = setupSendTabMocks({ fxaDevices: null }); + + updateTabContextMenu(testTab); + is( + document.getElementById("context_sendTabToDevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context_sendTabToDevice").disabled, + true, + "Send tab to device is disabled" + ); + + sandbox.restore(); +}); + +add_task(async function test_tab_contextmenu_sync_not_ready_configured() { + const sandbox = setupSendTabMocks({ syncReady: false }); + + updateTabContextMenu(testTab); + is( + document.getElementById("context_sendTabToDevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context_sendTabToDevice").disabled, + true, + "Send tab to device is disabled" + ); + + sandbox.restore(); +}); + +add_task(async function test_tab_contextmenu_sync_not_ready_other_state() { + const sandbox = setupSendTabMocks({ + syncReady: false, + state: UIState.STATUS_NOT_VERIFIED, + }); + + updateTabContextMenu(testTab); + is( + document.getElementById("context_sendTabToDevice").hidden, + false, + "Send tab to device is shown" + ); + is( + document.getElementById("context_sendTabToDevice").disabled, + false, + "Send tab to device is enabled" + ); + + sandbox.restore(); +}); + +add_task(async function test_tab_contextmenu_fxa_disabled() { + const getter = sinon.stub(gSync, "FXA_ENABLED").get(() => false); + // Simulate onFxaDisabled() being called on window open. + gSync.onFxaDisabled(); + + updateTabContextMenu(testTab); + is( + document.getElementById("context_sendTabToDevice").hidden, + true, + "Send tab to device is hidden" + ); + + getter.restore(); + [...document.querySelectorAll(".sync-ui-item")].forEach( + e => (e.hidden = false) + ); +}); + +add_task(async function teardown() { + Weave.Service.clientsEngine.getClientByFxaDeviceId.restore(); + Weave.Service.clientsEngine.getClientType.restore(); +}); + +async function openTabContextMenu(openSubmenuId = null) { + const contextMenu = document.getElementById("tabContextMenu"); + is(contextMenu.state, "closed", "checking if popup is closed"); + + const awaitPopupShown = BrowserTestUtils.waitForEvent( + contextMenu, + "popupshown" + ); + EventUtils.synthesizeMouseAtCenter(gBrowser.selectedTab, { + type: "contextmenu", + button: 2, + }); + await awaitPopupShown; + + if (openSubmenuId) { + const menuPopup = document.getElementById(openSubmenuId).menupopup; + const menuPopupPromise = BrowserTestUtils.waitForEvent( + menuPopup, + "popupshown" + ); + menuPopup.openPopup(); + await menuPopupPromise; + } +} + +async function hideTabContextMenu() { + const contextMenu = document.getElementById("tabContextMenu"); + const awaitPopupHidden = BrowserTestUtils.waitForEvent( + contextMenu, + "popuphidden" + ); + contextMenu.hidePopup(); + await awaitPopupHidden; +} + +function promiseObserver(topic) { + return new Promise(resolve => { + let obs = (aSubject, aTopic, aData) => { + Services.obs.removeObserver(obs, aTopic); + resolve(aSubject); + }; + Services.obs.addObserver(obs, topic); + }); +} diff --git a/browser/base/content/test/sync/browser_fxa_badge.js b/browser/base/content/test/sync/browser_fxa_badge.js new file mode 100644 index 0000000000..f6a6155c16 --- /dev/null +++ b/browser/base/content/test/sync/browser_fxa_badge.js @@ -0,0 +1,71 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { AppMenuNotifications } = ChromeUtils.import( + "resource://gre/modules/AppMenuNotifications.jsm" +); + +add_task(async function test_unconfigured_no_badge() { + const oldUIState = UIState.get; + + UIState.get = () => ({ + status: UIState.STATUS_NOT_CONFIGURED, + }); + Services.obs.notifyObservers(null, UIState.ON_UPDATE); + checkFxABadge(false); + + UIState.get = oldUIState; +}); + +add_task(async function test_signedin_no_badge() { + const oldUIState = UIState.get; + + UIState.get = () => ({ + status: UIState.STATUS_SIGNED_IN, + lastSync: new Date(), + email: "foo@bar.com", + }); + Services.obs.notifyObservers(null, UIState.ON_UPDATE); + checkFxABadge(false); + + UIState.get = oldUIState; +}); + +add_task(async function test_unverified_badge_shown() { + const oldUIState = UIState.get; + + UIState.get = () => ({ + status: UIState.STATUS_NOT_VERIFIED, + email: "foo@bar.com", + }); + Services.obs.notifyObservers(null, UIState.ON_UPDATE); + checkFxABadge(true); + + UIState.get = oldUIState; +}); + +add_task(async function test_loginFailed_badge_shown() { + const oldUIState = UIState.get; + + UIState.get = () => ({ + status: UIState.STATUS_LOGIN_FAILED, + email: "foo@bar.com", + }); + Services.obs.notifyObservers(null, UIState.ON_UPDATE); + checkFxABadge(true); + + UIState.get = oldUIState; +}); + +function checkFxABadge(shouldBeShown) { + let isShown = false; + for (let notification of AppMenuNotifications.notifications) { + if (notification.id == "fxa-needs-authentication") { + isShown = true; + break; + } + } + is(isShown, shouldBeShown, "Fxa badge shown matches expected value."); +} diff --git a/browser/base/content/test/sync/browser_fxa_web_channel.html b/browser/base/content/test/sync/browser_fxa_web_channel.html new file mode 100644 index 0000000000..c169a9744f --- /dev/null +++ b/browser/base/content/test/sync/browser_fxa_web_channel.html @@ -0,0 +1,138 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>fxa_web_channel_test</title> +</head> +<body> +<script> + var webChannelId = "account_updates_test"; + + window.onload = function() { + var testName = window.location.search.replace(/^\?/, ""); + + switch (testName) { + case "profile_change": + test_profile_change(); + break; + case "login": + test_login(); + break; + case "can_link_account": + test_can_link_account(); + break; + case "logout": + test_logout(); + break; + case "delete": + test_delete(); + break; + } + }; + + function test_profile_change() { + var event = new window.CustomEvent("WebChannelMessageToChrome", { + detail: JSON.stringify({ + id: webChannelId, + message: { + command: "profile:change", + data: { + uid: "abc123", + }, + }, + }), + }); + + window.dispatchEvent(event); + } + + function test_login() { + var event = new window.CustomEvent("WebChannelMessageToChrome", { + detail: JSON.stringify({ + id: webChannelId, + message: { + command: "fxaccounts:login", + data: { + authAt: Date.now(), + email: "testuser@testuser.com", + keyFetchToken: "key_fetch_token", + sessionToken: "session_token", + uid: "uid", + unwrapBKey: "unwrap_b_key", + verified: true, + }, + messageId: 1, + }, + }), + }); + + window.dispatchEvent(event); + } + + function test_can_link_account() { + window.addEventListener("WebChannelMessageToContent", function(e) { + // echo any responses from the browser back to the tests on the + // fxaccounts_webchannel_response_echo WebChannel. The tests are + // listening for events and do the appropriate checks. + var event = new window.CustomEvent("WebChannelMessageToChrome", { + detail: JSON.stringify({ + id: "fxaccounts_webchannel_response_echo", + message: e.detail.message, + }), + }); + + window.dispatchEvent(event); + }, true); + + var event = new window.CustomEvent("WebChannelMessageToChrome", { + detail: JSON.stringify({ + id: webChannelId, + message: { + command: "fxaccounts:can_link_account", + data: { + email: "testuser@testuser.com", + }, + messageId: 2, + }, + }), + }); + + window.dispatchEvent(event); + } + + function test_logout() { + var event = new window.CustomEvent("WebChannelMessageToChrome", { + detail: JSON.stringify({ + id: webChannelId, + message: { + command: "fxaccounts:logout", + data: { + uid: "uid", + }, + messageId: 3, + }, + }), + }); + + window.dispatchEvent(event); + } + + function test_delete() { + var event = new window.CustomEvent("WebChannelMessageToChrome", { + detail: JSON.stringify({ + id: webChannelId, + message: { + command: "fxaccounts:delete", + data: { + uid: "uid", + }, + messageId: 4, + }, + }), + }); + + window.dispatchEvent(event); + } +</script> +</body> +</html> diff --git a/browser/base/content/test/sync/browser_fxa_web_channel.js b/browser/base/content/test/sync/browser_fxa_web_channel.js new file mode 100644 index 0000000000..5e5f43aa32 --- /dev/null +++ b/browser/base/content/test/sync/browser_fxa_web_channel.js @@ -0,0 +1,248 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function() { + return ChromeUtils.import("resource://gre/modules/FxAccountsCommon.js", {}); +}); + +ChromeUtils.defineModuleGetter( + this, + "WebChannel", + "resource://gre/modules/WebChannel.jsm" +); + +// FxAccountsWebChannel isn't explicitly exported by FxAccountsWebChannel.jsm +// but we can get it here via a backstage pass. +var { FxAccountsWebChannel } = ChromeUtils.import( + "resource://gre/modules/FxAccountsWebChannel.jsm", + null +); + +const TEST_HTTP_PATH = "http://example.com"; +const TEST_BASE_URL = + TEST_HTTP_PATH + + "/browser/browser/base/content/test/sync/browser_fxa_web_channel.html"; +const TEST_CHANNEL_ID = "account_updates_test"; + +var gTests = [ + { + desc: "FxA Web Channel - should receive message about profile changes", + async run() { + let client = new FxAccountsWebChannel({ + content_uri: TEST_HTTP_PATH, + channel_id: TEST_CHANNEL_ID, + }); + let promiseObserver = new Promise((resolve, reject) => { + makeObserver(FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION, function( + subject, + topic, + data + ) { + Assert.equal(data, "abc123"); + client.tearDown(); + resolve(); + }); + }); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_BASE_URL + "?profile_change", + }, + async function() { + await promiseObserver; + } + ); + }, + }, + { + desc: + "fxa web channel - login messages should notify the fxAccounts object", + async run() { + let promiseLogin = new Promise((resolve, reject) => { + let login = accountData => { + Assert.equal(typeof accountData.authAt, "number"); + Assert.equal(accountData.email, "testuser@testuser.com"); + Assert.equal(accountData.keyFetchToken, "key_fetch_token"); + Assert.equal(accountData.sessionToken, "session_token"); + Assert.equal(accountData.uid, "uid"); + Assert.equal(accountData.unwrapBKey, "unwrap_b_key"); + Assert.equal(accountData.verified, true); + + client.tearDown(); + resolve(); + }; + + let client = new FxAccountsWebChannel({ + content_uri: TEST_HTTP_PATH, + channel_id: TEST_CHANNEL_ID, + helpers: { + login, + }, + }); + }); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_BASE_URL + "?login", + }, + async function() { + await promiseLogin; + } + ); + }, + }, + { + desc: "fxa web channel - can_link_account messages should respond", + async run() { + let properUrl = TEST_BASE_URL + "?can_link_account"; + + let promiseEcho = new Promise((resolve, reject) => { + let webChannelOrigin = Services.io.newURI(properUrl); + // responses sent to content are echoed back over the + // `fxaccounts_webchannel_response_echo` channel. Ensure the + // fxaccounts:can_link_account message is responded to. + let echoWebChannel = new WebChannel( + "fxaccounts_webchannel_response_echo", + webChannelOrigin + ); + echoWebChannel.listen((webChannelId, message, target) => { + Assert.equal(message.command, "fxaccounts:can_link_account"); + Assert.equal(message.messageId, 2); + Assert.equal(message.data.ok, true); + + client.tearDown(); + echoWebChannel.stopListening(); + + resolve(); + }); + + let client = new FxAccountsWebChannel({ + content_uri: TEST_HTTP_PATH, + channel_id: TEST_CHANNEL_ID, + helpers: { + shouldAllowRelink(acctName) { + return acctName === "testuser@testuser.com"; + }, + }, + }); + }); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: properUrl, + }, + async function() { + await promiseEcho; + } + ); + }, + }, + { + desc: + "fxa web channel - logout messages should notify the fxAccounts object", + async run() { + let promiseLogout = new Promise((resolve, reject) => { + let logout = uid => { + Assert.equal(uid, "uid"); + + client.tearDown(); + resolve(); + }; + + let client = new FxAccountsWebChannel({ + content_uri: TEST_HTTP_PATH, + channel_id: TEST_CHANNEL_ID, + helpers: { + logout, + }, + }); + }); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_BASE_URL + "?logout", + }, + async function() { + await promiseLogout; + } + ); + }, + }, + { + desc: + "fxa web channel - delete messages should notify the fxAccounts object", + async run() { + let promiseDelete = new Promise((resolve, reject) => { + let logout = uid => { + Assert.equal(uid, "uid"); + + client.tearDown(); + resolve(); + }; + + let client = new FxAccountsWebChannel({ + content_uri: TEST_HTTP_PATH, + channel_id: TEST_CHANNEL_ID, + helpers: { + logout, + }, + }); + }); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_BASE_URL + "?delete", + }, + async function() { + await promiseDelete; + } + ); + }, + }, +]; // gTests + +function makeObserver(aObserveTopic, aObserveFunc) { + let callback = function(aSubject, aTopic, aData) { + if (aTopic == aObserveTopic) { + removeMe(); + aObserveFunc(aSubject, aTopic, aData); + } + }; + + function removeMe() { + Services.obs.removeObserver(callback, aObserveTopic); + } + + Services.obs.addObserver(callback, aObserveTopic); + return removeMe; +} + +registerCleanupFunction(function() { + Services.prefs.clearUserPref( + "browser.tabs.remote.separatePrivilegedMozillaWebContentProcess" + ); +}); + +function test() { + waitForExplicitFinish(); + Services.prefs.setBoolPref( + "browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", + false + ); + + (async function() { + for (let testCase of gTests) { + info("Running: " + testCase.desc); + await testCase.run(); + } + })().then(finish, ex => { + Assert.ok(false, "Unexpected Exception: " + ex); + finish(); + }); +} diff --git a/browser/base/content/test/sync/browser_sync.js b/browser/base/content/test/sync/browser_sync.js new file mode 100644 index 0000000000..c1b62ae6fb --- /dev/null +++ b/browser/base/content/test/sync/browser_sync.js @@ -0,0 +1,608 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(function setup() { + // gSync.init() is called in a requestIdleCallback. Force its initialization. + gSync.init(); +}); + +add_task(async function test_ui_state_notification_calls_updateAllUI() { + let called = false; + let updateAllUI = gSync.updateAllUI; + gSync.updateAllUI = () => { + called = true; + }; + + Services.obs.notifyObservers(null, UIState.ON_UPDATE); + ok(called); + + gSync.updateAllUI = updateAllUI; +}); + +add_task(async function test_ui_state_signedin() { + await openTabAndRemoteTabsPanel(); + + const relativeDateAnchor = new Date(); + let state = { + status: UIState.STATUS_SIGNED_IN, + syncEnabled: true, + email: "foo@bar.com", + displayName: "Foo Bar", + avatarURL: "https://foo.bar", + lastSync: new Date(), + syncing: false, + }; + + const origRelativeTimeFormat = gSync.relativeTimeFormat; + gSync.relativeTimeFormat = { + formatBestUnit(date) { + return origRelativeTimeFormat.formatBestUnit(date, { + now: relativeDateAnchor, + }); + }, + }; + + gSync.updateAllUI(state); + checkRemoteTabsPanel("PanelUI-remotetabs-main", false); + checkMenuBarItem("sync-syncnowitem"); + checkFxaToolbarButtonPanel({ + headerTitle: "foo@bar.com", + headerDescription: "Account Settings", + enabledItems: [ + "PanelUI-fxa-menu-sendtab-button", + "PanelUI-fxa-menu-connect-device-button", + "PanelUI-fxa-menu-syncnow-button", + "PanelUI-fxa-menu-remotetabs-button", + "PanelUI-fxa-menu-sync-prefs-button", + "PanelUI-fxa-menu-logins-button", + "PanelUI-fxa-menu-monitor-button", + "PanelUI-fxa-menu-send-button", + ], + disabledItems: [], + hiddenItems: ["PanelUI-fxa-menu-setup-sync-button"], + }); + checkFxAAvatar("signedin"); + gSync.relativeTimeFormat = origRelativeTimeFormat; + await closeRemoteTabsPanel(); + + await openMainPanel(); + + checkPanelUIStatusBar({ + label: "foo@bar.com", + fxastatus: "signedin", + syncing: false, + }); + + await closeTabAndMainPanel(); +}); + +add_task(async function test_ui_state_syncing() { + let state = { + status: UIState.STATUS_SIGNED_IN, + syncEnabled: true, + email: "foo@bar.com", + displayName: "Foo Bar", + avatarURL: "https://foo.bar", + lastSync: new Date(), + syncing: true, + }; + + gSync.updateAllUI(state); + + checkSyncNowButtons(true); + + // Be good citizens and remove the "syncing" state. + gSync.updateAllUI({ + status: UIState.STATUS_SIGNED_IN, + syncEnabled: true, + email: "foo@bar.com", + lastSync: new Date(), + syncing: false, + }); + // Because we switch from syncing to non-syncing, and there's a timeout involved. + await promiseObserver("test:browser-sync:activity-stop"); +}); + +add_task(async function test_ui_state_unconfigured() { + await openTabAndRemoteTabsPanel(); + + let state = { + status: UIState.STATUS_NOT_CONFIGURED, + }; + + gSync.updateAllUI(state); + + let signedOffLabel = gSync.appMenuStatus.getAttribute("defaultlabel"); + checkPanelUIStatusBar({ + label: signedOffLabel, + }); + checkRemoteTabsPanel("PanelUI-remotetabs-setupsync"); + checkMenuBarItem("sync-setup"); + checkFxaToolbarButtonPanel({ + headerTitle: signedOffLabel, + headerDescription: "Turn on Sync", + enabledItems: [ + "PanelUI-fxa-menu-sendtab-button", + "PanelUI-fxa-menu-setup-sync-button", + "PanelUI-fxa-menu-remotetabs-button", + "PanelUI-fxa-menu-logins-button", + "PanelUI-fxa-menu-monitor-button", + "PanelUI-fxa-menu-send-button", + ], + disabledItems: ["PanelUI-fxa-menu-connect-device-button"], + hiddenItems: [ + "PanelUI-fxa-menu-syncnow-button", + "PanelUI-fxa-menu-sync-prefs-button", + ], + }); + checkFxAAvatar("not_configured"); + await closeRemoteTabsPanel(); + + await openMainPanel(); + + checkPanelUIStatusBar({ + label: signedOffLabel, + }); + + await closeTabAndMainPanel(); +}); + +add_task(async function test_ui_state_syncdisabled() { + await openTabAndRemoteTabsPanel(); + + let state = { + status: UIState.STATUS_SIGNED_IN, + syncEnabled: false, + email: "foo@bar.com", + displayName: "Foo Bar", + avatarURL: "https://foo.bar", + }; + + gSync.updateAllUI(state); + checkRemoteTabsPanel("PanelUI-remotetabs-syncdisabled", false); + checkMenuBarItem("sync-enable"); + checkFxaToolbarButtonPanel({ + headerTitle: "foo@bar.com", + headerDescription: "Account Settings", + enabledItems: [ + "PanelUI-fxa-menu-sendtab-button", + "PanelUI-fxa-menu-connect-device-button", + "PanelUI-fxa-menu-setup-sync-button", + "PanelUI-fxa-menu-remotetabs-button", + "PanelUI-fxa-menu-logins-button", + "PanelUI-fxa-menu-monitor-button", + "PanelUI-fxa-menu-send-button", + ], + disabledItems: [], + hiddenItems: [ + "PanelUI-fxa-menu-syncnow-button", + "PanelUI-fxa-menu-sync-prefs-button", + ], + }); + checkFxAAvatar("signedin"); + await closeRemoteTabsPanel(); + + await openMainPanel(); + + checkPanelUIStatusBar({ + label: "foo@bar.com", + fxastatus: "signedin", + syncing: false, + }); + + await closeTabAndMainPanel(); +}); + +add_task(async function test_ui_state_unverified() { + await openTabAndRemoteTabsPanel(); + + let state = { + status: UIState.STATUS_NOT_VERIFIED, + email: "foo@bar.com", + syncing: false, + }; + + gSync.updateAllUI(state); + + const expectedLabel = gSync.fxaStrings.GetStringFromName( + "account.finishAccountSetup" + ); + + checkRemoteTabsPanel("PanelUI-remotetabs-unverified", false); + checkMenuBarItem("sync-unverifieditem"); + checkFxaToolbarButtonPanel({ + headerTitle: expectedLabel, + headerDescription: state.email, + enabledItems: [ + "PanelUI-fxa-menu-sendtab-button", + "PanelUI-fxa-menu-setup-sync-button", + "PanelUI-fxa-menu-remotetabs-button", + "PanelUI-fxa-menu-logins-button", + "PanelUI-fxa-menu-monitor-button", + "PanelUI-fxa-menu-send-button", + ], + disabledItems: ["PanelUI-fxa-menu-connect-device-button"], + hiddenItems: [ + "PanelUI-fxa-menu-syncnow-button", + "PanelUI-fxa-menu-sync-prefs-button", + ], + }); + checkFxAAvatar("unverified"); + await closeRemoteTabsPanel(); + await openMainPanel(); + + checkPanelUIStatusBar({ + label: expectedLabel, + fxastatus: "unverified", + syncing: false, + }); + + await closeTabAndMainPanel(); +}); + +add_task(async function test_ui_state_loginFailed() { + await openTabAndRemoteTabsPanel(); + + let state = { + status: UIState.STATUS_LOGIN_FAILED, + email: "foo@bar.com", + }; + + gSync.updateAllUI(state); + + const expectedLabel = gSync.fxaStrings.GetStringFromName( + "account.reconnectToFxA" + ); + + checkRemoteTabsPanel("PanelUI-remotetabs-reauthsync", false); + checkMenuBarItem("sync-reauthitem"); + checkFxaToolbarButtonPanel({ + headerTitle: expectedLabel, + headerDescription: state.email, + enabledItems: [ + "PanelUI-fxa-menu-sendtab-button", + "PanelUI-fxa-menu-setup-sync-button", + "PanelUI-fxa-menu-remotetabs-button", + "PanelUI-fxa-menu-logins-button", + "PanelUI-fxa-menu-monitor-button", + "PanelUI-fxa-menu-send-button", + ], + disabledItems: ["PanelUI-fxa-menu-connect-device-button"], + hiddenItems: [ + "PanelUI-fxa-menu-syncnow-button", + "PanelUI-fxa-menu-sync-prefs-button", + ], + }); + checkFxAAvatar("login-failed"); + await closeRemoteTabsPanel(); + await openMainPanel(); + + checkPanelUIStatusBar({ + label: expectedLabel, + fxastatus: "login-failed", + syncing: false, + }); + + await closeTabAndMainPanel(); +}); + +add_task(async function test_account_settings_state_signedin() { + await BrowserTestUtils.openNewForegroundTab(gBrowser, "https://example.com/"); + const relativeDateAnchor = new Date(); + let state = { + status: UIState.STATUS_SIGNED_IN, + syncEnabled: true, + email: "foo@bar.com", + displayName: "Foo Bar", + avatarURL: "https://foo.bar", + lastSync: new Date(), + syncing: false, + }; + + const origRelativeTimeFormat = gSync.relativeTimeFormat; + gSync.relativeTimeFormat = { + formatBestUnit(date) { + return origRelativeTimeFormat.formatBestUnit(date, { + now: relativeDateAnchor, + }); + }, + }; + + gSync.updateAllUI(state); + + await checkAccountPanel([ + "PanelUI-fxa-menu-account-settings-button", + "PanelUI-fxa-menu-account-signout-button", + ]); + await closeRemoteTabsPanel(); + await openMainPanel(); + + checkPanelUIStatusBar({ + label: "foo@bar.com", + fxastatus: "signedin", + syncing: false, + }); + + await closeTabAndMainPanel(); +}); + +add_task(async function test_app_menu_fxa_disabled() { + const newWin = await BrowserTestUtils.openNewBrowserWindow(); + + Services.prefs.setBoolPref("identity.fxaccounts.enabled", true); + newWin.gSync.onFxaDisabled(); + + let menuButton = newWin.document.getElementById("PanelUI-menu-button"); + menuButton.click(); + await BrowserTestUtils.waitForEvent(newWin.PanelUI.mainView, "ViewShown"); + + ok( + BrowserTestUtils.is_hidden( + newWin.document.getElementById("appMenu-fxa-status") + ), + "Fxa status is hidden" + ); + + [...newWin.document.querySelectorAll(".sync-ui-item")].forEach( + e => (e.hidden = false) + ); + let mainView = newWin.document.getElementById("appMenu-mainView"); + let hidden = BrowserTestUtils.waitForEvent( + newWin.document, + "popuphidden", + true + ); + mainView.closest("panel").hidePopup(); + await hidden; + await BrowserTestUtils.closeWindow(newWin); +}); + +function checkPanelUIStatusBar({ label, fxastatus, syncing }) { + let labelNode = document.getElementById("appMenu-fxa-label"); + is(labelNode.getAttribute("label"), label, "fxa label has the right value"); +} + +function checkRemoteTabsPanel(expectedShownItemId, syncing, syncNowTooltip) { + checkItemsVisibilities( + [ + "PanelUI-remotetabs-main", + "PanelUI-remotetabs-setupsync", + "PanelUI-remotetabs-reauthsync", + "PanelUI-remotetabs-unverified", + ], + expectedShownItemId + ); + + if (syncing != undefined && syncNowTooltip != undefined) { + checkSyncNowButtons(syncing, syncNowTooltip); + } +} + +function checkMenuBarItem(expectedShownItemId) { + checkItemsVisibilities( + [ + "sync-setup", + "sync-enable", + "sync-syncnowitem", + "sync-reauthitem", + "sync-unverifieditem", + ], + expectedShownItemId + ); +} + +function checkSyncNowButtons(syncing, tooltip = null) { + const syncButtons = document.querySelectorAll(".syncNowBtn"); + + for (const syncButton of syncButtons) { + is( + syncButton.getAttribute("syncstatus"), + syncing ? "active" : "", + "button active has the right value" + ); + if (tooltip) { + is( + syncButton.getAttribute("tooltiptext"), + tooltip, + "button tooltiptext is set to the right value" + ); + } + + is( + syncButton.hasAttribute("disabled"), + syncing, + "disabled has the right value" + ); + if (syncing) { + is( + document.l10n.getAttributes(syncButton).id, + syncButton.getAttribute("syncinglabel"), + "label is set to the right value" + ); + } else { + is( + document.l10n.getAttributes(syncButton).id, + "fxa-toolbar-sync-now", + "label is set to the right value" + ); + } + } +} + +async function checkFxaToolbarButtonPanel({ + headerTitle, + headerDescription, + enabledItems, + disabledItems, + hiddenItems, +}) { + is( + document.getElementById("fxa-menu-header-title").value, + headerTitle, + "has correct title" + ); + is( + document.getElementById("fxa-menu-header-description").value, + headerDescription, + "has correct description" + ); + + for (const id of enabledItems) { + const el = document.getElementById(id); + is(el.hasAttribute("disabled"), false, id + " is enabled"); + } + + for (const id of disabledItems) { + const el = document.getElementById(id); + is(el.getAttribute("disabled"), "true", id + " is disabled"); + } + + for (const id of hiddenItems) { + const el = document.getElementById(id); + let elShown = window.getComputedStyle(el).display == "none"; + is(elShown, true, id + " is hidden"); + } +} + +async function checkFxABadged() { + const button = document.getElementById("fxa-toolbar-menu-button"); + await BrowserTestUtils.waitForCondition(() => { + return button.querySelector("label.feature-callout"); + }); + const badge = button.querySelector("label.feature-callout"); + ok(badge, "expected feature-callout style badge"); + ok(BrowserTestUtils.is_visible(badge), "expected the badge to be visible"); +} + +// fxaStatus is one of 'not_configured', 'unverified', 'login-failed', or 'signedin'. +function checkFxAAvatar(fxaStatus) { + // Unhide the panel so computed styles can be read + document.querySelector("#appMenu-popup").hidden = false; + + const avatarContainers = [ + document.getElementById("fxa-menu-avatar"), + document.getElementById("fxa-avatar-image"), + ]; + for (const avatar of avatarContainers) { + const avatarURL = getComputedStyle(avatar).listStyleImage; + const expected = { + not_configured: 'url("chrome://browser/skin/fxa/avatar-empty.svg")', + unverified: 'url("chrome://browser/skin/fxa/avatar-confirm.svg")', + signedin: 'url("chrome://browser/skin/fxa/avatar.svg")', + "login-failed": 'url("chrome://browser/skin/fxa/avatar-alert.svg")', + }; + ok( + avatarURL == expected[fxaStatus], + `expected avatar URL to be ${expected[fxaStatus]}, got ${avatarURL}` + ); + } +} + +async function checkAccountPanel(enabledItems) { + let fxaButton = document.getElementById("fxa-toolbar-menu-button"); + fxaButton.click(); + + let fxaView = document.getElementById("PanelUI-fxa"); + await BrowserTestUtils.waitForEvent(fxaView, "ViewShown"); + + let manageAccountButton = document.getElementById( + "fxa-manage-account-button" + ); + PanelUI.showSubView("PanelUI-fxa-menu-account-panel", manageAccountButton); + + let manageAccountPanel = document.getElementById( + "PanelUI-fxa-menu-account-panel" + ); + await BrowserTestUtils.waitForEvent(manageAccountPanel, "ViewShown"); + + for (const id of enabledItems) { + const el = document.getElementById(id); + is(el.hasAttribute("disabled"), false, id + " is enabled"); + } +} + +// Only one item displayed at a time. +function checkItemsDisplayed(itemsIds, expectedShownItemId) { + for (let id of itemsIds) { + if (id == expectedShownItemId) { + ok( + BrowserTestUtils.is_visible(document.getElementById(id)), + `view ${id} should be visible` + ); + } else { + ok( + BrowserTestUtils.is_hidden(document.getElementById(id)), + `view ${id} should be hidden` + ); + } + } +} + +// Only one item visible at a time. +function checkItemsVisibilities(itemsIds, expectedShownItemId) { + for (let id of itemsIds) { + if (id == expectedShownItemId) { + ok( + !document.getElementById(id).hidden, + "menuitem " + id + " should be visible" + ); + } else { + ok( + document.getElementById(id).hidden, + "menuitem " + id + " should be hidden" + ); + } + } +} + +function promiseObserver(topic) { + return new Promise(resolve => { + let obs = (aSubject, aTopic, aData) => { + Services.obs.removeObserver(obs, aTopic); + resolve(aSubject); + }; + Services.obs.addObserver(obs, topic); + }); +} + +async function openTabAndRemoteTabsPanel() { + await BrowserTestUtils.openNewForegroundTab(gBrowser, "https://example.com/"); + + let fxaButton = document.getElementById("fxa-toolbar-menu-button"); + fxaButton.click(); + + let fxaView = document.getElementById("PanelUI-fxa"); + await BrowserTestUtils.waitForEvent(fxaView, "ViewShown"); + + let remoteTabsButton = document.getElementById( + "PanelUI-fxa-menu-remotetabs-button" + ); + remoteTabsButton.click(); + + let remoteTabsView = document.getElementById("PanelUI-remotetabs"); + await BrowserTestUtils.waitForEvent(remoteTabsView, "ViewShown"); +} + +async function closeRemoteTabsPanel() { + let fxaView = document.getElementById("PanelUI-fxa"); + let hidden = BrowserTestUtils.waitForEvent(document, "popuphidden", true); + fxaView.closest("panel").hidePopup(); + await hidden; +} + +async function openMainPanel() { + let menuButton = document.getElementById("PanelUI-menu-button"); + menuButton.click(); + await BrowserTestUtils.waitForEvent(window.PanelUI.mainView, "ViewShown"); +} + +async function closeTabAndMainPanel() { + let mainView = document.getElementById("appMenu-mainView"); + let hidden = BrowserTestUtils.waitForEvent(document, "popuphidden", true); + mainView.closest("panel").hidePopup(); + await hidden; + + BrowserTestUtils.removeTab(gBrowser.selectedTab); +} diff --git a/browser/base/content/test/sync/head.js b/browser/base/content/test/sync/head.js new file mode 100644 index 0000000000..d6ca8d9b98 --- /dev/null +++ b/browser/base/content/test/sync/head.js @@ -0,0 +1,24 @@ +ChromeUtils.import("resource://services-sync/UIState.jsm", this); +const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm"); + +function promiseSyncReady() { + let service = Cc["@mozilla.org/weave/service;1"].getService(Ci.nsISupports) + .wrappedJSObject; + return service.whenLoaded(); +} + +function setupSendTabMocks({ + fxaDevices = null, + state = UIState.STATUS_SIGNED_IN, + isSendableURI = true, +}) { + const sandbox = sinon.createSandbox(); + sandbox.stub(fxAccounts.device, "recentDeviceList").get(() => fxaDevices); + sandbox.stub(UIState, "get").returns({ + status: state, + syncEnabled: true, + }); + sandbox.stub(gSync, "isSendableURI").returns(isSendableURI); + sandbox.stub(fxAccounts.device, "refreshDeviceList").resolves(true); + return sandbox; +} |