diff options
Diffstat (limited to 'services/fxaccounts/tests/xpcshell/test_web_channel.js')
-rw-r--r-- | services/fxaccounts/tests/xpcshell/test_web_channel.js | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/services/fxaccounts/tests/xpcshell/test_web_channel.js b/services/fxaccounts/tests/xpcshell/test_web_channel.js new file mode 100644 index 000000000..3cf566278 --- /dev/null +++ b/services/fxaccounts/tests/xpcshell/test_web_channel.js @@ -0,0 +1,499 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +Cu.import("resource://gre/modules/FxAccountsCommon.js"); +const { FxAccountsWebChannel, FxAccountsWebChannelHelpers } = + Cu.import("resource://gre/modules/FxAccountsWebChannel.jsm"); + +const URL_STRING = "https://example.com"; + +const mockSendingContext = { + browser: {}, + principal: {}, + eventTarget: {} +}; + +add_test(function () { + validationHelper(undefined, + "Error: Missing configuration options"); + + validationHelper({ + channel_id: WEBCHANNEL_ID + }, + "Error: Missing 'content_uri' option"); + + validationHelper({ + content_uri: 'bad uri', + channel_id: WEBCHANNEL_ID + }, + /NS_ERROR_MALFORMED_URI/); + + validationHelper({ + content_uri: URL_STRING + }, + 'Error: Missing \'channel_id\' option'); + + run_next_test(); +}); + +add_task(function* test_rejection_reporting() { + let mockMessage = { + command: 'fxaccounts:login', + messageId: '1234', + data: { email: 'testuser@testuser.com' }, + }; + + let channel = new FxAccountsWebChannel({ + channel_id: WEBCHANNEL_ID, + content_uri: URL_STRING, + helpers: { + login(accountData) { + equal(accountData.email, 'testuser@testuser.com', + 'Should forward incoming message data to the helper'); + return Promise.reject(new Error('oops')); + }, + }, + }); + + let promiseSend = new Promise(resolve => { + channel._channel.send = (message, context) => { + resolve({ message, context }); + }; + }); + + channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext); + + let { message, context } = yield promiseSend; + + equal(context, mockSendingContext, 'Should forward the original context'); + equal(message.command, 'fxaccounts:login', + 'Should include the incoming command'); + equal(message.messageId, '1234', 'Should include the message ID'); + equal(message.data.error.message, 'Error: oops', + 'Should convert the error message to a string'); + notStrictEqual(message.data.error.stack, null, + 'Should include the stack for JS error rejections'); +}); + +add_test(function test_exception_reporting() { + let mockMessage = { + command: 'fxaccounts:sync_preferences', + messageId: '5678', + data: { entryPoint: 'fxa:verification_complete' } + }; + + let channel = new FxAccountsWebChannel({ + channel_id: WEBCHANNEL_ID, + content_uri: URL_STRING, + helpers: { + openSyncPreferences(browser, entryPoint) { + equal(entryPoint, 'fxa:verification_complete', + 'Should forward incoming message data to the helper'); + throw new TypeError('splines not reticulated'); + }, + }, + }); + + channel._channel.send = (message, context) => { + equal(context, mockSendingContext, 'Should forward the original context'); + equal(message.command, 'fxaccounts:sync_preferences', + 'Should include the incoming command'); + equal(message.messageId, '5678', 'Should include the message ID'); + equal(message.data.error.message, 'TypeError: splines not reticulated', + 'Should convert the exception to a string'); + notStrictEqual(message.data.error.stack, null, + 'Should include the stack for JS exceptions'); + + run_next_test(); + }; + + channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext); +}); + +add_test(function test_profile_image_change_message() { + var mockMessage = { + command: "profile:change", + data: { uid: "foo" } + }; + + makeObserver(ON_PROFILE_CHANGE_NOTIFICATION, function (subject, topic, data) { + do_check_eq(data, "foo"); + run_next_test(); + }); + + var channel = new FxAccountsWebChannel({ + channel_id: WEBCHANNEL_ID, + content_uri: URL_STRING + }); + + channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext); +}); + +add_test(function test_login_message() { + let mockMessage = { + command: 'fxaccounts:login', + data: { email: 'testuser@testuser.com' } + }; + + let channel = new FxAccountsWebChannel({ + channel_id: WEBCHANNEL_ID, + content_uri: URL_STRING, + helpers: { + login: function (accountData) { + do_check_eq(accountData.email, 'testuser@testuser.com'); + run_next_test(); + return Promise.resolve(); + } + } + }); + + channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext); +}); + +add_test(function test_logout_message() { + let mockMessage = { + command: 'fxaccounts:logout', + data: { uid: "foo" } + }; + + let channel = new FxAccountsWebChannel({ + channel_id: WEBCHANNEL_ID, + content_uri: URL_STRING, + helpers: { + logout: function (uid) { + do_check_eq(uid, 'foo'); + run_next_test(); + return Promise.resolve(); + } + } + }); + + channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext); +}); + +add_test(function test_delete_message() { + let mockMessage = { + command: 'fxaccounts:delete', + data: { uid: "foo" } + }; + + let channel = new FxAccountsWebChannel({ + channel_id: WEBCHANNEL_ID, + content_uri: URL_STRING, + helpers: { + logout: function (uid) { + do_check_eq(uid, 'foo'); + run_next_test(); + return Promise.resolve(); + } + } + }); + + channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext); +}); + +add_test(function test_can_link_account_message() { + let mockMessage = { + command: 'fxaccounts:can_link_account', + data: { email: 'testuser@testuser.com' } + }; + + let channel = new FxAccountsWebChannel({ + channel_id: WEBCHANNEL_ID, + content_uri: URL_STRING, + helpers: { + shouldAllowRelink: function (email) { + do_check_eq(email, 'testuser@testuser.com'); + run_next_test(); + } + } + }); + + channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext); +}); + +add_test(function test_sync_preferences_message() { + let mockMessage = { + command: 'fxaccounts:sync_preferences', + data: { entryPoint: 'fxa:verification_complete' } + }; + + let channel = new FxAccountsWebChannel({ + channel_id: WEBCHANNEL_ID, + content_uri: URL_STRING, + helpers: { + openSyncPreferences: function (browser, entryPoint) { + do_check_eq(entryPoint, 'fxa:verification_complete'); + do_check_eq(browser, mockSendingContext.browser); + run_next_test(); + } + } + }); + + channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext); +}); + +add_test(function test_unrecognized_message() { + let mockMessage = { + command: 'fxaccounts:unrecognized', + data: {} + }; + + let channel = new FxAccountsWebChannel({ + channel_id: WEBCHANNEL_ID, + content_uri: URL_STRING + }); + + // no error is expected. + channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext); + run_next_test(); +}); + + +add_test(function test_helpers_should_allow_relink_same_email() { + let helpers = new FxAccountsWebChannelHelpers(); + + helpers.setPreviousAccountNameHashPref('testuser@testuser.com'); + do_check_true(helpers.shouldAllowRelink('testuser@testuser.com')); + + run_next_test(); +}); + +add_test(function test_helpers_should_allow_relink_different_email() { + let helpers = new FxAccountsWebChannelHelpers(); + + helpers.setPreviousAccountNameHashPref('testuser@testuser.com'); + + helpers._promptForRelink = (acctName) => { + return acctName === 'allowed_to_relink@testuser.com'; + }; + + do_check_true(helpers.shouldAllowRelink('allowed_to_relink@testuser.com')); + do_check_false(helpers.shouldAllowRelink('not_allowed_to_relink@testuser.com')); + + run_next_test(); +}); + +add_task(function* test_helpers_login_without_customize_sync() { + let helpers = new FxAccountsWebChannelHelpers({ + fxAccounts: { + setSignedInUser: function(accountData) { + return new Promise(resolve => { + // ensure fxAccounts is informed of the new user being signed in. + do_check_eq(accountData.email, 'testuser@testuser.com'); + + // verifiedCanLinkAccount should be stripped in the data. + do_check_false('verifiedCanLinkAccount' in accountData); + + // the customizeSync pref should not update + do_check_false(helpers.getShowCustomizeSyncPref()); + + // previously signed in user preference is updated. + do_check_eq(helpers.getPreviousAccountNameHashPref(), helpers.sha256('testuser@testuser.com')); + + resolve(); + }); + } + } + }); + + // the show customize sync pref should stay the same + helpers.setShowCustomizeSyncPref(false); + + // ensure the previous account pref is overwritten. + helpers.setPreviousAccountNameHashPref('lastuser@testuser.com'); + + yield helpers.login({ + email: 'testuser@testuser.com', + verifiedCanLinkAccount: true, + customizeSync: false + }); +}); + +add_task(function* test_helpers_login_with_customize_sync() { + let helpers = new FxAccountsWebChannelHelpers({ + fxAccounts: { + setSignedInUser: function(accountData) { + return new Promise(resolve => { + // ensure fxAccounts is informed of the new user being signed in. + do_check_eq(accountData.email, 'testuser@testuser.com'); + + // customizeSync should be stripped in the data. + do_check_false('customizeSync' in accountData); + + // the customizeSync pref should not update + do_check_true(helpers.getShowCustomizeSyncPref()); + + resolve(); + }); + } + } + }); + + // the customize sync pref should be overwritten + helpers.setShowCustomizeSyncPref(false); + + yield helpers.login({ + email: 'testuser@testuser.com', + verifiedCanLinkAccount: true, + customizeSync: true + }); +}); + +add_task(function* test_helpers_login_with_customize_sync_and_declined_engines() { + let helpers = new FxAccountsWebChannelHelpers({ + fxAccounts: { + setSignedInUser: function(accountData) { + return new Promise(resolve => { + // ensure fxAccounts is informed of the new user being signed in. + do_check_eq(accountData.email, 'testuser@testuser.com'); + + // customizeSync should be stripped in the data. + do_check_false('customizeSync' in accountData); + do_check_false('declinedSyncEngines' in accountData); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.addons"), false); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.bookmarks"), true); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.history"), true); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.passwords"), true); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.prefs"), false); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.tabs"), true); + + // the customizeSync pref should be disabled + do_check_false(helpers.getShowCustomizeSyncPref()); + + resolve(); + }); + } + } + }); + + // the customize sync pref should be overwritten + helpers.setShowCustomizeSyncPref(true); + + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.addons"), true); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.bookmarks"), true); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.history"), true); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.passwords"), true); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.prefs"), true); + do_check_eq(Services.prefs.getBoolPref("services.sync.engine.tabs"), true); + yield helpers.login({ + email: 'testuser@testuser.com', + verifiedCanLinkAccount: true, + customizeSync: true, + declinedSyncEngines: ['addons', 'prefs'] + }); +}); + +add_test(function test_helpers_open_sync_preferences() { + let helpers = new FxAccountsWebChannelHelpers({ + fxAccounts: { + } + }); + + let mockBrowser = { + loadURI(uri) { + do_check_eq(uri, "about:preferences?entrypoint=fxa%3Averification_complete#sync"); + run_next_test(); + } + }; + + helpers.openSyncPreferences(mockBrowser, "fxa:verification_complete"); +}); + +add_task(function* test_helpers_change_password() { + let wasCalled = { + updateUserAccountData: false, + updateDeviceRegistration: false + }; + let helpers = new FxAccountsWebChannelHelpers({ + fxAccounts: { + updateUserAccountData(credentials) { + return new Promise(resolve => { + do_check_true(credentials.hasOwnProperty("email")); + do_check_true(credentials.hasOwnProperty("uid")); + do_check_true(credentials.hasOwnProperty("kA")); + do_check_true(credentials.hasOwnProperty("deviceId")); + do_check_null(credentials.deviceId); + // "foo" isn't a field known by storage, so should be dropped. + do_check_false(credentials.hasOwnProperty("foo")); + wasCalled.updateUserAccountData = true; + + resolve(); + }); + }, + + updateDeviceRegistration() { + do_check_eq(arguments.length, 0); + wasCalled.updateDeviceRegistration = true; + return Promise.resolve() + } + } + }); + yield helpers.changePassword({ email: "email", uid: "uid", kA: "kA", foo: "foo" }); + do_check_true(wasCalled.updateUserAccountData); + do_check_true(wasCalled.updateDeviceRegistration); +}); + +add_task(function* test_helpers_change_password_with_error() { + let wasCalled = { + updateUserAccountData: false, + updateDeviceRegistration: false + }; + let helpers = new FxAccountsWebChannelHelpers({ + fxAccounts: { + updateUserAccountData() { + wasCalled.updateUserAccountData = true; + return Promise.reject(); + }, + + updateDeviceRegistration() { + wasCalled.updateDeviceRegistration = true; + return Promise.resolve() + } + } + }); + try { + yield helpers.changePassword({}); + do_check_false('changePassword should have rejected'); + } catch (_) { + do_check_true(wasCalled.updateUserAccountData); + do_check_false(wasCalled.updateDeviceRegistration); + } +}); + +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; +} + +function validationHelper(params, expected) { + try { + new FxAccountsWebChannel(params); + } catch (e) { + if (typeof expected === 'string') { + return do_check_eq(e.toString(), expected); + } else { + return do_check_true(e.toString().match(expected)); + } + } + throw new Error("Validation helper error"); +} |