mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1139657 - Expose a method on FxAccounts for retrieving profile information. r=markh
This commit is contained in:
parent
116d5cd06c
commit
a4437315a6
@ -11,7 +11,7 @@
|
||||
detail: {
|
||||
id: "account_updates",
|
||||
message: {
|
||||
command: "profile:image:change",
|
||||
command: "profile:change",
|
||||
data: {
|
||||
uid: "abc123",
|
||||
},
|
||||
|
@ -34,7 +34,7 @@ let gTests = [
|
||||
content_uri: HTTP_PATH,
|
||||
});
|
||||
|
||||
makeObserver(FxAccountsCommon.ONPROFILE_IMAGE_CHANGE_NOTIFICATION, function (subject, topic, data) {
|
||||
makeObserver(FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION, function (subject, topic, data) {
|
||||
Assert.ok(tabOpened);
|
||||
Assert.equal(data, "abc123");
|
||||
resolve();
|
||||
|
@ -26,6 +26,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsOAuthGrantClient",
|
||||
"resource://gre/modules/FxAccountsOAuthGrantClient.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsProfile",
|
||||
"resource://gre/modules/FxAccountsProfile.jsm");
|
||||
|
||||
// All properties exposed by the public FxAccounts API.
|
||||
let publicProperties = [
|
||||
"accountStatus",
|
||||
@ -36,6 +39,7 @@ let publicProperties = [
|
||||
"getKeys",
|
||||
"getSignedInUser",
|
||||
"getOAuthToken",
|
||||
"getSignedInUserProfile",
|
||||
"loadAndPoll",
|
||||
"localtimeOffsetMsec",
|
||||
"now",
|
||||
@ -75,6 +79,7 @@ AccountState.prototype = {
|
||||
signedInUser: null,
|
||||
whenVerifiedDeferred: null,
|
||||
whenKeysReadyDeferred: null,
|
||||
profile: null,
|
||||
|
||||
get isCurrent() this.fxaInternal && this.fxaInternal.currentAccountState === this,
|
||||
|
||||
@ -90,10 +95,17 @@ AccountState.prototype = {
|
||||
new Error("Verification aborted; Another user signing in"));
|
||||
this.whenKeysReadyDeferred = null;
|
||||
}
|
||||
|
||||
this.cert = null;
|
||||
this.keyPair = null;
|
||||
this.signedInUser = null;
|
||||
this.fxaInternal = null;
|
||||
this.initProfilePromise = null;
|
||||
|
||||
if (this.profile) {
|
||||
this.profile.tearDown();
|
||||
this.profile = null;
|
||||
}
|
||||
},
|
||||
|
||||
getUserAccountData: function() {
|
||||
@ -204,6 +216,41 @@ AccountState.prototype = {
|
||||
return d.promise.then(result => this.resolve(result));
|
||||
},
|
||||
|
||||
// Get the account's profile image URL from the profile server
|
||||
getProfile: function () {
|
||||
return this.initProfile()
|
||||
.then(() => this.profile.getProfile());
|
||||
},
|
||||
|
||||
// Instantiate a FxAccountsProfile with a fresh OAuth token if needed
|
||||
initProfile: function () {
|
||||
|
||||
let profileServerUrl = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.profile.uri");
|
||||
|
||||
let oAuthOptions = {
|
||||
scope: "profile"
|
||||
};
|
||||
|
||||
if (this.initProfilePromise) {
|
||||
return this.initProfilePromise;
|
||||
}
|
||||
|
||||
this.initProfilePromise = this.fxaInternal.getOAuthToken(oAuthOptions)
|
||||
.then(token => {
|
||||
this.profile = new FxAccountsProfile(this, {
|
||||
profileServerUrl: profileServerUrl,
|
||||
token: token
|
||||
});
|
||||
this.initProfilePromise = null;
|
||||
})
|
||||
.then(null, err => {
|
||||
this.initProfilePromise = null;
|
||||
throw err;
|
||||
});
|
||||
|
||||
return this.initProfilePromise;
|
||||
},
|
||||
|
||||
resolve: function(result) {
|
||||
if (!this.isCurrent) {
|
||||
log.info("An accountState promise was resolved, but was actually rejected" +
|
||||
@ -228,7 +275,7 @@ AccountState.prototype = {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Copies properties from a given object to another object.
|
||||
@ -989,9 +1036,9 @@ FxAccountsInternal.prototype = {
|
||||
let error = SERVER_ERRNO_TO_ERROR[aError.errno];
|
||||
return this._error(ERROR_TO_GENERAL_ERROR_CLASS[error] || ERROR_UNKNOWN, aError);
|
||||
} else if (aError.message &&
|
||||
aError.message === "INVALID_PARAMETER" ||
|
||||
(aError.message === "INVALID_PARAMETER" ||
|
||||
aError.message === "NO_ACCOUNT" ||
|
||||
aError.message === "UNVERIFIED_ACCOUNT") {
|
||||
aError.message === "UNVERIFIED_ACCOUNT")) {
|
||||
return Promise.reject(aError);
|
||||
}
|
||||
return this._error(ERROR_UNKNOWN, aError);
|
||||
@ -1004,7 +1051,60 @@ FxAccountsInternal.prototype = {
|
||||
reason.details = aDetails;
|
||||
}
|
||||
return Promise.reject(reason);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the user's account and profile data
|
||||
*
|
||||
* @param options
|
||||
* {
|
||||
* contentUrl: (string) Used by the FxAccountsProfileChannel.
|
||||
* Defaults to pref identity.fxaccounts.settings.uri
|
||||
* profileServerUrl: (string) Used by the FxAccountsProfileChannel.
|
||||
* Defaults to pref identity.fxaccounts.remote.profile.uri
|
||||
* }
|
||||
*
|
||||
* @return Promise.<object | Error>
|
||||
* The promise resolves to an accountData object with extra profile
|
||||
* information such as profileImageUrl, or rejects with
|
||||
* an error object ({error: ERROR, details: {}}) of the following:
|
||||
* INVALID_PARAMETER
|
||||
* NO_ACCOUNT
|
||||
* UNVERIFIED_ACCOUNT
|
||||
* NETWORK_ERROR
|
||||
* AUTH_ERROR
|
||||
* UNKNOWN_ERROR
|
||||
*/
|
||||
getSignedInUserProfile: function () {
|
||||
let accountState = this.currentAccountState;
|
||||
return accountState.getProfile()
|
||||
.then(
|
||||
(profileData) => {
|
||||
let profile = JSON.parse(JSON.stringify(profileData));
|
||||
// profileData doesn't include "verified", but it must be true
|
||||
// if we've gotten this far.
|
||||
profile.verified = true;
|
||||
return accountState.resolve(profile);
|
||||
},
|
||||
(error) => {
|
||||
log.error("Could not retrieve profile data", error);
|
||||
|
||||
return this.getSignedInUser().then(data => {
|
||||
let profile = null;
|
||||
if (data) {
|
||||
// If we fail to fetch the profile and have no profile cached
|
||||
// we resort to using the account data for basic profile data.
|
||||
profile = {
|
||||
email: data.email,
|
||||
uid: data.uid,
|
||||
verified: data.verified
|
||||
};
|
||||
}
|
||||
return accountState.resolve(profile);
|
||||
});
|
||||
})
|
||||
.then(null, err => this._errorToErrorClass(err));
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -90,7 +90,7 @@ exports.ONLOGOUT_NOTIFICATION = "fxaccounts:onlogout";
|
||||
// Internal to services/fxaccounts only
|
||||
exports.ON_FXA_UPDATE_NOTIFICATION = "fxaccounts:update";
|
||||
|
||||
exports.ONPROFILE_IMAGE_CHANGE_NOTIFICATION = "fxaccounts:profileimagechange";
|
||||
exports.ON_PROFILE_CHANGE_NOTIFICATION = "fxaccounts:profilechange";
|
||||
|
||||
// UI Requests.
|
||||
exports.UI_REQUEST_SIGN_IN_FLOW = "signInFlow";
|
||||
|
165
services/fxaccounts/FxAccountsProfile.jsm
Normal file
165
services/fxaccounts/FxAccountsProfile.jsm
Normal file
@ -0,0 +1,165 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Firefox Accounts Profile helper.
|
||||
*
|
||||
* This class abstracts interaction with the profile server for an account.
|
||||
* It will handle things like fetching profile data, listening for updates to
|
||||
* the user's profile in open browser tabs, and cacheing/invalidating profile data.
|
||||
*/
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["FxAccountsProfile"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsProfileClient",
|
||||
"resource://gre/modules/FxAccountsProfileClient.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsProfileChannel",
|
||||
"resource://gre/modules/FxAccountsProfileChannel.jsm");
|
||||
|
||||
let fxAccountProfileChannel = null;
|
||||
|
||||
// Based off of deepEqual from Assert.jsm
|
||||
function deepEqual(actual, expected) {
|
||||
if (actual === expected) {
|
||||
return true;
|
||||
} else if (typeof actual != "object" && typeof expected != "object") {
|
||||
return actual == expected;
|
||||
} else {
|
||||
return objEquiv(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
function isUndefinedOrNull(value) {
|
||||
return value === null || value === undefined;
|
||||
}
|
||||
|
||||
function objEquiv(a, b) {
|
||||
if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) {
|
||||
return false;
|
||||
}
|
||||
if (a.prototype !== b.prototype) {
|
||||
return false;
|
||||
}
|
||||
let ka, kb, key, i;
|
||||
try {
|
||||
ka = Object.keys(a);
|
||||
kb = Object.keys(b);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
if (ka.length != kb.length) {
|
||||
return false;
|
||||
}
|
||||
ka.sort();
|
||||
kb.sort();
|
||||
for (i = ka.length - 1; i >= 0; i--) {
|
||||
key = ka[i];
|
||||
if (!deepEqual(a[key], b[key])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function hasChanged(oldData, newData) {
|
||||
return !deepEqual(oldData, newData);
|
||||
}
|
||||
|
||||
this.FxAccountsProfile = function (accountState, options = {}) {
|
||||
this.currentAccountState = accountState;
|
||||
this.client = options.profileClient || new FxAccountsProfileClient({
|
||||
serverURL: options.profileServerUrl,
|
||||
token: options.token
|
||||
});
|
||||
|
||||
// for testing
|
||||
if (options.channel) {
|
||||
this.channel = options.channel;
|
||||
}
|
||||
}
|
||||
|
||||
this.FxAccountsProfile.prototype = {
|
||||
|
||||
tearDown: function () {
|
||||
this.currentAccountState = null;
|
||||
this.client = null;
|
||||
},
|
||||
|
||||
_getCachedProfile: function () {
|
||||
let currentState = this.currentAccountState;
|
||||
return currentState.getUserAccountData()
|
||||
.then(cachedData => cachedData.profile);
|
||||
},
|
||||
|
||||
_notifyProfileChange: function (uid) {
|
||||
Services.obs.notifyObservers(null, ON_PROFILE_CHANGE_NOTIFICATION, uid);
|
||||
},
|
||||
|
||||
// Cache fetched data if it is different from what's in the cache.
|
||||
// Send out a notification if it has changed so that UI can update.
|
||||
_cacheProfile: function (profileData) {
|
||||
let currentState = this.currentAccountState;
|
||||
if (!currentState) {
|
||||
return;
|
||||
}
|
||||
return currentState.getUserAccountData()
|
||||
.then(data => {
|
||||
if (!hasChanged(data.profile, profileData)) {
|
||||
return;
|
||||
}
|
||||
data.profile = profileData;
|
||||
return currentState.setUserAccountData(data)
|
||||
.then(() => this._notifyProfileChange(data.uid));
|
||||
});
|
||||
},
|
||||
|
||||
_fetchAndCacheProfile: function () {
|
||||
return this.client.fetchProfile()
|
||||
.then(profile => {
|
||||
return this._cacheProfile(profile).then(() => profile);
|
||||
});
|
||||
},
|
||||
|
||||
// Initialize a profile channel to listen for account changes.
|
||||
_listenForProfileChanges: function () {
|
||||
if (! fxAccountProfileChannel) {
|
||||
let contentUri = Services.urlFormatter.formatURLPref("identity.fxaccounts.settings.uri");
|
||||
|
||||
fxAccountProfileChannel = new FxAccountsProfileChannel({
|
||||
content_uri: contentUri
|
||||
});
|
||||
}
|
||||
|
||||
return fxAccountProfileChannel;
|
||||
},
|
||||
|
||||
// Returns cached data right away if available, then fetches the latest profile
|
||||
// data in the background. After data is fetched a notification will be sent
|
||||
// out if the profile has changed.
|
||||
getProfile: function () {
|
||||
this._listenForProfileChanges();
|
||||
|
||||
return this._getCachedProfile()
|
||||
.then(cachedProfile => {
|
||||
if (cachedProfile) {
|
||||
this._fetchAndCacheProfile();
|
||||
return cachedProfile;
|
||||
}
|
||||
return this._fetchAndCacheProfile();
|
||||
})
|
||||
.then(profile => {
|
||||
return profile;
|
||||
});
|
||||
},
|
||||
};
|
@ -19,7 +19,7 @@ Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebChannel",
|
||||
"resource://gre/modules/WebChannel.jsm");
|
||||
|
||||
const PROFILE_IMAGE_CHANGE_COMMAND = "profile:image:change";
|
||||
const PROFILE_CHANGE_COMMAND = "profile:change";
|
||||
|
||||
/**
|
||||
* Create a new FxAccountsProfileChannel to listen to profile updates
|
||||
@ -102,8 +102,8 @@ this.FxAccountsProfileChannel.prototype = {
|
||||
let command = message.command;
|
||||
let data = message.data;
|
||||
switch (command) {
|
||||
case PROFILE_IMAGE_CHANGE_COMMAND:
|
||||
Services.obs.notifyObservers(null, ONPROFILE_IMAGE_CHANGE_NOTIFICATION, data.uid);
|
||||
case PROFILE_CHANGE_COMMAND:
|
||||
Services.obs.notifyObservers(null, ON_PROFILE_CHANGE_NOTIFICATION, data.uid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ EXTRA_JS_MODULES += [
|
||||
'FxAccountsCommon.js',
|
||||
'FxAccountsOAuthClient.jsm',
|
||||
'FxAccountsOAuthGrantClient.jsm',
|
||||
'FxAccountsProfile.jsm',
|
||||
'FxAccountsProfileChannel.jsm',
|
||||
'FxAccountsProfileClient.jsm',
|
||||
]
|
||||
|
@ -32,6 +32,13 @@ Services.prefs.setCharPref("identity.fxaccounts.remote.oauth.uri", "https://exam
|
||||
Services.prefs.setCharPref("identity.fxaccounts.oauth.client_id", "abc123");
|
||||
|
||||
|
||||
const PROFILE_SERVER_URL = "http://example.com/v1";
|
||||
const CONTENT_URL = "http://accounts.example.com/";
|
||||
|
||||
Services.prefs.setCharPref("identity.fxaccounts.remote.profile.uri", PROFILE_SERVER_URL);
|
||||
Services.prefs.setCharPref("identity.fxaccounts.settings.uri", CONTENT_URL);
|
||||
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
@ -855,6 +862,123 @@ add_test(function test_getOAuthToken_unknown_error() {
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_accountState_initProfile() {
|
||||
let fxa = new MockFxAccounts();
|
||||
let alice = getTestUser("alice");
|
||||
alice.verified = true;
|
||||
|
||||
fxa.internal.getOAuthToken = function (opts) {
|
||||
return Promise.resolve("token");
|
||||
};
|
||||
|
||||
fxa.setSignedInUser(alice).then(() => {
|
||||
let accountState = fxa.internal.currentAccountState;
|
||||
|
||||
accountState.initProfile(options)
|
||||
.then(result => {
|
||||
do_check_true(!!accountState.profile);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
add_test(function test_accountState_getProfile() {
|
||||
let fxa = new MockFxAccounts();
|
||||
let alice = getTestUser("alice");
|
||||
alice.verified = true;
|
||||
|
||||
let mockProfile = {
|
||||
getProfile: function () {
|
||||
return Promise.resolve({ avatar: "image" });
|
||||
}
|
||||
};
|
||||
|
||||
fxa.setSignedInUser(alice).then(() => {
|
||||
let accountState = fxa.internal.currentAccountState;
|
||||
accountState.profile = mockProfile;
|
||||
accountState.initProfilePromise = new Promise((resolve, reject) => resolve(mockProfile));
|
||||
|
||||
accountState.getProfile()
|
||||
.then(result => {
|
||||
do_check_true(!!result);
|
||||
do_check_eq(result.avatar, "image");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
add_test(function test_getSignedInUserProfile_ok() {
|
||||
let fxa = new MockFxAccounts();
|
||||
let alice = getTestUser("alice");
|
||||
alice.verified = true;
|
||||
|
||||
fxa.setSignedInUser(alice).then(() => {
|
||||
let accountState = fxa.internal.currentAccountState;
|
||||
accountState.getProfile = function () {
|
||||
return Promise.resolve({ avatar: "image" });
|
||||
};
|
||||
|
||||
fxa.getSignedInUserProfile()
|
||||
.then(result => {
|
||||
do_check_eq(result.avatar, "image");
|
||||
do_check_true(result.verified);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
add_test(function test_getSignedInUserProfile_error_uses_account_data() {
|
||||
let fxa = new MockFxAccounts();
|
||||
let alice = getTestUser("alice");
|
||||
alice.verified = true;
|
||||
|
||||
fxa.internal.getSignedInUser = function () {
|
||||
return Promise.resolve({ email: "foo@bar.com" });
|
||||
};
|
||||
|
||||
fxa.setSignedInUser(alice).then(() => {
|
||||
let accountState = fxa.internal.currentAccountState;
|
||||
accountState.getProfile = function () {
|
||||
return Promise.reject("boom");
|
||||
};
|
||||
|
||||
fxa.getSignedInUserProfile()
|
||||
.then(result => {
|
||||
do_check_eq(typeof result.avatar, "undefined");
|
||||
do_check_eq(result.email, "foo@bar.com");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
add_test(function test_getSignedInUserProfile_no_account_data() {
|
||||
let fxa = new MockFxAccounts();
|
||||
|
||||
fxa.internal.getSignedInUser = function () {
|
||||
return Promise.resolve({ email: "foo@bar.com" });
|
||||
};
|
||||
|
||||
let accountState = fxa.internal.currentAccountState;
|
||||
accountState.getProfile = function () {
|
||||
return Promise.reject("boom");
|
||||
};
|
||||
|
||||
fxa.internal.getSignedInUser = function () {
|
||||
return Promise.resolve(null);
|
||||
};
|
||||
|
||||
fxa.getSignedInUserProfile()
|
||||
.then(result => {
|
||||
do_check_eq(result, null);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
* End of tests.
|
||||
* Utility functions follow.
|
||||
|
286
services/fxaccounts/tests/xpcshell/test_profile.js
Normal file
286
services/fxaccounts/tests/xpcshell/test_profile.js
Normal file
@ -0,0 +1,286 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||
Cu.import("resource://gre/modules/FxAccountsProfileClient.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccountsProfile.jsm");
|
||||
|
||||
const URL_STRING = "https://example.com";
|
||||
Services.prefs.setCharPref("identity.fxaccounts.settings.uri", "https://example.com/settings");
|
||||
|
||||
const PROFILE_CLIENT_OPTIONS = {
|
||||
token: "123ABC",
|
||||
serverURL: "http://127.0.0.1:1111/v1",
|
||||
profileServerUrl: "http://127.0.0.1:1111/v1"
|
||||
};
|
||||
|
||||
const STATUS_SUCCESS = 200;
|
||||
|
||||
/**
|
||||
* Mock request responder
|
||||
* @param {String} response
|
||||
* Mocked raw response from the server
|
||||
* @returns {Function}
|
||||
*/
|
||||
let mockResponse = function (response) {
|
||||
let Request = function (requestUri) {
|
||||
// Store the request uri so tests can inspect it
|
||||
Request._requestUri = requestUri;
|
||||
return {
|
||||
setHeader: function () {},
|
||||
head: function () {
|
||||
this.response = response;
|
||||
this.onComplete();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return Request;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mock request error responder
|
||||
* @param {Error} error
|
||||
* Error object
|
||||
* @returns {Function}
|
||||
*/
|
||||
let mockResponseError = function (error) {
|
||||
return function () {
|
||||
return {
|
||||
setHeader: function () {},
|
||||
head: function () {
|
||||
this.onComplete(error);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
let mockClient = function () {
|
||||
let client = new FxAccountsProfileClient(PROFILE_CLIENT_OPTIONS);
|
||||
return client;
|
||||
};
|
||||
|
||||
const ACCOUNT_DATA = {
|
||||
uid: "abc123"
|
||||
};
|
||||
|
||||
function AccountData () {
|
||||
}
|
||||
AccountData.prototype = {
|
||||
getUserAccountData: function () {
|
||||
return Promise.resolve(ACCOUNT_DATA);
|
||||
}
|
||||
};
|
||||
|
||||
let mockAccountData = function () {
|
||||
return new AccountData();
|
||||
};
|
||||
|
||||
add_test(function getCachedProfile() {
|
||||
let accountData = mockAccountData();
|
||||
accountData.getUserAccountData = function () {
|
||||
return Promise.resolve({
|
||||
profile: { avatar: "myurl" }
|
||||
});
|
||||
};
|
||||
let profile = new FxAccountsProfile(accountData, PROFILE_CLIENT_OPTIONS);
|
||||
|
||||
return profile._getCachedProfile()
|
||||
.then(function (cached) {
|
||||
do_check_eq(cached.avatar, "myurl");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function cacheProfile_change() {
|
||||
let accountData = mockAccountData();
|
||||
let setUserAccountDataCalled = false;
|
||||
accountData.setUserAccountData = function (data) {
|
||||
setUserAccountDataCalled = true;
|
||||
do_check_eq(data.profile.avatar, "myurl");
|
||||
return Promise.resolve();
|
||||
};
|
||||
let profile = new FxAccountsProfile(accountData, PROFILE_CLIENT_OPTIONS);
|
||||
|
||||
makeObserver(ON_PROFILE_CHANGE_NOTIFICATION, function (subject, topic, data) {
|
||||
do_check_eq(data, ACCOUNT_DATA.uid);
|
||||
do_check_true(setUserAccountDataCalled);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
return profile._cacheProfile({ avatar: "myurl" });
|
||||
});
|
||||
|
||||
add_test(function cacheProfile_no_change() {
|
||||
let accountData = mockAccountData();
|
||||
accountData.getUserAccountData = function () {
|
||||
return Promise.resolve({
|
||||
profile: { avatar: "myurl" }
|
||||
});
|
||||
};
|
||||
accountData.setUserAccountData = function (data) {
|
||||
throw new Error("should not update account data");
|
||||
};
|
||||
let profile = new FxAccountsProfile(accountData, PROFILE_CLIENT_OPTIONS);
|
||||
|
||||
return profile._cacheProfile({ avatar: "myurl" })
|
||||
.then((result) => {
|
||||
do_check_false(!!result);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function fetchAndCacheProfile_ok() {
|
||||
let client = mockClient();
|
||||
client.fetchProfile = function () {
|
||||
return Promise.resolve({ avatar: "myimg"});
|
||||
};
|
||||
let profile = new FxAccountsProfile(mockAccountData(), {
|
||||
profileClient: client
|
||||
});
|
||||
|
||||
profile._cacheProfile = function (toCache) {
|
||||
do_check_eq(toCache.avatar, "myimg");
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
return profile._fetchAndCacheProfile()
|
||||
.then(result => {
|
||||
do_check_eq(result.avatar, "myimg");
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
add_test(function profile_channel() {
|
||||
let profile = new FxAccountsProfile(mockAccountData(), PROFILE_CLIENT_OPTIONS);
|
||||
|
||||
let channel = profile._listenForProfileChanges();
|
||||
do_check_true(!!channel);
|
||||
|
||||
let channel2 = profile._listenForProfileChanges();
|
||||
|
||||
do_check_eq(channel, channel2);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function tearDown_ok() {
|
||||
let profile = new FxAccountsProfile(mockAccountData(), PROFILE_CLIENT_OPTIONS);
|
||||
|
||||
do_check_true(!!profile.client);
|
||||
do_check_true(!!profile.currentAccountState);
|
||||
|
||||
profile.tearDown();
|
||||
do_check_null(profile.currentAccountState);
|
||||
do_check_null(profile.client);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function getProfile_ok() {
|
||||
let cachedUrl = "myurl";
|
||||
let accountData = mockAccountData();
|
||||
let didFetch = false;
|
||||
let didListen = false;
|
||||
|
||||
let profile = new FxAccountsProfile(accountData, PROFILE_CLIENT_OPTIONS);
|
||||
profile._getCachedProfile = function () {
|
||||
return Promise.resolve({ avatar: cachedUrl });
|
||||
};
|
||||
|
||||
profile._fetchAndCacheProfile = function () {
|
||||
didFetch = true;
|
||||
};
|
||||
profile._listenForProfileChanges = function () {
|
||||
didListen = true;
|
||||
};
|
||||
|
||||
return profile.getProfile()
|
||||
.then(result => {
|
||||
do_check_eq(result.avatar, cachedUrl);
|
||||
do_check_true(didFetch);
|
||||
do_check_true(didListen);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function getProfile_no_cache() {
|
||||
let fetchedUrl = "newUrl";
|
||||
let accountData = mockAccountData();
|
||||
let didListen = false;
|
||||
|
||||
let profile = new FxAccountsProfile(accountData, PROFILE_CLIENT_OPTIONS);
|
||||
profile._getCachedProfile = function () {
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
profile._fetchAndCacheProfile = function () {
|
||||
return Promise.resolve({ avatar: fetchedUrl });
|
||||
};
|
||||
profile._listenForProfileChanges = function () {
|
||||
didListen = true;
|
||||
};
|
||||
|
||||
return profile.getProfile()
|
||||
.then(result => {
|
||||
do_check_eq(result.avatar, fetchedUrl);
|
||||
do_check_true(didListen);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function getProfile_has_cached_fetch_deleted() {
|
||||
let cachedUrl = "myurl";
|
||||
let didFetch = false;
|
||||
let didListen = false;
|
||||
|
||||
let client = mockClient();
|
||||
client.fetchProfile = function () {
|
||||
return Promise.resolve({ avatar: null });
|
||||
};
|
||||
|
||||
let accountData = mockAccountData();
|
||||
accountData.getUserAccountData = function () {
|
||||
return Promise.resolve({ profile: { avatar: cachedUrl } });
|
||||
};
|
||||
accountData.setUserAccountData = function (data) {
|
||||
do_check_null(data.profile.avatar);
|
||||
run_next_test();
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
let profile = new FxAccountsProfile(accountData, {
|
||||
profileClient: client
|
||||
});
|
||||
|
||||
return profile.getProfile()
|
||||
.then(result => {
|
||||
do_check_eq(result.avatar, "myurl");
|
||||
});
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function makeObserver(aObserveTopic, aObserveFunc) {
|
||||
let callback = function (aSubject, aTopic, aData) {
|
||||
log.debug("observed " + aTopic + " " + aData);
|
||||
if (aTopic == aObserveTopic) {
|
||||
removeMe();
|
||||
aObserveFunc(aSubject, aTopic, aData);
|
||||
}
|
||||
};
|
||||
|
||||
function removeMe() {
|
||||
log.debug("removing observer for " + aObserveTopic);
|
||||
Services.obs.removeObserver(callback, aObserveTopic);
|
||||
}
|
||||
|
||||
Services.obs.addObserver(callback, aObserveTopic, false);
|
||||
return removeMe;
|
||||
}
|
@ -23,11 +23,11 @@ add_test(function () {
|
||||
|
||||
add_test(function () {
|
||||
var mockMessage = {
|
||||
command: "profile:image:change",
|
||||
command: "profile:change",
|
||||
data: { uid: "foo" }
|
||||
};
|
||||
|
||||
makeObserver(ONPROFILE_IMAGE_CHANGE_NOTIFICATION, function (subject, topic, data) {
|
||||
makeObserver(ON_PROFILE_CHANGE_NOTIFICATION, function (subject, topic, data) {
|
||||
do_check_eq(data, "foo");
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -16,3 +16,4 @@ reason = FxAccountsManager is only available for B2G for now
|
||||
[test_oauth_grant_client.js]
|
||||
[test_profile_client.js]
|
||||
[test_profile_channel.js]
|
||||
[test_profile.js]
|
||||
|
Loading…
Reference in New Issue
Block a user