Backed out 2 changesets (bug 1368383) for a11y failures in test_focus_general.html a=backout
authorWes Kocher <wkocher@mozilla.com>
Wed, 07 Jun 2017 15:00:41 -0700
changeset 410989 807243861494284b3dc25ebad7bfe3877529b1d4
parent 410988 4795dae51ea662221496c708635ff8cf8f72fd7c
child 410990 c46606ac60c8ce5a07798aa63e4717f54cc14e5e
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1368383
milestone55.0a1
backs out4eb7778c4325c8ab17c4576aaf57e952cddbadbe
3ca93081969bdb74ada3974ce36afa7dd327bbb2
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 2 changesets (bug 1368383) for a11y failures in test_focus_general.html a=backout Backed out changeset 4eb7778c4325 (bug 1368383) Backed out changeset 3ca93081969b (bug 1368383) MozReview-Commit-ID: BZfthG2g9FE
browser/app/profile/firefox.js
browser/base/content/browser-sync.js
browser/base/content/browser.css
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/test/contextMenu/browser_contextmenu_mozextension.js
browser/base/content/test/general/browser_contextmenu.js
browser/base/content/test/general/browser_visibleTabs_contextMenu.js
browser/base/content/test/general/head.js
browser/base/content/test/sync/browser.ini
browser/base/content/test/sync/browser_contextmenu_sendpage.js
browser/base/content/test/sync/browser_contextmenu_sendtab.js
browser/base/content/test/sync/head.js
browser/base/content/test/urlbar/browser_page_action_menu.js
browser/locales/en-US/chrome/browser/browser.dtd
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1206,16 +1206,18 @@ pref("services.sync.prefs.sync.spellchec
 pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
 
 // A preference that controls whether we should show the icon for a remote tab.
 // This pref has no UI but exists because some people may be concerned that
 // fetching these icons to show remote tabs may leak information about that
 // user's tabs and bookmarks. Note this pref is also synced.
 pref("services.sync.syncedTabs.showRemoteIcons", true);
 
+pref("services.sync.sendTabToDevice.enabled", true);
+
 // Developer edition preferences
 #ifdef MOZ_DEV_EDITION
 sticky_pref("lightweightThemes.selectedThemeID", "firefox-compact-dark@mozilla.org");
 #else
 sticky_pref("lightweightThemes.selectedThemeID", "");
 #endif
 
 // Whether the character encoding menu is under the main Firefox button. This
--- a/browser/base/content/browser-sync.js
+++ b/browser/base/content/browser-sync.js
@@ -35,22 +35,18 @@ var gSync = {
     delete this.syncStrings;
     // XXXzpao these strings should probably be moved from /services to /browser... (bug 583381)
     //        but for now just make it work
     return this.syncStrings = Services.strings.createBundle(
       "chrome://weave/locale/sync.properties"
     );
   },
 
-  get syncReady() {
-    return Cc["@mozilla.org/weave/service;1"].getService().wrappedJSObject.ready;
-  },
-
-  get isSignedIn() {
-    return UIState.get().status == UIState.STATUS_SIGNED_IN;
+  get sendTabToDeviceEnabled() {
+    return Services.prefs.getBoolPref("services.sync.sendTabToDevice.enabled");
   },
 
   get remoteClients() {
     return Weave.Service.clientsEngine.remoteClients
            .sort((a, b) => a.name.localeCompare(b.name));
   },
 
   _generateNodeGetters(usePhoton) {
@@ -296,50 +292,50 @@ var gSync = {
     for (let i = devicesPopup.childNodes.length - 1; i >= 0; --i) {
       let child = devicesPopup.childNodes[i];
       if (child.classList.contains("sync-menuitem")) {
         child.remove();
       }
     }
 
     const fragment = document.createDocumentFragment();
-    if (this.syncReady) {
-      const onTargetDeviceCommand = (event) => {
-        let clients = event.target.getAttribute("clientId") ?
-          [event.target.getAttribute("clientId")] :
-          this.remoteClients.map(client => client.id);
 
-        clients.forEach(clientId => this.sendTabToDevice(url, clientId, title));
-        gPageActionButton.panel.hidePopup();
-      }
+    const onTargetDeviceCommand = (event) => {
+      let clients = event.target.getAttribute("clientId") ?
+        [event.target.getAttribute("clientId")] :
+        this.remoteClients.map(client => client.id);
+
+      clients.forEach(clientId => this.sendTabToDevice(url, clientId, title));
+      gPageActionButton.panel.hidePopup();
+    }
 
-      function addTargetDevice(clientId, name, clientType) {
-        const targetDevice = createDeviceNodeFn(clientId, name, clientType);
-        targetDevice.addEventListener("command", onTargetDeviceCommand, true);
-        targetDevice.classList.add("sync-menuitem", "sendtab-target");
-        targetDevice.setAttribute("clientId", clientId);
-        targetDevice.setAttribute("clientType", clientType);
-        targetDevice.setAttribute("label", name);
-        fragment.appendChild(targetDevice);
-      }
+    function addTargetDevice(clientId, name, clientType) {
+      const targetDevice = createDeviceNodeFn(clientId, name, clientType);
+      targetDevice.addEventListener("command", onTargetDeviceCommand, true);
+      targetDevice.classList.add("sync-menuitem", "sendtab-target");
+      targetDevice.setAttribute("clientId", clientId);
+      targetDevice.setAttribute("clientType", clientType);
+      targetDevice.setAttribute("label", name);
+      fragment.appendChild(targetDevice);
+    }
 
-      const clients = this.remoteClients;
-      for (let client of clients) {
-        addTargetDevice(client.id, client.name, client.type);
-      }
+    const clients = this.remoteClients;
+    for (let client of clients) {
+      addTargetDevice(client.id, client.name, client.type);
+    }
 
-      // "All devices" menu item
-      if (clients.length > 1) {
-        const separator = createDeviceNodeFn();
-        separator.classList.add("sync-menuitem");
-        fragment.appendChild(separator);
-        const allDevicesLabel = this.fxaStrings.GetStringFromName("sendTabToAllDevices.menuitem");
-        addTargetDevice("", allDevicesLabel, "");
-      }
+    // "All devices" menu item
+    if (clients.length > 1) {
+      const separator = createDeviceNodeFn();
+      separator.classList.add("sync-menuitem");
+      fragment.appendChild(separator);
+      const allDevicesLabel = this.fxaStrings.GetStringFromName("sendTabToAllDevices.menuitem");
+      addTargetDevice("", allDevicesLabel, "");
     }
+
     devicesPopup.appendChild(fragment);
   },
 
   isSendableURI(aURISpec) {
     if (!aURISpec) {
       return false;
     }
     // Disallow sending tabs with more than 65535 characters.
@@ -355,52 +351,54 @@ var gSync = {
       // The preference has been removed, or is an invalid regexp, so we log an
       // error and treat it as a valid URI -- and the more problematic case is
       // the length, which we've already addressed.
       Cu.reportError(`Failed to build url filter regexp for send tab: ${e}`);
       return true;
     }
   },
 
-  // "Send Tab to Device" menu item
   updateTabContextMenu(aPopupMenu, aTargetTab) {
-    const enabled = this.syncReady &&
-                    this.remoteClients.length > 0 &&
-                    this.isSendableURI(aTargetTab.linkedBrowser.currentURI.spec);
-    document.getElementById("context_sendTabToDevice").disabled = !enabled;
+    if (!this.sendTabToDeviceEnabled || !this.weaveService.ready) {
+      return;
+    }
+
+    const targetURI = aTargetTab.linkedBrowser.currentURI.spec;
+    const showSendTab = this.remoteClients.length > 0 && this.isSendableURI(targetURI);
+
+    ["context_sendTabToDevice", "context_sendTabToDevice_separator"]
+    .forEach(id => { document.getElementById(id).hidden = !showSendTab });
   },
 
-  // "Send Page to Device" and "Send Link to Device" menu items
   initPageContextMenu(contextMenu) {
+    if (!this.sendTabToDeviceEnabled || !this.weaveService.ready) {
+      return;
+    }
+
+    const remoteClientPresent = this.remoteClients.length > 0;
     // showSendLink and showSendPage are mutually exclusive
-    const showSendLink = contextMenu.onSaveableLink || contextMenu.onPlainTextLink;
-    const showSendPage = !showSendLink
+    let showSendLink = remoteClientPresent
+                       && (contextMenu.onSaveableLink || contextMenu.onPlainTextLink);
+    const showSendPage = !showSendLink && remoteClientPresent
                          && !(contextMenu.isContentSelected ||
                               contextMenu.onImage || contextMenu.onCanvas ||
                               contextMenu.onVideo || contextMenu.onAudio ||
-                              contextMenu.onLink ||
-                              (contextMenu.target &&
-                               ["input", "textarea"].includes(contextMenu.target.tagName.toLowerCase())));
+                              contextMenu.onLink || contextMenu.onTextInput)
+                         && this.isSendableURI(contextMenu.browser.currentURI.spec);
+
+    if (showSendLink) {
+      // This isn't part of the condition above since we don't want to try and
+      // send the page if a link is clicked on or selected but is not sendable.
+      showSendLink = this.isSendableURI(contextMenu.linkURL);
+    }
 
     ["context-sendpagetodevice", "context-sep-sendpagetodevice"]
     .forEach(id => contextMenu.showItem(id, showSendPage));
     ["context-sendlinktodevice", "context-sep-sendlinktodevice"]
     .forEach(id => contextMenu.showItem(id, showSendLink));
-
-    if (!showSendLink && !showSendPage) {
-      return;
-    }
-
-    const targetURI = showSendLink ? contextMenu.linkURL :
-                                     contextMenu.browser.currentURI.spec;
-    const enabled = this.syncReady && this.remoteClients.length > 0 &&
-                    this.isSendableURI(targetURI);
-    contextMenu.setItemAttr(showSendPage ? "context-sendpagetodevice" :
-                                           "context-sendlinktodevice",
-                            "disabled", !enabled || null);
   },
 
   // Functions called by observers
   onActivityStart() {
     clearTimeout(this._syncAnimationTimer);
     this._syncStartTime = Date.now();
 
     let broadcaster = document.getElementById("sync-status");
@@ -564,8 +562,14 @@ var gSync = {
     }
   },
 
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference
   ])
 };
+
+XPCOMUtils.defineLazyGetter(gSync, "weaveService", function() {
+  return Components.classes["@mozilla.org/weave/service;1"]
+                   .getService(Components.interfaces.nsISupports)
+                   .wrappedJSObject;
+});
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -1320,15 +1320,15 @@ toolbarpaletteitem[place="palette"][hidd
 
 .dragfeedback-tab {
   -moz-appearance: none;
   opacity: 0.65;
   -moz-window-shadow: none;
 }
 
 /* Page action menu */
-#page-action-sendToDeviceView-body:not([state="notsignedin"]) > #page-action-sendToDevice-fxa-button,
-#page-action-sendToDeviceView-body:not([state="nodevice"]) > #page-action-no-devices-button,
-#page-action-sendToDeviceView-body:not([state="notready"]) > #page-action-sync-not-ready-button {
+#page-action-sendToDeviceView-body[signedin] > #page-action-sendToDevice-fxa-button,
+#page-action-sendToDeviceView-body:not([signedin]) > #page-action-no-devices-button,
+#page-action-sendToDeviceView-body[hasdevices] > #page-action-no-devices-button {
   display: none;
 }
 
 %include theme-vars.inc.css
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7833,64 +7833,46 @@ var gPageActionButton = {
   },
 
   emailLink() {
     this.panel.hidePopup();
     MailIntegration.sendLinkForBrowser(gBrowser.selectedBrowser);
   },
 
   showSendToDeviceView(subviewButton) {
-    this.setupSendToDeviceView();
-    PanelUI.showSubView("page-action-sendToDeviceView", subviewButton);
-  },
-
-  setupSendToDeviceView() {
     let browser = gBrowser.selectedBrowser;
     let url = browser.currentURI.spec;
     let title = browser.contentTitle;
     let body = this.sendToDeviceBody;
 
-    // This is on top because it also clears the device list between state changes.
     gSync.populateSendTabToDevicesMenu(body, url, title, (clientId, name, clientType) => {
       if (!name) {
         return document.createElement("toolbarseparator");
       }
       let item = document.createElement("toolbarbutton");
       item.classList.add("page-action-sendToDevice-device", "subviewbutton");
       if (clientId) {
         item.classList.add("subviewbutton-iconic");
       }
       return item;
     });
 
-    if (!gSync.isSignedIn) {
-      // Could be unconfigured or unverified
-      body.setAttribute("state", "notsignedin");
-      return;
-    }
-
-    // In the first ~10 sec after startup, Sync may not be loaded and the list
-    // of devices will be empty.
-    if (!gSync.syncReady) {
-      body.setAttribute("state", "notready");
-      // Force a background Sync
-      Services.tm.dispatchToMainThread(() => {
-        Weave.Service.sync([]);  // [] = clients engine only
-        if (!window.closed && gSync.syncReady) {
-          this.setupSendToDeviceView();
-        }
-      });
-      return;
-    }
-    if (!gSync.remoteClients.length) {
-      body.setAttribute("state", "nodevice");
-      return;
-    }
-
-    body.setAttribute("state", "signedin");
+    if (gSync.remoteClients.length) {
+      body.setAttribute("hasdevices", "true");
+    } else {
+      body.removeAttribute("hasdevices");
+    }
+
+    if (UIState.get().status == UIState.STATUS_SIGNED_IN) {
+      body.setAttribute("signedin", "true");
+    } else {
+      body.removeAttribute("signedin");
+    }
+
+    PanelUI.showSubView("page-action-sendToDeviceView", subviewButton);
   },
 
   fxaButtonClicked() {
     this.panel.hidePopup();
     gSync.openPrefs();
   },
 };
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -97,19 +97,19 @@
                 tbattr="tabbrowser-multiple"
                 oncommand="gBrowser.replaceTabWithWindow(TabContextMenu.contextTab);"/>
 #ifdef E10S_TESTING_ONLY
       <menuitem id="context_openNonRemoteWindow" label="Open in new non-e10s window"
                 tbattr="tabbrowser-remote"
                 hidden="true"
                 oncommand="gBrowser.openNonRemoteWindow(TabContextMenu.contextTab);"/>
 #endif
-      <menuseparator id="context_sendTabToDevice_separator"/>
+      <menuseparator id="context_sendTabToDevice_separator" hidden="true"/>
       <menu id="context_sendTabToDevice" label="&sendTabToDevice.label;"
-            accesskey="&sendTabToDevice.accesskey;">
+            accesskey="&sendTabToDevice.accesskey;" hidden="true">
         <menupopup id="context_sendTabToDevicePopupMenu"
                    onpopupshowing="gSync.populateSendTabToDevicesMenu(event.target, TabContextMenu.contextTab.linkedBrowser.currentURI.spec, TabContextMenu.contextTab.linkedBrowser.contentTitle);"/>
       </menu>
       <menuseparator/>
       <menuitem id="context_reloadAllTabs" label="&reloadAllTabs.label;" accesskey="&reloadAllTabs.accesskey;"
                 tbattr="tabbrowser-multiple-visible"
                 oncommand="gBrowser.reloadAllTabs();"/>
       <menuitem id="context_bookmarkAllTabs"
@@ -489,20 +489,16 @@
                            class="subviewbutton subviewbutton-iconic"
                            label="&syncBrand.fxAccount.label;"
                            shortcut="&sendToDevice.fxaRequired.label;"
                            oncommand="gPageActionButton.fxaButtonClicked();"/>
             <toolbarbutton id="page-action-no-devices-button"
                            class="subviewbutton"
                            label="&sendToDevice.noDevices.label;"
                            disabled="true"/>
-            <toolbarbutton id="page-action-sync-not-ready-button"
-                           class="subviewbutton"
-                           label="&sendToDevice.syncNotReady.label;"
-                           disabled="true"/>
           </vbox>
         </panelview>
       </photonpanelmultiview>
     </panel>
 
     <!-- Bookmarks and history tooltip -->
     <tooltip id="bhTooltip"/>
 
--- a/browser/base/content/test/contextMenu/browser_contextmenu_mozextension.js
+++ b/browser/base/content/test/contextMenu/browser_contextmenu_mozextension.js
@@ -39,19 +39,17 @@ add_task(async function test_link() {
        // We need a blank entry here because the containers submenu is
        // dynamically generated with no ids.
        ...(hasContainers ? ["", null] : []),
        "context-openlink",      true,
        "context-openlinkprivate", true,
        "---",                   null,
        "context-savelink",      true,
        "context-copylink",      true,
-       "context-searchselect",  true,
-       "---", null,
-       "context-sendlinktodevice", false, [], null]);
+       "context-searchselect",  true]);
 });
 
 add_task(async function test_video() {
   await test_contextmenu("#video",
   ["context-media-play",         null,
    "context-media-mute",         null,
    "context-media-playbackrate", null,
        ["context-media-playbackrate-050x", null,
--- a/browser/base/content/test/general/browser_contextmenu.js
+++ b/browser/base/content/test/general/browser_contextmenu.js
@@ -33,19 +33,17 @@ add_task(async function test_xul_text_li
      ...(hasContainers ? ["", null] : []),
      "context-openlink",      true,
      "context-openlinkprivate", true,
      "---",                   null,
      "context-bookmarklink",  true,
      "context-savelink",      true,
      ...(hasPocket ? ["context-savelinktopocket", true] : []),
      "context-copylink",      true,
-     "context-searchselect",  true,
-     "---", null,
-     "context-sendlinktodevice", false, [], null,
+     "context-searchselect",  true
     ]
   );
 
   // Clean up so won't affect HTML element test cases
   lastElementSelector = null;
   gBrowser.removeCurrentTab();
 });
 
@@ -86,18 +84,16 @@ add_task(async function test_plaintext()
   plainTextItems = ["context-navigation",   null,
                         ["context-back",         false,
                          "context-forward",      false,
                          "context-reload",       true,
                          "context-bookmarkpage", true], null,
                     "---",                  null,
                     "context-savepage",     true,
                     ...(hasPocket ? ["context-pocket", true] : []),
-                    "---", null,
-                    "context-sendpagetodevice", false, [], null,
                     "---",                  null,
                     "context-viewbgimage",  false,
                     "context-selectall",    true,
                     "---",                  null,
                     "context-viewsource",   true,
                     "context-viewinfo",     true
                    ];
   await test_contextmenu("#test-text", plainTextItems, {
@@ -114,19 +110,17 @@ add_task(async function test_link() {
      ...(hasContainers ? ["", null] : []),
      "context-openlink",      true,
      "context-openlinkprivate", true,
      "---",                   null,
      "context-bookmarklink",  true,
      "context-savelink",      true,
      ...(hasPocket ? ["context-savelinktopocket", true] : []),
      "context-copylink",      true,
-     "context-searchselect",  true,
-     "---", null,
-     "context-sendlinktodevice", false, [], null,
+     "context-searchselect",  true
     ]
   );
 });
 
 add_task(async function test_mailto() {
   await test_contextmenu("#test-mailto",
     ["context-copyemail", true,
      "context-searchselect", true
@@ -263,18 +257,16 @@ add_task(async function test_iframe() {
     ["context-navigation", null,
          ["context-back",         false,
           "context-forward",      false,
           "context-reload",       true,
           "context-bookmarkpage", true], null,
      "---",                  null,
      "context-savepage",     true,
      ...(hasPocket ? ["context-pocket", true] : []),
-     "---", null,
-     "context-sendpagetodevice", false, [], null,
      "---",                  null,
      "context-viewbgimage",  false,
      "context-selectall",    true,
      "frame",                null,
          ["context-showonlythisframe", true,
           "context-openframeintab",    true,
           "context-openframe",         true,
           "---",                       null,
@@ -569,18 +561,16 @@ add_task(async function test_pagemenu() 
          ["+Radio1",             {type: "checkbox", icon: "", checked: false, disabled: false},
           "+Radio2",             {type: "checkbox", icon: "", checked: true, disabled: false},
           "+Radio3",             {type: "checkbox", icon: "", checked: false, disabled: false},
           "---",                 null,
           "+Checkbox",           {type: "checkbox", icon: "", checked: false, disabled: false}], null,
      "---",                  null,
      "context-savepage",     true,
      ...(hasPocket ? ["context-pocket", true] : []),
-     "---", null,
-     "context-sendpagetodevice", false, [], null,
      "---",                  null,
      "context-viewbgimage",  false,
      "context-selectall",    true,
      "---",                  null,
      "context-viewsource",   true,
      "context-viewinfo",     true
     ],
     {async postCheckContextMenuFn() {
@@ -603,18 +593,16 @@ add_task(async function test_dom_full_sc
           "context-forward",         false,
           "context-reload",          true,
           "context-bookmarkpage",    true], null,
      "---",                          null,
      "context-leave-dom-fullscreen", true,
      "---",                          null,
      "context-savepage",             true,
      ...(hasPocket ? ["context-pocket", true] : []),
-     "---", null,
-     "context-sendpagetodevice", false, [], null,
      "---",                          null,
      "context-viewbgimage",          false,
      "context-selectall",            true,
      "---",                          null,
      "context-viewsource",           true,
      "context-viewinfo",             true
     ],
     {
@@ -652,18 +640,16 @@ add_task(async function test_pagemenu2()
     ["context-navigation", null,
          ["context-back",         false,
           "context-forward",      false,
           "context-reload",       true,
           "context-bookmarkpage", true], null,
      "---",                  null,
      "context-savepage",     true,
      ...(hasPocket ? ["context-pocket", true] : []),
-     "---", null,
-     "context-sendpagetodevice", false, [], null,
      "---",                  null,
      "context-viewbgimage",  false,
      "context-selectall",    true,
      "---",                  null,
      "context-viewsource",   true,
      "context-viewinfo",     true
     ],
     {maybeScreenshotsPresent: true,
@@ -701,18 +687,16 @@ add_task(async function test_select_text
      "context-openlinkprivate",             true,
      "---",                                 null,
      "context-bookmarklink",                true,
      "context-savelink",                    true,
      "context-copy",                        true,
      "context-selectall",                   true,
      "---",                                 null,
      "context-searchselect",                true,
-     "---", null,
-     "context-sendlinktodevice", false, [], null,
      "context-viewpartialsource-selection", true
     ],
     {
       offsetX: 6,
       offsetY: 6,
       async preCheckContextMenuFn() {
         await selectText("#test-select-text-link");
       },
@@ -743,19 +727,17 @@ add_task(async function test_imagelink()
      "---",                   null,
      "context-viewimage",            true,
      "context-copyimage-contents",   true,
      "context-copyimage",            true,
      "---",                          null,
      "context-saveimage",            true,
      "context-sendimage",            true,
      "context-setDesktopBackground", true,
-     "context-viewimageinfo",        true,
-     "---", null,
-     "context-sendlinktodevice", false, [], null,
+     "context-viewimageinfo",        true
     ]
   );
 });
 
 add_task(async function test_select_input_text() {
   todo(false, "spell checker tests are failing, bug 1246296");
 
   /*
@@ -837,18 +819,16 @@ add_task(async function test_click_to_pl
           "context-reload",       true,
           "context-bookmarkpage", true], null,
      "---",                  null,
      "context-ctp-play",     true,
      "context-ctp-hide",     true,
      "---",                  null,
      "context-savepage",     true,
      ...(hasPocket ? ["context-pocket", true] : []),
-     "---", null,
-     "context-sendpagetodevice", false, [], null,
      "---",                  null,
      "context-viewbgimage",  false,
      "context-selectall",    true,
      "---",                  null,
      "context-viewsource",   true,
      "context-viewinfo",     true
     ],
     {
@@ -884,18 +864,16 @@ add_task(async function test_srcdoc() {
     ["context-navigation", null,
          ["context-back",         false,
           "context-forward",      false,
           "context-reload",       true,
           "context-bookmarkpage", true], null,
      "---",                  null,
      "context-savepage",     true,
      ...(hasPocket ? ["context-pocket", true] : []),
-     "---", null,
-     "context-sendpagetodevice", false, [], null,
      "---",                  null,
      "context-viewbgimage",  false,
      "context-selectall",    true,
      "frame",                null,
          ["context-reloadframe",       true,
           "---",                       null,
           "context-saveframe",         true,
           "---",                       null,
@@ -923,71 +901,143 @@ add_task(async function test_input_spell
      "context-delete",      false,
      "---",                 null,
      "context-selectall",   true,
     ]
   );
   */
 });
 
+const remoteClientsFixture = [ { id: 1, name: "Foo"}, { id: 2, name: "Bar"} ];
+
+add_task(async function test_plaintext_sendpagetodevice() {
+  if (!gSync.sendTabToDeviceEnabled) {
+    return;
+  }
+  await ensureSyncReady();
+  const oldGetter = setupRemoteClientsFixture(remoteClientsFixture);
+
+  let plainTextItemsWithSendPage =
+                    ["context-navigation",   null,
+                      ["context-back",         false,
+                        "context-forward",      false,
+                        "context-reload",       true,
+                        "context-bookmarkpage", true], null,
+                    "---",                  null,
+                    "context-savepage",     true,
+                    ...(hasPocket ? ["context-pocket", true] : []),
+                    "---",                  null,
+                    "context-sendpagetodevice", true,
+                      ["*Foo", true,
+                       "*Bar", true,
+                       "---", null,
+                       "*All Devices", true], null,
+                    "---",                  null,
+                    "context-viewbgimage",  false,
+                    "context-selectall",    true,
+                    "---",                  null,
+                    "context-viewsource",   true,
+                    "context-viewinfo",     true
+                   ];
+  await test_contextmenu("#test-text", plainTextItemsWithSendPage, {
+      maybeScreenshotsPresent: true,
+      async onContextMenuShown() {
+        await openMenuItemSubmenu("context-sendpagetodevice");
+      }
+    });
+
+  restoreRemoteClients(oldGetter);
+});
+
+add_task(async function test_link_sendlinktodevice() {
+  if (!gSync.sendTabToDeviceEnabled) {
+    return;
+  }
+  await ensureSyncReady();
+  const oldGetter = setupRemoteClientsFixture(remoteClientsFixture);
+
+  await test_contextmenu("#test-link",
+    ["context-openlinkintab", true,
+     ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
+     // We need a blank entry here because the containers submenu is
+     // dynamically generated with no ids.
+     ...(hasContainers ? ["", null] : []),
+     "context-openlink",      true,
+     "context-openlinkprivate", true,
+     "---",                   null,
+     "context-bookmarklink",  true,
+     "context-savelink",      true,
+     ...(hasPocket ? ["context-savelinktopocket", true] : []),
+     "context-copylink",      true,
+     "context-searchselect",  true,
+     "---",                  null,
+     "context-sendlinktodevice", true,
+      ["*Foo", true,
+       "*Bar", true,
+       "---", null,
+       "*All Devices", true], null,
+    ],
+    {
+      async onContextMenuShown() {
+        await openMenuItemSubmenu("context-sendlinktodevice");
+      }
+    });
+
+  restoreRemoteClients(oldGetter);
+});
+
 add_task(async function test_svg_link() {
   await test_contextmenu("#svg-with-link > a",
     ["context-openlinkintab", true,
      ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
      // We need a blank entry here because the containers submenu is
      // dynamically generated with no ids.
      ...(hasContainers ? ["", null] : []),
      "context-openlink",      true,
      "context-openlinkprivate", true,
      "---",                   null,
      "context-bookmarklink",  true,
      "context-savelink",      true,
      ...(hasPocket ? ["context-savelinktopocket", true] : []),
      "context-copylink",      true,
-     "context-searchselect",  true,
-     "---", null,
-     "context-sendlinktodevice", false, [], null,
+     "context-searchselect",  true
     ]
   );
 
   await test_contextmenu("#svg-with-link2 > a",
     ["context-openlinkintab", true,
      ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
      // We need a blank entry here because the containers submenu is
      // dynamically generated with no ids.
      ...(hasContainers ? ["", null] : []),
      "context-openlink",      true,
      "context-openlinkprivate", true,
      "---",                   null,
      "context-bookmarklink",  true,
      "context-savelink",      true,
      ...(hasPocket ? ["context-savelinktopocket", true] : []),
      "context-copylink",      true,
-     "context-searchselect",  true,
-     "---", null,
-     "context-sendlinktodevice", false, [], null,
+     "context-searchselect",  true
     ]
   );
 
   await test_contextmenu("#svg-with-link3 > a",
     ["context-openlinkintab", true,
      ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
      // We need a blank entry here because the containers submenu is
      // dynamically generated with no ids.
      ...(hasContainers ? ["", null] : []),
      "context-openlink",      true,
      "context-openlinkprivate", true,
      "---",                   null,
      "context-bookmarklink",  true,
      "context-savelink",      true,
      ...(hasPocket ? ["context-savelinktopocket", true] : []),
      "context-copylink",      true,
-     "context-searchselect",  true,
-     "---", null,
-     "context-sendlinktodevice", false, [], null,
+     "context-searchselect",  true
     ]
   );
 });
 
 add_task(async function test_cleanup_html() {
   gBrowser.removeCurrentTab();
 });
 
@@ -1007,8 +1057,15 @@ async function selectText(selector) {
     let div = doc.createRange();
     let element = doc.querySelector(contentSelector);
     Assert.ok(element, "Found element to select text from");
     div.setStartBefore(element);
     div.setEndAfter(element);
     win.getSelection().addRange(div);
   });
 }
+
+function ensureSyncReady() {
+  let service = Cc["@mozilla.org/weave/service;1"]
+                  .getService(Components.interfaces.nsISupports)
+                  .wrappedJSObject;
+  return service.whenLoaded();
+}
--- a/browser/base/content/test/general/browser_visibleTabs_contextMenu.js
+++ b/browser/base/content/test/general/browser_visibleTabs_contextMenu.js
@@ -11,16 +11,38 @@ add_task(async function test() {
   let testTab = BrowserTestUtils.addTab(gBrowser);
   is(gBrowser.visibleTabs.length, 2, "there are now two visible tabs");
 
   // Check the context menu with two tabs
   updateTabContextMenu(origTab);
   is(document.getElementById("context_closeTab").disabled, false, "Close Tab is enabled");
   is(document.getElementById("context_reloadAllTabs").disabled, false, "Reload All Tabs is enabled");
 
+
+  if (gSync.sendTabToDeviceEnabled) {
+    const origIsSendableURI = gSync.isSendableURI;
+    gSync.isSendableURI = () => true;
+    // Check the send tab to device menu item
+    await ensureSyncReady();
+    const oldGetter = setupRemoteClientsFixture(remoteClientsFixture);
+    await updateTabContextMenu(origTab, async function() {
+      await openMenuItemSubmenu("context_sendTabToDevice");
+    });
+    is(document.getElementById("context_sendTabToDevice").hidden, false, "Send tab to device is shown");
+    let targets = document.getElementById("context_sendTabToDevicePopupMenu").childNodes;
+    is(targets[0].getAttribute("label"), "Foo", "Foo target is present");
+    is(targets[1].getAttribute("label"), "Bar", "Bar target is present");
+    is(targets[3].getAttribute("label"), "All Devices", "All Devices target is present");
+    gSync.isSendableURI = () => false;
+    updateTabContextMenu(origTab);
+    is(document.getElementById("context_sendTabToDevice").hidden, true, "Send tab to device is hidden");
+    restoreRemoteClients(oldGetter);
+    gSync.isSendableURI = origIsSendableURI;
+  }
+
   // Hide the original tab.
   gBrowser.selectedTab = testTab;
   gBrowser.showOnlyTheseTabs([testTab]);
   is(gBrowser.visibleTabs.length, 1, "now there is only one visible tab");
 
   // Check the context menu with one tab.
   updateTabContextMenu(testTab);
   is(document.getElementById("context_closeTab").disabled, false, "Close Tab is enabled when more than one tab exists");
@@ -50,8 +72,15 @@ add_task(async function test() {
   // Close Tabs To The End should now be enabled
   updateTabContextMenu(origTab);
   is(document.getElementById("context_closeTabsToTheEnd").disabled, false, "Close Tabs To The End is enabled");
 
   gBrowser.removeTab(testTab);
   gBrowser.removeTab(pinned);
 });
 
+function ensureSyncReady() {
+  let service = Cc["@mozilla.org/weave/service;1"]
+                  .getService(Components.interfaces.nsISupports)
+                  .wrappedJSObject;
+  return service.whenLoaded();
+}
+
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -826,8 +826,31 @@ function getCertExceptionDialog(aLocatio
 
       if (childDoc.location.href == aLocation) {
         return childDoc;
       }
     }
   }
   return undefined;
 }
+
+function setupRemoteClientsFixture(fixture) {
+  let oldRemoteClientsGetter =
+    Object.getOwnPropertyDescriptor(gSync, "remoteClients").get;
+
+  Object.defineProperty(gSync, "remoteClients", {
+    get() { return fixture; }
+  });
+  return oldRemoteClientsGetter;
+}
+
+function restoreRemoteClients(getter) {
+  Object.defineProperty(gSync, "remoteClients", {
+    get: getter
+  });
+}
+
+async function openMenuItemSubmenu(id) {
+  let menuPopup = document.getElementById(id).menupopup;
+  let menuPopupPromise = BrowserTestUtils.waitForEvent(menuPopup, "popupshown");
+  menuPopup.showPopup();
+  await menuPopupPromise;
+}
--- a/browser/base/content/test/sync/browser.ini
+++ b/browser/base/content/test/sync/browser.ini
@@ -1,15 +1,9 @@
-[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]
 [browser_aboutAccounts.js]
 skip-if = os == "linux" # Bug 958026
 support-files =
   content_aboutAccounts.js
deleted file mode 100644
--- a/browser/base/content/test/sync/browser_contextmenu_sendpage.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-const remoteClientsFixture = [ { id: 1, name: "Foo"}, { id: 2, name: "Bar"} ];
-
-const origRemoteClients = mockReturn(gSync, "remoteClients", remoteClientsFixture);
-const origSyncReady = mockReturn(gSync, "syncReady", true);
-const origIsSendableURI = mockReturn(gSync, "isSendableURI", true);
-
-add_task(async function setup() {
-  await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
-});
-
-add_task(async function test_page_contextmenu() {
-  await updateContentContextMenu("#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");
-  let devices = document.getElementById("context-sendpagetodevice-popup").childNodes;
-  is(devices[0].getAttribute("label"), "Foo", "Foo target is present");
-  is(devices[1].getAttribute("label"), "Bar", "Bar target is present");
-  is(devices[3].getAttribute("label"), "All Devices", "All Devices target is present");
-});
-
-add_task(async function test_page_contextmenu_notsendable() {
-  const isSendableURIMock = mockReturn(gSync, "isSendableURI", false);
-
-  await updateContentContextMenu("#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");
-
-  isSendableURIMock.restore();
-});
-
-add_task(async function test_page_contextmenu_sendtab_no_remote_clients() {
-  let remoteClientsMock = mockReturn(gSync, "remoteClients", []);
-
-  await updateContentContextMenu("#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");
-
-  remoteClientsMock.restore();
-});
-
-add_task(async function test_page_contextmenu_sync_not_ready() {
-  const syncReadyMock = mockReturn(gSync, "syncReady", false);
-
-  await updateContentContextMenu("#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");
-
-  syncReadyMock.restore();
-});
-
-// We are not going to bother testing the states of context-sendlinktodevice since they use
-// the exact same code.
-// However, browser_contextmenu.js contains tests that verify the menu item is present.
-
-add_task(async function cleanup() {
-  gBrowser.removeCurrentTab();
-  origSyncReady.restore();
-  origRemoteClients.restore();
-  origIsSendableURI.restore();
-});
-
-async function updateContentContextMenu(selector, openSubmenuId = null) {
-  let contextMenu = document.getElementById("contentAreaContextMenu");
-  is(contextMenu.state, "closed", "checking if popup is closed");
-
-  let 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) {
-    let menuPopup = document.getElementById(openSubmenuId).menupopup;
-    let menuPopupPromise = BrowserTestUtils.waitForEvent(menuPopup, "popupshown");
-    menuPopup.showPopup();
-    await menuPopupPromise;
-  }
-
-  let awaitPopupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
-
-  contextMenu.hidePopup();
-  await awaitPopupHidden;
-}
deleted file mode 100644
--- a/browser/base/content/test/sync/browser_contextmenu_sendtab.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/* 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 remoteClientsFixture = [ { id: 1, name: "Foo"}, { id: 2, name: "Bar"} ];
-
-const origRemoteClients = mockReturn(gSync, "remoteClients", remoteClientsFixture);
-const origSyncReady = mockReturn(gSync, "syncReady", true);
-const origIsSendableURI = mockReturn(gSync, "isSendableURI", true);
-let [testTab] = gBrowser.visibleTabs;
-
-add_task(async function setup() {
-  is(gBrowser.visibleTabs.length, 1, "there is one visible tab");
-});
-
-add_task(async function test_tab_contextmenu() {
-  await updateTabContextMenu(testTab, openSendTabTargetsSubmenu);
-  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");
-  let devices = document.getElementById("context_sendTabToDevicePopupMenu").childNodes;
-  is(devices[0].getAttribute("label"), "Foo", "Foo target is present");
-  is(devices[1].getAttribute("label"), "Bar", "Bar target is present");
-  is(devices[3].getAttribute("label"), "All Devices", "All Devices target is present");
-});
-
-add_task(async function test_tab_contextmenu_only_one_remote_device() {
-  const remoteClientsMock = mockReturn(gSync, "remoteClients", [{ id: 1, name: "Foo"}]);
-
-  await updateTabContextMenu(testTab, openSendTabTargetsSubmenu);
-  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");
-  let devices = document.getElementById("context_sendTabToDevicePopupMenu").childNodes;
-  is(devices.length, 1, "There should not be any separator or All Devices item");
-  is(devices[0].getAttribute("label"), "Foo", "Foo target is present");
-
-  remoteClientsMock.restore();
-});
-
-add_task(async function test_tab_contextmenu_not_sendable() {
-  const isSendableURIMock = mockReturn(gSync, "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");
-
-  isSendableURIMock.restore();
-});
-
-add_task(async function test_tab_contextmenu_no_remote_clients() {
-  let remoteClientsMock = mockReturn(gSync, "remoteClients", []);
-
-  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");
-
-  remoteClientsMock.restore();
-});
-
-add_task(async function test_tab_contextmenu_sync_not_ready() {
-  const syncReadyMock = mockReturn(gSync, "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");
-
-  syncReadyMock.restore();
-});
-
-add_task(async function cleanup() {
-  origSyncReady.restore();
-  origRemoteClients.restore();
-  origIsSendableURI.restore();
-});
-
-async function openSendTabTargetsSubmenu() {
-  let menuPopup = document.getElementById("context_sendTabToDevice").menupopup;
-  let menuPopupPromise = BrowserTestUtils.waitForEvent(menuPopup, "popupshown");
-  menuPopup.showPopup();
-  await menuPopupPromise;
-}
deleted file mode 100644
--- a/browser/base/content/test/sync/head.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Mocks a getter or a function
-// This is basically sinon.js (our in-tree version doesn't do getters :/) (see bug 1369855)
-function mockReturn(obj, symbol, fixture) {
-  let getter = Object.getOwnPropertyDescriptor(obj, symbol).get;
-  if (getter) {
-    Object.defineProperty(obj, symbol, {
-      get() { return fixture; }
-    });
-    return {
-      restore() {
-        Object.defineProperty(obj, symbol, {
-          get: getter
-        });
-      }
-    }
-  }
-  let func = obj[symbol];
-  obj[symbol] = () => fixture;
-  return {
-    restore() {
-      obj[symbol] = func;
-    }
-  }
-}
--- a/browser/base/content/test/urlbar/browser_page_action_menu.js
+++ b/browser/base/content/test/urlbar/browser_page_action_menu.js
@@ -1,18 +1,12 @@
 "use strict";
 
 let gPanel = document.getElementById("page-action-panel");
 
-const mockRemoteClients = [
-  { id: "0", name: "foo", type: "mobile" },
-  { id: "1", name: "bar", type: "desktop" },
-  { id: "2", name: "baz", type: "mobile" },
-];
-
 add_task(async function bookmark() {
   // Open a unique page.
   let url = "http://example.com/browser_page_action_menu";
   await BrowserTestUtils.withNewTab(url, async () => {
     // Open the panel.
     await promisePanelOpen();
 
     // The bookmark button should read "Bookmark This Page" and not be starred.
@@ -129,122 +123,16 @@ add_task(async function sendToDevice_non
       document.getElementById("page-action-send-to-device-button");
     Assert.ok(sendToDeviceButton.disabled);
     let hiddenPromise = promisePanelHidden();
     gPanel.hidePopup();
     await hiddenPromise;
   });
 });
 
-add_task(async function sendToDevice_syncNotReady() {
-  // Open a tab that's sendable.
-  await BrowserTestUtils.withNewTab("http://example.com/", async () => {
-    let syncReadyMock = mockReturn(gSync, "syncReady", false);
-    let signedInMock = mockReturn(gSync, "isSignedIn", true);
-
-    let remoteClientsMock;
-    let origSync = Weave.Service.sync;
-    Weave.Service.sync = () => {
-      mockReturn(gSync, "syncReady", true);
-      remoteClientsMock = mockReturn(gSync, "remoteClients", mockRemoteClients);
-    };
-
-    let origSetupSendToDeviceView = gPageActionButton.setupSendToDeviceView;
-    gPageActionButton.setupSendToDeviceView = () => {
-      this.numCall++ || (this.numCall = 1);
-      origSetupSendToDeviceView.call(gPageActionButton);
-      testSendTabToDeviceMenu(this.numCall);
-    }
-
-    let cleanUp = () => {
-      Weave.Service.sync = origSync;
-      gPageActionButton.setupSendToDeviceView = origSetupSendToDeviceView;
-      signedInMock.restore();
-      syncReadyMock.restore();
-      remoteClientsMock.restore();
-    };
-    registerCleanupFunction(cleanUp);
-
-    // Open the panel.
-    await promisePanelOpen();
-    let sendToDeviceButton =
-      document.getElementById("page-action-send-to-device-button");
-    Assert.ok(!sendToDeviceButton.disabled);
-
-    // Click Send to Device.
-    let viewPromise = promiseViewShown();
-    EventUtils.synthesizeMouseAtCenter(sendToDeviceButton, {});
-    let view = await viewPromise;
-    Assert.equal(view.id, "page-action-sendToDeviceView");
-
-    function testSendTabToDeviceMenu(numCall) {
-      if (numCall == 1) {
-        // The Fxa button should be shown.
-        checkSendToDeviceItems([
-          {
-            id: "page-action-sendToDevice-fxa-button",
-            display: "none",
-          },
-          {
-            id: "page-action-no-devices-button",
-            display: "none",
-            disabled: true,
-          },
-          {
-            id: "page-action-sync-not-ready-button",
-            disabled: true,
-          },
-        ]);
-      } else if (numCall == 2) {
-        // The devices should be shown in the subview.
-        let expectedItems = [
-          {
-            id: "page-action-sendToDevice-fxa-button",
-            display: "none",
-          },
-          {
-            id: "page-action-no-devices-button",
-            display: "none",
-            disabled: true,
-          },
-          {
-            id: "page-action-sync-not-ready-button",
-            display: "none",
-            disabled: true,
-          },
-        ];
-        for (let client of mockRemoteClients) {
-          expectedItems.push({
-            attrs: {
-              clientId: client.id,
-              label: client.name,
-              clientType: client.type,
-            },
-          });
-        }
-        expectedItems.push(
-          null,
-          {
-            label: "All Devices",
-          }
-        );
-        checkSendToDeviceItems(expectedItems);
-      } else {
-        ok(false, "This should never happen");
-      }
-    }
-
-    // Done, hide the panel.
-    let hiddenPromise = promisePanelHidden();
-    gPanel.hidePopup();
-    await hiddenPromise;
-    cleanUp();
-  });
-});
-
 add_task(async function sendToDevice_notSignedIn() {
   // Open a tab that's sendable.
   await BrowserTestUtils.withNewTab("http://example.com/", async () => {
     await promiseSyncReady();
 
     // Open the panel.
     await promisePanelOpen();
     let sendToDeviceButton =
@@ -262,21 +150,16 @@ add_task(async function sendToDevice_not
       {
         id: "page-action-sendToDevice-fxa-button",
       },
       {
         id: "page-action-no-devices-button",
         display: "none",
         disabled: true,
       },
-      {
-        id: "page-action-sync-not-ready-button",
-        display: "none",
-        disabled: true,
-      },
     ]);
 
     // Click the Fxa button.
     let body = view.firstChild;
     let fxaButton = body.childNodes[0];
     Assert.equal(fxaButton.id, "page-action-sendToDevice-fxa-button");
     let prefsTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
     let hiddenPromise = promisePanelHidden();
@@ -318,21 +201,16 @@ add_task(async function sendToDevice_noD
       {
         id: "page-action-sendToDevice-fxa-button",
         display: "none",
       },
       {
         id: "page-action-no-devices-button",
         disabled: true,
       },
-      {
-        id: "page-action-sync-not-ready-button",
-        display: "none",
-        disabled: true,
-      },
     ]);
 
     // Done, hide the panel.
     let hiddenPromise = promisePanelHidden();
     gPanel.hidePopup();
     await hiddenPromise;
 
     await UIState.reset();
@@ -341,19 +219,30 @@ add_task(async function sendToDevice_noD
 
 add_task(async function sendToDevice_devices() {
   // Open a tab that's sendable.
   await BrowserTestUtils.withNewTab("http://example.com/", async () => {
     await promiseSyncReady();
     UIState._internal._state = { status: UIState.STATUS_SIGNED_IN };
 
     // Set up mock remote clients.
-    let remoteClientsMock = mockReturn(gSync, "remoteClients", mockRemoteClients);
+    let mockRemoteClients = [
+      { id: "0", name: "foo", type: "mobile" },
+      { id: "1", name: "bar", type: "desktop" },
+      { id: "2", name: "baz", type: "mobile" },
+    ];
+    let originalGetter =
+      Object.getOwnPropertyDescriptor(gSync, "remoteClients").get;
+    Object.defineProperty(gSync, "remoteClients", {
+      get() { return mockRemoteClients; }
+    });
     let cleanUp = () => {
-      remoteClientsMock.restore();
+      Object.defineProperty(gSync, "remoteClients", {
+        get: originalGetter
+      });
     };
     registerCleanupFunction(cleanUp);
 
     // Open the panel.
     await promisePanelOpen();
     let sendToDeviceButton =
       document.getElementById("page-action-send-to-device-button");
     Assert.ok(!sendToDeviceButton.disabled);
@@ -370,21 +259,16 @@ add_task(async function sendToDevice_dev
         id: "page-action-sendToDevice-fxa-button",
         display: "none",
       },
       {
         id: "page-action-no-devices-button",
         display: "none",
         disabled: true,
       },
-      {
-        id: "page-action-sync-not-ready-button",
-        display: "none",
-        disabled: true,
-      },
     ];
     for (let client of mockRemoteClients) {
       expectedItems.push({
         attrs: {
           clientId: client.id,
           label: client.name,
           clientType: client.type,
         },
@@ -492,32 +376,8 @@ function checkSendToDeviceItems(expected
     if ("attrs" in expected) {
       for (let name in expected.attrs) {
         Assert.ok(actual.hasAttribute(name));
         Assert.equal(actual.getAttribute(name), expected.attrs[name]);
       }
     }
   }
 }
-
-// Copied from test/sync/head.js (see bug 1369855)
-function mockReturn(obj, symbol, fixture) {
-  let getter = Object.getOwnPropertyDescriptor(obj, symbol).get;
-  if (getter) {
-    Object.defineProperty(obj, symbol, {
-      get() { return fixture; }
-    });
-    return {
-      restore() {
-        Object.defineProperty(obj, symbol, {
-          get: getter
-        });
-      }
-    }
-  }
-  let func = obj[symbol];
-  obj[symbol] = () => fixture;
-  return {
-    restore() {
-      obj[symbol] = func;
-    }
-  }
-}
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -958,9 +958,8 @@ you can use these alternative items. Oth
 <!ENTITY updateRestart.panelUI.label2 "Restart to update &brandShorterName;">
 
 <!ENTITY pageActionButton.tooltip "Page actions">
 
 <!ENTITY sendToDevice.label "Send to Deviceā€¦">
 <!ENTITY sendToDevice.viewTitle "Send to Device">
 <!ENTITY sendToDevice.fxaRequired.label "Required">
 <!ENTITY sendToDevice.noDevices.label "No Devices Available">
-<!ENTITY sendToDevice.syncNotReady.label "Syncing Devicesā€¦">