diff options
Diffstat (limited to 'browser/base/content/test/general/browser_fxaccounts.js')
-rw-r--r-- | browser/base/content/test/general/browser_fxaccounts.js | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/browser/base/content/test/general/browser_fxaccounts.js b/browser/base/content/test/general/browser_fxaccounts.js new file mode 100644 index 000000000..0f68286dc --- /dev/null +++ b/browser/base/content/test/general/browser_fxaccounts.js @@ -0,0 +1,261 @@ +/* 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 {Task} = Cu.import("resource://gre/modules/Task.jsm", {}); +var {fxAccounts} = Cu.import("resource://gre/modules/FxAccounts.jsm", {}); +var FxAccountsCommon = {}; +Cu.import("resource://gre/modules/FxAccountsCommon.js", FxAccountsCommon); + +const TEST_ROOT = "http://example.com/browser/browser/base/content/test/general/"; + +// instrument gFxAccounts to send observer notifications when it's done +// what it does. +(function() { + let unstubs = {}; // The original functions we stub out. + + // The stub functions. + let stubs = { + updateAppMenuItem: function() { + return unstubs['updateAppMenuItem'].call(gFxAccounts).then(() => { + Services.obs.notifyObservers(null, "test:browser_fxaccounts:updateAppMenuItem", null); + }); + }, + // Opening preferences is trickier than it should be as leaks are reported + // due to the promises it fires off at load time and there's no clear way to + // know when they are done. + // So just ensure openPreferences is called rather than whether it opens. + openPreferences: function() { + Services.obs.notifyObservers(null, "test:browser_fxaccounts:openPreferences", null); + } + }; + + for (let name in stubs) { + unstubs[name] = gFxAccounts[name]; + gFxAccounts[name] = stubs[name]; + } + // and undo our damage at the end. + registerCleanupFunction(() => { + for (let name in unstubs) { + gFxAccounts[name] = unstubs[name]; + } + stubs = unstubs = null; + }); +})(); + +// Other setup/cleanup +var newTab; + +Services.prefs.setCharPref("identity.fxaccounts.remote.signup.uri", + TEST_ROOT + "accounts_testRemoteCommands.html"); + +registerCleanupFunction(() => { + Services.prefs.clearUserPref("identity.fxaccounts.remote.signup.uri"); + Services.prefs.clearUserPref("identity.fxaccounts.remote.profile.uri"); + gBrowser.removeTab(newTab); +}); + +add_task(function* initialize() { + // Set a new tab with something other than about:blank, so it doesn't get reused. + // We must wait for it to load or the promiseTabOpen() call in the next test + // gets confused. + newTab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false}); + yield promiseTabLoaded(newTab); +}); + +// The elements we care about. +var panelUILabel = document.getElementById("PanelUI-fxa-label"); +var panelUIStatus = document.getElementById("PanelUI-fxa-status"); +var panelUIFooter = document.getElementById("PanelUI-footer-fxa"); + +// The tests +add_task(function* test_nouser() { + let user = yield fxAccounts.getSignedInUser(); + Assert.strictEqual(user, null, "start with no user signed in"); + let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem"); + Services.obs.notifyObservers(null, this.FxAccountsCommon.ONLOGOUT_NOTIFICATION, null); + yield promiseUpdateDone; + + // Check the world - the FxA footer area is visible as it is offering a signin. + Assert.ok(isFooterVisible()) + + Assert.equal(panelUILabel.getAttribute("label"), panelUIStatus.getAttribute("defaultlabel")); + Assert.equal(panelUIStatus.getAttribute("tooltiptext"), panelUIStatus.getAttribute("signedinTooltiptext")); + Assert.ok(!panelUIFooter.hasAttribute("fxastatus"), "no fxsstatus when signed out"); + Assert.ok(!panelUIFooter.hasAttribute("fxaprofileimage"), "no fxaprofileimage when signed out"); + + let promisePreferencesOpened = promiseObserver("test:browser_fxaccounts:openPreferences"); + panelUIStatus.click(); + yield promisePreferencesOpened; +}); + +/* +XXX - Bug 1191162 - need a better hawk mock story or this will leak in debug builds. + +add_task(function* test_unverifiedUser() { + let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem"); + yield setSignedInUser(false); // this will fire the observer that does the update. + yield promiseUpdateDone; + + // Check the world. + Assert.ok(isFooterVisible()) + + Assert.equal(panelUILabel.getAttribute("label"), "foo@example.com"); + Assert.equal(panelUIStatus.getAttribute("tooltiptext"), + panelUIStatus.getAttribute("signedinTooltiptext")); + Assert.equal(panelUIFooter.getAttribute("fxastatus"), "signedin"); + let promisePreferencesOpened = promiseObserver("test:browser_fxaccounts:openPreferences"); + panelUIStatus.click(); + yield promisePreferencesOpened + yield signOut(); +}); +*/ + +add_task(function* test_verifiedUserEmptyProfile() { + // We see 2 updateAppMenuItem() calls - one for the signedInUser and one after + // we first fetch the profile. We want them both to fire or we aren't testing + // the state we think we are testing. + let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem", 2); + gFxAccounts._cachedProfile = null; + configureProfileURL({}); // successful but empty profile. + yield setSignedInUser(true); // this will fire the observer that does the update. + yield promiseUpdateDone; + + // Check the world. + Assert.ok(isFooterVisible()) + Assert.equal(panelUILabel.getAttribute("label"), "foo@example.com"); + Assert.equal(panelUIStatus.getAttribute("tooltiptext"), + panelUIStatus.getAttribute("signedinTooltiptext")); + Assert.equal(panelUIFooter.getAttribute("fxastatus"), "signedin"); + + let promisePreferencesOpened = promiseObserver("test:browser_fxaccounts:openPreferences"); + panelUIStatus.click(); + yield promisePreferencesOpened; + yield signOut(); +}); + +add_task(function* test_verifiedUserDisplayName() { + let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem", 2); + gFxAccounts._cachedProfile = null; + configureProfileURL({ displayName: "Test User Display Name" }); + yield setSignedInUser(true); // this will fire the observer that does the update. + yield promiseUpdateDone; + + Assert.ok(isFooterVisible()) + Assert.equal(panelUILabel.getAttribute("label"), "Test User Display Name"); + Assert.equal(panelUIStatus.getAttribute("tooltiptext"), + panelUIStatus.getAttribute("signedinTooltiptext")); + Assert.equal(panelUIFooter.getAttribute("fxastatus"), "signedin"); + yield signOut(); +}); + +add_task(function* test_verifiedUserProfileFailure() { + // profile failure means only one observer fires. + let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem", 1); + gFxAccounts._cachedProfile = null; + configureProfileURL(null, 500); + yield setSignedInUser(true); // this will fire the observer that does the update. + yield promiseUpdateDone; + + Assert.ok(isFooterVisible()) + Assert.equal(panelUILabel.getAttribute("label"), "foo@example.com"); + Assert.equal(panelUIStatus.getAttribute("tooltiptext"), + panelUIStatus.getAttribute("signedinTooltiptext")); + Assert.equal(panelUIFooter.getAttribute("fxastatus"), "signedin"); + yield signOut(); +}); + +// Helpers. +function isFooterVisible() { + let style = window.getComputedStyle(panelUIFooter); + return style.getPropertyValue("display") == "flex"; +} + +function configureProfileURL(profile, responseStatus = 200) { + let responseBody = profile ? JSON.stringify(profile) : ""; + let url = TEST_ROOT + "fxa_profile_handler.sjs?" + + "responseStatus=" + responseStatus + + "responseBody=" + responseBody + + // This is a bit cheeky - the FxA code will just append "/profile" + // to the preference value. We arrange for this to be seen by our + // .sjs as part of the query string. + "&path="; + + Services.prefs.setCharPref("identity.fxaccounts.remote.profile.uri", url); +} + +function promiseObserver(topic, count = 1) { + return new Promise(resolve => { + let obs = (aSubject, aTopic, aData) => { + if (--count == 0) { + Services.obs.removeObserver(obs, aTopic); + resolve(aSubject); + } + } + Services.obs.addObserver(obs, topic, false); + }); +} + +// Stolen from browser_aboutHome.js +function promiseWaitForEvent(node, type, capturing) { + return new Promise((resolve) => { + node.addEventListener(type, function listener(event) { + node.removeEventListener(type, listener, capturing); + resolve(event); + }, capturing); + }); +} + +var promiseTabOpen = Task.async(function*(urlBase) { + info("Waiting for tab to open..."); + let event = yield promiseWaitForEvent(gBrowser.tabContainer, "TabOpen", true); + let tab = event.target; + yield promiseTabLoadEvent(tab); + ok(tab.linkedBrowser.currentURI.spec.startsWith(urlBase), + "Got " + tab.linkedBrowser.currentURI.spec + ", expecting " + urlBase); + let whenUnloaded = promiseTabUnloaded(tab); + gBrowser.removeTab(tab); + yield whenUnloaded; +}); + +function promiseTabUnloaded(tab) +{ + return new Promise(resolve => { + info("Wait for tab to unload"); + function handle(event) { + tab.linkedBrowser.removeEventListener("unload", handle, true); + info("Got unload event"); + resolve(event); + } + tab.linkedBrowser.addEventListener("unload", handle, true, true); + }); +} + +// FxAccounts helpers. +function setSignedInUser(verified) { + let data = { + email: "foo@example.com", + uid: "1234@lcip.org", + assertion: "foobar", + sessionToken: "dead", + kA: "beef", + kB: "cafe", + verified: verified, + + oauthTokens: { + // a token for the profile server. + profile: "key value", + } + } + return fxAccounts.setSignedInUser(data); +} + +var signOut = Task.async(function* () { + // This test needs to make sure that any updates for the logout have + // completed before starting the next test, or we see the observer + // notifications get out of sync. + let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem"); + // we always want a "localOnly" signout here... + yield fxAccounts.signOut(true); + yield promiseUpdateDone; +}); |