Bug 1053939 - pass entry point to fxa content server when opening about:accounts + tests. r=markh

This commit is contained in:
Alex Bardas 2014-09-10 13:39:00 +02:00
parent a316f27bea
commit 603011765d
14 changed files with 217 additions and 49 deletions

View File

@ -96,7 +96,7 @@ function shouldAllowRelink(acctName) {
let wrapper = {
iframe: null,
init: function (url=null) {
init: function (url, entryPoint) {
let weave = Cc["@mozilla.org/weave/service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject;
@ -116,9 +116,11 @@ let wrapper = {
let iframe = document.getElementById("remote");
this.iframe = iframe;
iframe.addEventListener("load", this);
try {
iframe.src = url || fxAccounts.getAccountsSignUpURI();
if (entryPoint) {
url += (url.indexOf("?") >= 0 ? "&" : "?") + entryPoint;
}
iframe.src = url;
} catch (e) {
error("Couldn't init Firefox Account wrapper: " + e.message);
}
@ -288,6 +290,17 @@ function openPrefs() {
function init() {
fxAccounts.getSignedInUser().then(user => {
// If the url contains an entrypoint query parameter, extract it into a variable
// to append it to the accounts URI resource.
// Works for the following cases:
// - about:accounts?entrypoint="abouthome"
// - about:accounts?entrypoint=abouthome&action=signup
let entryPointQParam = "entrypoint=";
let entryPointPos = window.location.href.indexOf(entryPointQParam);
let entryPoint = "";
if (entryPointPos >= 0) {
entryPoint = window.location.href.substring(entryPointPos).split("&")[0];
}
// tests in particular might cause the window to start closing before
// getSignedInUser has returned.
if (window.closed) {
@ -299,7 +312,7 @@ function init() {
show("stage", "manage");
} else {
show("remote");
wrapper.init(fxAccounts.getAccountsSignInURI());
wrapper.init(fxAccounts.getAccountsSignInURI(), entryPoint);
}
} else if (window.location.href.contains("action=signup")) {
if (user) {
@ -307,7 +320,7 @@ function init() {
show("stage", "manage");
} else {
show("remote");
wrapper.init();
wrapper.init(fxAccounts.getAccountsSignUpURI(), entryPoint);
}
} else if (window.location.href.contains("action=reauth")) {
// ideally we would only show this when we know the user is in a
@ -316,7 +329,7 @@ function init() {
// promiseAccountsForceSigninURI, just always show it.
fxAccounts.promiseAccountsForceSigninURI().then(url => {
show("remote");
wrapper.init(url);
wrapper.init(url, entryPoint);
});
} else {
// No action specified
@ -327,7 +340,7 @@ function init() {
} else {
show("stage", "intro");
// load the remote frame in the background
wrapper.init();
wrapper.init(fxAccounts.getAccountsSignUpURI(), entryPoint);
}
}
});

View File

@ -224,10 +224,22 @@ let gFxAccounts = {
},
openAccountsPage: function () {
switchToTabHavingURI("about:accounts", true);
let entryPoint = "menupanel";
if (UITour.originTabs.get(window) && UITour.originTabs.get(window).has(gBrowser.selectedTab)) {
entryPoint = "uitour";
}
switchToTabHavingURI("about:accounts?entrypoint=" + entryPoint, true, {
replaceQueryString: true
});
},
openSignInAgainPage: function () {
switchToTabHavingURI("about:accounts?action=reauth", true);
let entryPoint = "menupanel";
if (UITour.originTabs.get(window) && UITour.originTabs.get(window).has(gBrowser.selectedTab)) {
entryPoint = "uitour";
}
switchToTabHavingURI("about:accounts?action=reauth&entrypoint=" + entryPoint, true, {
replaceQueryString: true
});
}
};

View File

@ -476,7 +476,7 @@
label="&syncSetup.label;"
accesskey="&syncSetup.accesskey;"
observes="sync-setup-state"
oncommand="gSyncUI.openSetup()"/>
oncommand="gSyncUI.openSetup(null, 'menubar')"/>
<menuitem id="sync-syncnowitem"
label="&syncSyncNowItem.label;"
accesskey="&syncSyncNowItem.accesskey;"
@ -486,7 +486,7 @@
label="&syncReAuthItem.label;"
accesskey="&syncReAuthItem.accesskey;"
observes="sync-reauth-state"
oncommand="gSyncUI.openSignInAgainPage();"/>
oncommand="gSyncUI.openSignInAgainPage('menubar');"/>
#endif
<menuseparator id="devToolsSeparator"/>
<menu id="webDeveloperMenu"

View File

@ -314,9 +314,11 @@ let gSyncUI = {
* null -- regular set up wizard
* "pair" -- pair a device first
* "reset" -- reset sync
* @param entryPoint
* Indicates the entrypoint from where this method was called.
*/
openSetup: function SUI_openSetup(wizardType) {
openSetup: function SUI_openSetup(wizardType, entryPoint = "syncbutton") {
let xps = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
@ -325,7 +327,13 @@ let gSyncUI = {
if (userData) {
this.openPrefs();
} else {
switchToTabHavingURI("about:accounts", true);
// If the user is also in an uitour, set the entrypoint to `uitour`
if (UITour.originTabs.get(window) && UITour.originTabs.get(window).has(gBrowser.selectedTab)) {
entryPoint = "uitour";
}
switchToTabHavingURI("about:accounts?entrypoint=" + entryPoint, true, {
replaceQueryString: true
});
}
});
} else {
@ -366,8 +374,14 @@ let gSyncUI = {
openPreferences("paneSync");
},
openSignInAgainPage: function () {
switchToTabHavingURI("about:accounts?action=reauth", true);
openSignInAgainPage: function (entryPoint = "syncbutton") {
// If the user is also in an uitour, set the entrypoint to `uitour`
if (UITour.originTabs.get(window) && UITour.originTabs.get(window).has(gBrowser.selectedTab)) {
entryPoint = "uitour";
}
switchToTabHavingURI("about:accounts?action=reauth&entrypoint=" + entryPoint, true, {
replaceQueryString: true
});
},
// Helpers

View File

@ -180,6 +180,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "TabCrashReporter",
XPCOMUtils.defineLazyModuleGetter(this, "FormValidationHandler",
"resource:///modules/FormValidationHandler.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
"resource:///modules/UITour.jsm");
let gInitialPages = [
"about:blank",
"about:newtab",
@ -6916,9 +6919,13 @@ let gRemoteTabsUI = {
* If switching to this URI results in us opening a tab, aOpenParams
* will be the parameter object that gets passed to openUILinkIn. Please
* see the documentation for openUILinkIn to see what parameters can be
* passed via this object. This object also allows the 'ignoreFragment'
* property to be set to true to exclude fragment-portion matching when
* comparing URIs.
* passed via this object.
* This object also allows:
* - 'ignoreFragment' property to be set to true to exclude fragment-portion
* matching when comparing URIs.
* - 'replaceQueryString' property to be set to true to exclude query string
* matching when comparing URIs and ovewrite the initial query string with
* the one from the new URI.
* @return True if an existing tab was found, false otherwise
*/
function switchToTabHavingURI(aURI, aOpenNew, aOpenParams={}) {
@ -6929,6 +6936,8 @@ function switchToTabHavingURI(aURI, aOpenNew, aOpenParams={}) {
]);
let ignoreFragment = aOpenParams.ignoreFragment;
let replaceQueryString = aOpenParams.replaceQueryString;
// This property is only used by switchToTabHavingURI and should
// not be used as a parameter for the new load.
delete aOpenParams.ignoreFragment;
@ -6960,6 +6969,15 @@ function switchToTabHavingURI(aURI, aOpenNew, aOpenParams={}) {
}
return true;
}
if (replaceQueryString) {
if (browser.currentURI.spec.split("?")[0] == aURI.spec.split("?")[0]) {
// Focus the matching window & tab
aWindow.focus();
aWindow.gBrowser.tabContainer.selectedIndex = i;
browser.loadURI(aURI.spec);
return true;
}
}
}
return false;
}

View File

@ -189,6 +189,38 @@ let gTests = [
is(tab.linkedBrowser.contentDocument.location.href, "about:accounts?action=signin");
}
},
{
desc: "Test entrypoint query string, no action, no user logged in",
teardown: () => gBrowser.removeCurrentTab(),
run: function* () {
// When this loads with no user logged-in, we expect the "normal" URL
setPref("identity.fxaccounts.remote.signup.uri", "https://example.com/");
let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?entrypoint=abouthome");
is(url, "https://example.com/?entrypoint=abouthome", "entrypoint=abouthome got the expected URL");
},
},
{
desc: "Test entrypoint query string for signin",
teardown: () => gBrowser.removeCurrentTab(),
run: function* () {
// When this loads with no user logged-in, we expect the "normal" URL
const expected_url = "https://example.com/?is_sign_in";
setPref("identity.fxaccounts.remote.signin.uri", expected_url);
let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=signin&entrypoint=abouthome");
is(url, expected_url + "&entrypoint=abouthome", "entrypoint=abouthome got the expected URL");
},
},
{
desc: "Test entrypoint query string for signup",
teardown: () => gBrowser.removeCurrentTab(),
run: function* () {
// When this loads with no user logged-in, we expect the "normal" URL
const sign_up_url = "https://example.com/?is_sign_up";
setPref("identity.fxaccounts.remote.signup.uri", sign_up_url);
let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?entrypoint=abouthome&action=signup");
is(url, sign_up_url + "&entrypoint=abouthome", "entrypoint=abouthome got the expected URL");
},
},
]; // gTests
function test()

View File

@ -454,6 +454,18 @@ let gTests = [
yield promiseWaitForCondition(() => doc.activeElement === searchInput);
is(searchInput, doc.activeElement, "Search bar should be the active element.");
})
},
{
desc: "Sync button should open about:accounts page with `abouthome` entrypoint",
setup: function () {},
run: Task.async(function* () {
let syncButton = gBrowser.selectedTab.linkedBrowser.contentDocument.getElementById("sync");
yield EventUtils.synthesizeMouseAtCenter(syncButton, {}, gBrowser.contentWindow);
yield promiseTabLoadEvent(gBrowser.selectedTab, null, "load");
is(gBrowser.currentURI.spec, "about:accounts?entrypoint=abouthome",
"Entry point should be `abouthome`.");
})
}
];

View File

@ -15,21 +15,48 @@ add_task(function() {
gBrowser.selectedTab = tabRefAboutMozilla;
let numTabsAtStart = gBrowser.tabs.length;
switchTab("about:home#1", false, true);
switchTab("about:mozilla", false, true);
switchTab("about:home#2", true, true);
switchTab("about:home#1", false, false, true);
switchTab("about:mozilla", false, false, true);
switchTab("about:home#2", true, false, true);
is(tabRefAboutHome, gBrowser.selectedTab, "The same about:home tab should be switched to");
is(gBrowser.currentURI.ref, "2", "The ref should be updated to the new ref");
switchTab("about:mozilla", false, true);
switchTab("about:home#1", false, false);
switchTab("about:mozilla", false, false, true);
switchTab("about:home#1", false, false, false);
isnot(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should not be initial about:blank tab");
is(gBrowser.tabs.length, numTabsAtStart + 1, "Should have one new tab opened");
switchTab("about:about", true, false);
switchTab("about:about", true, false, false);
});
function switchTab(aURI, aIgnoreFragment, aShouldFindExistingTab) {
let tabFound = switchToTabHavingURI(aURI, true, {ignoreFragment: aIgnoreFragment});
// Test for replaceQueryString option.
add_task(function() {
registerCleanupFunction(function() {
while (gBrowser.tabs.length > 1)
gBrowser.removeCurrentTab();
});
let tabRefAboutHome = gBrowser.addTab("about:home?hello=firefox");
yield promiseTabLoaded(tabRefAboutHome);
switchTab("about:home", false, false, false);
switchTab("about:home?hello=firefox", false, false, true);
switchTab("about:home?hello=firefoxos", false, false, false);
// Remove the last opened tab to test replaceQueryString option.
gBrowser.removeCurrentTab();
switchTab("about:home?hello=firefoxos", false, true, true);
is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab");
// Wait for the tab to load the new URI spec.
yield promiseTabLoaded(tabRefAboutHome);
is(gBrowser.currentURI.spec, "about:home?hello=firefoxos", "The spec should be updated to the new spec");
});
function switchTab(aURI, aIgnoreFragment, aReplaceQueryString, aShouldFindExistingTab) {
let tabFound = switchToTabHavingURI(aURI, true, {
ignoreFragment: aIgnoreFragment,
replaceQueryString: aReplaceQueryString
});
is(tabFound, aShouldFindExistingTab,
"Should switch to existing " + aURI + " tab if one existed, " +
(aIgnoreFragment ? "ignoring" : "including") + " fragment portion");
(aIgnoreFragment ? "ignoring" : "including") + " fragment portion, " +
(aReplaceQueryString ? "ignoring" : "replacing") + " query string.");
}

View File

@ -2,12 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// The test expects the about:accounts page to open in the current tab
"use strict";
XPCOMUtils.defineLazyModuleGetter(this, "UITour", "resource:///modules/UITour.jsm");
let initialLocation = gBrowser.currentURI.spec;
let newTab = null;
add_task(function() {
function openAboutAccountsFromMenuPanel(entryPoint) {
info("Check Sync button functionality");
Services.prefs.setCharPref("identity.fxaccounts.remote.signup.uri", "http://example.com/");
@ -17,14 +21,27 @@ add_task(function() {
// check the button's functionality
yield PanelUI.show();
if (entryPoint == "uitour") {
UITour.originTabs.set(window, new Set());
UITour.originTabs.get(window).add(gBrowser.selectedTab);
}
let syncButton = document.getElementById("sync-button");
ok(syncButton, "The Sync button was added to the Panel Menu");
let deferred = Promise.defer();
let handler = () => {
gBrowser.selectedTab.removeEventListener("load", handler, true);
deferred.resolve();
}
gBrowser.selectedTab.addEventListener("load", handler, true);
syncButton.click();
yield deferred.promise;
newTab = gBrowser.selectedTab;
yield promiseTabLoadEvent(newTab, "about:accounts");
is(gBrowser.currentURI.spec, "about:accounts", "Firefox Sync page opened");
is(gBrowser.currentURI.spec, "about:accounts?entrypoint=" + entryPoint,
"Firefox Sync page opened with `menupanel` entrypoint");
ok(!isPanelUIOpen(), "The panel closed");
if(isPanelUIOpen()) {
@ -32,9 +49,9 @@ add_task(function() {
PanelUI.hide();
yield panelHidePromise;
}
});
}
add_task(function asyncCleanup() {
function asyncCleanup() {
Services.prefs.clearUserPref("identity.fxaccounts.remote.signup.uri");
// reset the panel UI to the default state
yield resetCustomization();
@ -43,4 +60,11 @@ add_task(function asyncCleanup() {
// restore the tabs
gBrowser.addTab(initialLocation);
gBrowser.removeTab(newTab);
});
UITour.originTabs.delete(window);
}
add_task(() => openAboutAccountsFromMenuPanel("syncbutton"));
add_task(asyncCleanup);
// Test that uitour is in progress, the entrypoint is `uitour` and not `menupanel`
add_task(() => openAboutAccountsFromMenuPanel("uitour"));
add_task(asyncCleanup);

View File

@ -313,7 +313,9 @@ let gSyncPane = {
.wrappedJSObject;
if (service.fxAccountsEnabled) {
this.openContentInBrowser("about:accounts");
this.openContentInBrowser("about:accounts?entrypoint=preferences", {
replaceQueryString: true
});
} else {
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
if (win)
@ -326,7 +328,7 @@ let gSyncPane = {
}
},
openContentInBrowser: function(url) {
openContentInBrowser: function(url, options) {
let win = Services.wm.getMostRecentWindow("navigator:browser");
if (!win) {
// no window to use, so use _openLink to create a new one. We don't
@ -335,7 +337,7 @@ let gSyncPane = {
gSyncUtils._openLink(url);
return;
}
win.openUILinkIn(url, "tab");
win.switchToTabHavingURI(url, true, options);
},
@ -350,15 +352,21 @@ let gSyncPane = {
},
signUp: function() {
this.openContentInBrowser("about:accounts?action=signup");
this.openContentInBrowser("about:accounts?action=signup&entrypoint=preferences", {
replaceQueryString: true
});
},
signIn: function() {
this.openContentInBrowser("about:accounts?action=signin");
this.openContentInBrowser("about:accounts?action=signin&entrypoint=preferences", {
replaceQueryString: true
});
},
reSignIn: function() {
this.openContentInBrowser("about:accounts?action=reauth");
this.openContentInBrowser("about:accounts?action=reauth&entrypoint=preferences", {
replaceQueryString: true
});
},
manageFirefoxAccount: function() {

View File

@ -229,7 +229,9 @@ let gSyncPane = {
.wrappedJSObject;
if (service.fxAccountsEnabled) {
this.openContentInBrowser("about:accounts");
this.openContentInBrowser("about:accounts?entrypoint=preferences", {
replaceQueryString: true
});
} else {
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
if (win) {
@ -242,7 +244,7 @@ let gSyncPane = {
}
},
openContentInBrowser: function(url) {
openContentInBrowser: function(url, options) {
let win = Services.wm.getMostRecentWindow("navigator:browser");
if (!win) {
// no window to use, so use _openLink to create a new one. We don't
@ -251,21 +253,27 @@ let gSyncPane = {
gSyncUtils._openLink(url);
return;
}
win.switchToTabHavingURI(url, true);
win.switchToTabHavingURI(url, true, options);
// seeing as we are doing this in a tab we close the prefs dialog.
window.close();
},
signUp: function() {
this.openContentInBrowser("about:accounts?action=signup");
this.openContentInBrowser("about:accounts?action=signup&entrypoint=preferences", {
replaceQueryString: true
});
},
signIn: function() {
this.openContentInBrowser("about:accounts?action=signin");
this.openContentInBrowser("about:accounts?action=signin&entrypoint=preferences", {
replaceQueryString: true
});
},
reSignIn: function() {
this.openContentInBrowser("about:accounts?action=reauth");
this.openContentInBrowser("about:accounts?action=reauth&entrypoint=preferences", {
replaceQueryString: true
});
},
manageFirefoxAccount: function() {

View File

@ -159,7 +159,7 @@ let AboutHome = {
if (userData) {
window.openPreferences("paneSync");
} else {
window.loadURI("about:accounts");
window.loadURI("about:accounts?entrypoint=abouthome");
}
});
} else {

View File

@ -424,7 +424,7 @@ this.UITour = {
// 'signup' is the only action that makes sense currently, so we don't
// accept arbitrary actions just to be safe...
// We want to replace the current tab.
contentDocument.location.href = "about:accounts?action=signup";
contentDocument.location.href = "about:accounts?action=signup&entrypoint=uitour";
break;
}
}

View File

@ -51,7 +51,7 @@ let tests = [
tabBrowser.removeEventListener("load", onload, true);
ise(tabBrowser.contentDocument.location.href,
"about:accounts?action=signup",
"about:accounts?action=signup&entrypoint=uitour",
"about:accounts should have replaced the tab");
// the iframe in about:accounts will still be loading, so we stop