summaryrefslogtreecommitdiffstats
path: root/services/fxaccounts/tests/xpcshell/test_web_channel.js
diff options
context:
space:
mode:
Diffstat (limited to 'services/fxaccounts/tests/xpcshell/test_web_channel.js')
-rw-r--r--services/fxaccounts/tests/xpcshell/test_web_channel.js499
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");
+}