summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/general/browser_syncui.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/general/browser_syncui.js')
-rw-r--r--browser/base/content/test/general/browser_syncui.js205
1 files changed, 205 insertions, 0 deletions
diff --git a/browser/base/content/test/general/browser_syncui.js b/browser/base/content/test/general/browser_syncui.js
new file mode 100644
index 000000000..daf0fa497
--- /dev/null
+++ b/browser/base/content/test/general/browser_syncui.js
@@ -0,0 +1,205 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var {Log} = Cu.import("resource://gre/modules/Log.jsm", {});
+var {Weave} = Cu.import("resource://services-sync/main.js", {});
+
+var stringBundle = Cc["@mozilla.org/intl/stringbundle;1"]
+ .getService(Ci.nsIStringBundleService)
+ .createBundle("chrome://weave/locale/services/sync.properties");
+
+// ensure test output sees log messages.
+Log.repository.getLogger("browserwindow.syncui").addAppender(new Log.DumpAppender());
+
+// Send the specified sync-related notification and return a promise that
+// resolves once gSyncUI._promiseUpateUI is complete and the UI is ready to check.
+function notifyAndPromiseUIUpdated(topic) {
+ return new Promise(resolve => {
+ // Instrument gSyncUI so we know when the update is complete.
+ let oldPromiseUpdateUI = gSyncUI._promiseUpdateUI.bind(gSyncUI);
+ gSyncUI._promiseUpdateUI = function() {
+ return oldPromiseUpdateUI().then(() => {
+ // Restore our override.
+ gSyncUI._promiseUpdateUI = oldPromiseUpdateUI;
+ // Resolve the promise so the caller knows the update is done.
+ resolve();
+ });
+ };
+ // Now send the notification.
+ Services.obs.notifyObservers(null, topic, null);
+ });
+}
+
+// Sync manages 3 broadcasters so the menus correctly reflect the Sync state.
+// Only one of these 3 should ever be visible - pass the ID of the broadcaster
+// you expect to be visible and it will check it's the only one that is.
+function checkBroadcasterVisible(broadcasterId) {
+ let all = ["sync-reauth-state", "sync-setup-state", "sync-syncnow-state"];
+ Assert.ok(all.indexOf(broadcasterId) >= 0, "valid id");
+ for (let check of all) {
+ let eltHidden = document.getElementById(check).hidden;
+ Assert.equal(eltHidden, check == broadcasterId ? false : true, check);
+ }
+}
+
+function promiseObserver(topic) {
+ return new Promise(resolve => {
+ let obs = (aSubject, aTopic, aData) => {
+ Services.obs.removeObserver(obs, aTopic);
+ resolve(aSubject);
+ }
+ Services.obs.addObserver(obs, topic, false);
+ });
+}
+
+function checkButtonTooltips(stringPrefix) {
+ for (let butId of ["PanelUI-remotetabs-syncnow", "PanelUI-fxa-icon"]) {
+ let text = document.getElementById(butId).getAttribute("tooltiptext");
+ let desc = `Text is "${text}", expecting it to start with "${stringPrefix}"`
+ Assert.ok(text.startsWith(stringPrefix), desc);
+ }
+}
+
+add_task(function* prepare() {
+ // add the Sync button to the toolbar so we can get it!
+ CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_NAVBAR);
+ registerCleanupFunction(() => {
+ CustomizableUI.removeWidgetFromArea("sync-button");
+ });
+
+ let xps = Components.classes["@mozilla.org/weave/service;1"]
+ .getService(Components.interfaces.nsISupports)
+ .wrappedJSObject;
+ yield xps.whenLoaded();
+ // Put Sync and the UI into a known state.
+ Weave.Status.login = Weave.LOGIN_FAILED_NO_USERNAME;
+ yield notifyAndPromiseUIUpdated("weave:service:login:error");
+
+ checkBroadcasterVisible("sync-setup-state");
+ checkButtonTooltips("Sign In To Sync");
+ // mock out the "_needsSetup()" function so we don't short-circuit.
+ let oldNeedsSetup = window.gSyncUI._needsSetup;
+ window.gSyncUI._needsSetup = () => Promise.resolve(false);
+ registerCleanupFunction(() => {
+ window.gSyncUI._needsSetup = oldNeedsSetup;
+ // and an observer to set the state back to what it should be now we've
+ // restored the stub.
+ Services.obs.notifyObservers(null, "weave:service:login:finish", null);
+ });
+ // and a notification to have the state change away from "needs setup"
+ yield notifyAndPromiseUIUpdated("weave:service:login:finish");
+ checkBroadcasterVisible("sync-syncnow-state");
+ // open the sync-button panel so we can check elements in that.
+ document.getElementById("sync-button").click();
+});
+
+add_task(function* testSyncNeedsVerification() {
+ // mock out the "_needsVerification()" function
+ let oldNeedsVerification = window.gSyncUI._needsVerification;
+ window.gSyncUI._needsVerification = () => true;
+ try {
+ // a notification for the state change
+ yield notifyAndPromiseUIUpdated("weave:service:login:finish");
+ checkButtonTooltips("Verify");
+ } finally {
+ window.gSyncUI._needsVerification = oldNeedsVerification;
+ }
+});
+
+
+add_task(function* testSyncLoginError() {
+ checkBroadcasterVisible("sync-syncnow-state");
+
+ // Pretend we are in a "login failed" error state
+ Weave.Status.sync = Weave.LOGIN_FAILED;
+ Weave.Status.login = Weave.LOGIN_FAILED_LOGIN_REJECTED;
+ yield notifyAndPromiseUIUpdated("weave:ui:sync:error");
+
+ // But the menu *should* reflect the login error.
+ checkBroadcasterVisible("sync-reauth-state");
+ // The tooltips for the buttons should also reflect it.
+ checkButtonTooltips("Reconnect");
+
+ // Now pretend we just had a successful login - the error notification should go away.
+ Weave.Status.sync = Weave.STATUS_OK;
+ Weave.Status.login = Weave.LOGIN_SUCCEEDED;
+ yield notifyAndPromiseUIUpdated("weave:service:login:start");
+ yield notifyAndPromiseUIUpdated("weave:service:login:finish");
+ // The menus should be back to "all good"
+ checkBroadcasterVisible("sync-syncnow-state");
+});
+
+function checkButtonsStatus(shouldBeActive) {
+ for (let eid of [
+ "sync-status", // the broadcaster itself.
+ "sync-button", // the main sync button which observes the broadcaster
+ "PanelUI-fxa-icon", // the sync icon in the fxa footer that observes it.
+ ]) {
+ let elt = document.getElementById(eid);
+ if (shouldBeActive) {
+ Assert.equal(elt.getAttribute("syncstatus"), "active", `${eid} should be active`);
+ } else {
+ Assert.ok(!elt.hasAttribute("syncstatus"), `${eid} should have no status attr`);
+ }
+ }
+}
+
+function* testButtonActions(startNotification, endNotification, expectActive = true) {
+ checkButtonsStatus(false);
+ // pretend a sync is starting.
+ yield notifyAndPromiseUIUpdated(startNotification);
+ checkButtonsStatus(expectActive);
+ // and has stopped
+ yield notifyAndPromiseUIUpdated(endNotification);
+ checkButtonsStatus(false);
+}
+
+function *doTestButtonActivities() {
+ // logins do not "activate" the spinner/button as they may block and make
+ // the UI look like Sync is never completing.
+ yield testButtonActions("weave:service:login:start", "weave:service:login:finish", false);
+ yield testButtonActions("weave:service:login:start", "weave:service:login:error", false);
+
+ // But notifications for Sync itself should activate it.
+ yield testButtonActions("weave:service:sync:start", "weave:service:sync:finish");
+ yield testButtonActions("weave:service:sync:start", "weave:service:sync:error");
+
+ // and ensure the counters correctly handle multiple in-flight syncs
+ yield notifyAndPromiseUIUpdated("weave:service:sync:start");
+ checkButtonsStatus(true);
+ // sync stops.
+ yield notifyAndPromiseUIUpdated("weave:service:sync:finish");
+ // Button should not be active.
+ checkButtonsStatus(false);
+}
+
+add_task(function* testButtonActivitiesInNavBar() {
+ // check the button's functionality while the button is in the NavBar - which
+ // it already is.
+ yield doTestButtonActivities();
+});
+
+add_task(function* testFormatLastSyncDateNow() {
+ let now = new Date();
+ let nowString = gSyncUI.formatLastSyncDate(now);
+ Assert.equal(nowString, "Last sync: " + now.toLocaleDateString(undefined, {weekday: 'long', hour: 'numeric', minute: 'numeric'}));
+});
+
+add_task(function* testFormatLastSyncDateMonthAgo() {
+ let monthAgo = new Date();
+ monthAgo.setMonth(monthAgo.getMonth() - 1);
+ let monthAgoString = gSyncUI.formatLastSyncDate(monthAgo);
+ Assert.equal(monthAgoString, "Last sync: " + monthAgo.toLocaleDateString(undefined, {month: 'long', day: 'numeric'}));
+});
+
+add_task(function* testButtonActivitiesInPanel() {
+ // check the button's functionality while the button is in the panel - it's
+ // currently in the NavBar - move it to the panel and open it.
+ CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
+ yield PanelUI.show();
+ try {
+ yield doTestButtonActivities();
+ } finally {
+ PanelUI.hide();
+ }
+});