Родитель
65588f6f20
Коммит
ef9eb398f2
|
@ -0,0 +1,52 @@
|
|||
/* 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/. */
|
||||
|
||||
define((require, exports, module) => {
|
||||
'use strict';
|
||||
|
||||
const BaseGroupingRule = require('./base');
|
||||
|
||||
function isEmailForcedIntoTreatment (email) {
|
||||
return /@softvision\.(com|ro)$/.test(email) ||
|
||||
/@mozilla\.(com|org)$/.test(email);
|
||||
}
|
||||
|
||||
module.exports = class CadOnSigninGroupingRule extends BaseGroupingRule {
|
||||
constructor () {
|
||||
super();
|
||||
this.name = 'cadOnSignin';
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `subject` data to decide if the user should see CAD on signin.
|
||||
*
|
||||
* @param {Object} subject data used to decide
|
||||
* @returns {Any}
|
||||
*/
|
||||
choose (subject) {
|
||||
if (! this._areSubjectPrereqsMet(subject)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isEmailForcedIntoTreatment(subject.account.get('email'))) {
|
||||
return 'treatment';
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are the subject pre-requisites met?
|
||||
*
|
||||
* @param {Object} subject
|
||||
* @returns {Boolean}
|
||||
* @private
|
||||
*/
|
||||
_areSubjectPrereqsMet (subject) {
|
||||
return subject &&
|
||||
subject.account &&
|
||||
subject.account.get('email');
|
||||
}
|
||||
};
|
||||
});
|
|
@ -13,6 +13,7 @@ define((require, exports, module) => {
|
|||
|
||||
const ExperimentGroupingRules = [
|
||||
require('./communication-prefs'),
|
||||
require('./connect-another-device-on-signin'),
|
||||
require('./disabled-button-state'),
|
||||
require('./email-first'),
|
||||
require('./is-sampled-user'),
|
||||
|
|
|
@ -20,7 +20,7 @@ define((require, exports, module) => {
|
|||
* @returns {Any}
|
||||
*/
|
||||
choose (subject) {
|
||||
const EXPERIMENTS = ['disabledButtonState', 'signupPasswordConfirm', 'emailFirst'];
|
||||
const EXPERIMENTS = ['disabledButtonState', 'signupPasswordConfirm', 'emailFirst', 'cadOnSignin'];
|
||||
if (! subject || ! subject.uniqueUserId) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ define(function (require, exports, module) {
|
|||
|
||||
defaultCapabilities: _.extend({}, proto.defaultCapabilities, {
|
||||
browserTransitionsAfterEmailVerification: true,
|
||||
cadAfterSignInConfirmationPoll: true,
|
||||
cadAfterSignUpConfirmationPoll: true,
|
||||
chooseWhatToSyncCheckbox: false,
|
||||
chooseWhatToSyncWebV1: true,
|
||||
openWebmailButtonVisible: true
|
||||
|
|
|
@ -27,6 +27,7 @@ define(function (require, exports, module) {
|
|||
},
|
||||
|
||||
defaultCapabilities: _.extend({}, proto.defaultCapabilities, {
|
||||
cadAfterSignInConfirmationPoll: true,
|
||||
cadAfterSignUpConfirmationPoll: true,
|
||||
chooseWhatToSyncCheckbox: true,
|
||||
chooseWhatToSyncWebV1: false,
|
||||
|
|
|
@ -14,16 +14,20 @@ define(function (require, exports, module) {
|
|||
const _ = require('underscore');
|
||||
const BaseAuthenticationBroker = require('models/auth_brokers/base');
|
||||
const ConnectAnotherDeviceBehavior = require('views/behaviors/connect-another-device');
|
||||
const ConnectAnotherDeviceOnSigninBehavior = require('views/behaviors/connect-another-device-on-signin');
|
||||
const SyncEngines = require('models/sync-engines');
|
||||
|
||||
const proto = BaseAuthenticationBroker.prototype;
|
||||
|
||||
module.exports = BaseAuthenticationBroker.extend({
|
||||
defaultBehaviors: _.extend({}, proto.defaultBehaviors, {
|
||||
afterCompleteSignIn: new ConnectAnotherDeviceOnSigninBehavior(proto.defaultBehaviors.afterCompleteSignIn),
|
||||
afterCompleteSignUp: new ConnectAnotherDeviceBehavior(proto.defaultBehaviors.afterCompleteSignUp)
|
||||
}),
|
||||
|
||||
defaultCapabilities: _.extend({}, proto.defaultCapabilities, {
|
||||
// Can CAD be displayed after the signin confirmation poll?
|
||||
cadAfterSignInConfirmationPoll: false,
|
||||
// Can CAD be displayed after the signup confirmation poll?
|
||||
cadAfterSignUpConfirmationPoll: false
|
||||
}),
|
||||
|
@ -69,13 +73,35 @@ define(function (require, exports, module) {
|
|||
}
|
||||
},
|
||||
|
||||
afterSignInConfirmationPoll (account) {
|
||||
return proto.afterSignInConfirmationPoll.call(this, account)
|
||||
.then((defaultBehavior) => {
|
||||
if (this.hasCapability('cadAfterSignInConfirmationPoll')) {
|
||||
// This is a hack to allow us to differentiate between users
|
||||
// who see CAD in the signin and verification tabs. CAD
|
||||
// was added to the verification tab first, view names and view
|
||||
// events are all unprefixed. In the signin tab, we force add
|
||||
// the `signin` view name prefix so that events that contain
|
||||
// viewNames have `signin` view name prefix.
|
||||
//
|
||||
// e.g.:
|
||||
// screen.sms <- view the sms screen in the verification tab.
|
||||
// screen.signin.sms <- view the sms screen in the signin tab.
|
||||
this._metrics.setViewNamePrefix('signin');
|
||||
return new ConnectAnotherDeviceOnSigninBehavior(defaultBehavior);
|
||||
}
|
||||
|
||||
return defaultBehavior;
|
||||
});
|
||||
},
|
||||
|
||||
afterSignUpConfirmationPoll (account) {
|
||||
return proto.afterSignUpConfirmationPoll.call(this, account)
|
||||
.then((defaultBehavior) => {
|
||||
if (this.hasCapability('cadAfterSignUpConfirmationPoll')) {
|
||||
// This is a hack to allow us to differentiate between users
|
||||
// who see CAD in the signup and verification tabs. CAD
|
||||
// was added to the verifiation tab first, view names and view
|
||||
// was added to the verification tab first, view names and view
|
||||
// events are all unprefixed. In the signup tab, we force add
|
||||
// the `signup` view name prefix so that events that contain
|
||||
// viewNames have `signup` view name prefix.
|
||||
|
|
|
@ -4,13 +4,18 @@
|
|||
<div class="success success-authenticated visible">{{#t}}This Firefox is connected{{/t}}</div>
|
||||
{{/isSignedIn}}
|
||||
{{^isSignedIn}}
|
||||
<div class="success success-not-authenticated visible">{{#t}}Email verified{{/t}}</div>
|
||||
{{#isSignUp}}
|
||||
<div class="success success-not-authenticated visible">{{#t}}Email verified{{/t}}</div>
|
||||
{{/isSignUp}}
|
||||
{{#isSignIn}}
|
||||
<div class="success success-not-authenticated visible">{{#t}}Signin confirmed{{/t}}</div>
|
||||
{{/isSignIn}}
|
||||
{{/isSignedIn}}
|
||||
<section>
|
||||
<div class="graphic graphic-connect-another-device">{{#t}}Success{{/t}}</div>
|
||||
|
||||
{{#canSignIn}}
|
||||
<p>
|
||||
<p class="instructions">
|
||||
{{#t}}Sign in to this Firefox to complete set-up{{/t}}
|
||||
</p>
|
||||
|
||||
|
@ -25,36 +30,45 @@
|
|||
<!-- User verified in Fx for Android - they are using an old Fennec
|
||||
or are already signed in. Ignore old browsers, assume already signed in.
|
||||
Encourage installation on another device. -->
|
||||
<p id="connect-other-firefox-from-android">
|
||||
<p id="connect-other-firefox-from-android" class="instructions">
|
||||
{{#isSignIn}}
|
||||
{{#t}}Still adding devices?{{/t}}
|
||||
{{/isSignIn}}
|
||||
{{#t}}Sign in to Firefox on another device to complete set-up{{/t}}
|
||||
</p>
|
||||
{{/isFirefoxAndroid}}
|
||||
{{#isFirefoxDesktop}}
|
||||
<p id="install-mobile-firefox-desktop">
|
||||
<p id="install-mobile-firefox-desktop" class="instructions">
|
||||
{{#isSignIn}}
|
||||
{{#t}}Still adding devices?{{/t}}
|
||||
{{/isSignIn}}
|
||||
{{#t}}Sign in to Firefox on another device to complete set-up{{/t}}
|
||||
</p>
|
||||
{{/isFirefoxDesktop}}
|
||||
{{#isFirefoxIos}}
|
||||
<!-- user verifies in Fx for iOS, assume they are not signed in -->
|
||||
<p id="signin-fxios">
|
||||
<p id="signin-fxios" class="instructions">
|
||||
{{#t}}Open settings and select Sign in to Firefox to complete set-up{{/t}}
|
||||
</p>
|
||||
{{/isFirefoxIos}}
|
||||
{{#isOtherAndroid}}
|
||||
<!-- Another android browser, encourage Fx for Android installation -->
|
||||
<p id="install-mobile-firefox-android">
|
||||
<p id="install-mobile-firefox-android" class="instructions">
|
||||
{{#t}}Sign in to Firefox for Android to complete set-up{{/t}}
|
||||
</p>
|
||||
{{/isOtherAndroid}}
|
||||
{{#isOtherIos}}
|
||||
<!-- Safari or Chrome for iOS, encourage installation of Fx -->
|
||||
<p id="install-mobile-firefox-ios">
|
||||
<p id="install-mobile-firefox-ios" class="instructions">
|
||||
{{#t}}Sign in to Firefox for iOS to complete set-up{{/t}}
|
||||
</p>
|
||||
{{/isOtherIos}}
|
||||
{{#isOther}}
|
||||
<!-- probably some desktop browser -->
|
||||
<p id="install-mobile-firefox-other">
|
||||
<p id="install-mobile-firefox-other" class="instructions">
|
||||
{{#isSignIn}}
|
||||
{{#t}}Still adding devices?{{/t}}
|
||||
{{/isSignIn}}
|
||||
{{#t}}Sign in to Firefox on another device to complete set-up{{/t}}
|
||||
</p>
|
||||
{{/isOther}}
|
||||
|
@ -64,7 +78,7 @@
|
|||
{{/isFirefoxIos}}
|
||||
{{/canSignIn}}
|
||||
<div class="links">
|
||||
<a data-flow-event="link.why" href="/connect_another_device/why">{{#t}}Why is this required?{{/t}}</a>
|
||||
<a data-flow-event="link.why" href="/connect_another_device/why">{{#t}}Why is more than one device required?{{/t}}</a>
|
||||
</div>
|
||||
<aside class="child-view"></aside>
|
||||
</section>
|
||||
|
|
|
@ -6,7 +6,12 @@
|
|||
<section>
|
||||
<div class="graphic graphic-connect-another-device">{{#t}}Success{{/t}}</div>
|
||||
|
||||
<p>{{#t}}Send Firefox directly to your smartphone and sign in to complete set-up{{/t}}</p>
|
||||
<p class="instructions">
|
||||
{{#isSignIn}}
|
||||
{{#t}}Still adding devices?{{/t}}
|
||||
{{/isSignIn}}
|
||||
{{#t}}Send Firefox directly to your smartphone and sign in to complete set-up{{/t}}
|
||||
</p>
|
||||
|
||||
<form novalidate>
|
||||
<div class="input-row sms-row">
|
||||
|
@ -20,7 +25,7 @@
|
|||
{{#unsafeTranslate}}SMS service only available in certain countries. SMS & data rates may apply. The intended recipient of the email or SMS must have consented. <a %(escapedLearnMoreAttributes)s>Learn more</a>{{/unsafeTranslate}}
|
||||
</div>
|
||||
<div class="links">
|
||||
<a href="/sms/why" data-flow-event="link.why" class="left">{{#t}}Why is this required?{{/t}}</a>
|
||||
<a href="/sms/why" data-flow-event="link.why" class="left">{{#t}}Why is more than one device required?{{/t}}</a>
|
||||
<a id="maybe-later" href="/connect_another_device" data-flow-event="link.maybe_later" class="right">{{#t}}Maybe later{{/t}}</a>
|
||||
</div>
|
||||
<aside class="child-view"></aside>
|
||||
|
|
|
@ -810,6 +810,7 @@ define(function (require, exports, module) {
|
|||
server: true,
|
||||
url
|
||||
});
|
||||
this._hasNavigated = true;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -822,6 +823,15 @@ define(function (require, exports, module) {
|
|||
this.navigate(url, nextViewData, { replace: true, trigger: true });
|
||||
},
|
||||
|
||||
/**
|
||||
* Has the view already navigated?
|
||||
*
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
hasNavigated () {
|
||||
return !! this._hasNavigated;
|
||||
},
|
||||
|
||||
/**
|
||||
* Focus the element with the [autofocus] attribute, if not a touch device.
|
||||
* Focusing an element on a touch device causes the virtual keyboard to
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/* 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/. */
|
||||
|
||||
/**
|
||||
* A behavior that sends eligible users to the appropriate
|
||||
* connect-another-device screen. If ineligible, fallback
|
||||
* to `defaultBehavior`.
|
||||
*
|
||||
* Should only be used for signin flows, a side effect
|
||||
* is to create/initialize CAD on signin experiments.
|
||||
*
|
||||
* Requires the view to mixin the ConnectAnotherDeviceMixin
|
||||
*/
|
||||
|
||||
define((require, exports, module) => {
|
||||
'use strict';
|
||||
|
||||
const p = require('lib/promise');
|
||||
|
||||
/**
|
||||
* Create a ConnectAnotherDeviceOnSignin behavior.
|
||||
*
|
||||
* @param {Object} defaultBehavior - behavior to invoke if ineligible
|
||||
* for ConnectAnotherDevice
|
||||
* @returns {Function} behavior
|
||||
*/
|
||||
module.exports = function (defaultBehavior) {
|
||||
const behavior = function (view, account) {
|
||||
return p().then(() => {
|
||||
if (view.isEligibleForConnectAnotherDeviceOnSignin(account)) {
|
||||
return view.navigateToConnectAnotherDeviceOnSigninScreen(account);
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
// if the user is not eligible for CAD, or if the .navigateToConnect*
|
||||
// function did not navigate, then return the default behavior.
|
||||
if (view.hasNavigated()) {
|
||||
// Cause the invokeBrokerMethod chain to stop, the screen
|
||||
// has already redirected.
|
||||
return p.defer().promise;
|
||||
}
|
||||
return defaultBehavior;
|
||||
});
|
||||
};
|
||||
|
||||
behavior.type = 'connect-another-device-on-signin';
|
||||
|
||||
return behavior;
|
||||
};
|
||||
});
|
|
@ -7,6 +7,8 @@
|
|||
* connect-another-device screen. If ineligible, fallback
|
||||
* to `defaultBehavior`.
|
||||
*
|
||||
* Do not use for a signin flow, instead use "connect-another-device-on-signin".
|
||||
*
|
||||
* Requires the view to mixin the ConnectAnotherDeviceMixin
|
||||
*/
|
||||
|
||||
|
@ -24,14 +26,21 @@ define((require, exports, module) => {
|
|||
*/
|
||||
module.exports = function (defaultBehavior) {
|
||||
const behavior = function (view, account) {
|
||||
if (view.isEligibleForConnectAnotherDevice(account)) {
|
||||
view.navigateToConnectAnotherDeviceScreen(account);
|
||||
// Cause the invokeBrokerMethod chain to stop, the screen
|
||||
// has already redirected.
|
||||
return p.defer().promise;
|
||||
}
|
||||
|
||||
return defaultBehavior;
|
||||
return p().then(() => {
|
||||
if (view.isEligibleForConnectAnotherDevice(account)) {
|
||||
return view.navigateToConnectAnotherDeviceScreen(account);
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
// if the user is not eligible for CAD, or if the .navigateToConnect*
|
||||
// function did not navigate, then return the default behavior.
|
||||
if (view.hasNavigated()) {
|
||||
// Cause the invokeBrokerMethod chain to stop, the screen
|
||||
// has already redirected.
|
||||
return p.defer().promise;
|
||||
}
|
||||
return defaultBehavior;
|
||||
});
|
||||
};
|
||||
|
||||
behavior.type = 'connect-another-device';
|
||||
|
|
|
@ -21,6 +21,7 @@ define(function (require, exports, module) {
|
|||
const SyncAuthMixin = require('views/mixins/sync-auth-mixin');
|
||||
const Template = require('stache!templates/connect_another_device');
|
||||
const UserAgentMixin = require('lib/user-agent-mixin');
|
||||
const VerificationReasonMixin = require('views/mixins/verification-reason-mixin');
|
||||
|
||||
class ConnectAnotherDeviceView extends FormView {
|
||||
initialize (options = {}) {
|
||||
|
@ -137,6 +138,8 @@ define(function (require, exports, module) {
|
|||
const isOtherAndroid = isAndroid && ! isFirefoxAndroid;
|
||||
const isOtherIos = isIos && ! isFirefoxIos;
|
||||
const isOther = ! isAndroid && ! isIos && ! isFirefoxDesktop;
|
||||
const isSignIn = this.isSignIn();
|
||||
const isSignUp = this.isSignUp();
|
||||
|
||||
context.set({
|
||||
canSignIn,
|
||||
|
@ -148,6 +151,8 @@ define(function (require, exports, module) {
|
|||
isOther,
|
||||
isOtherAndroid,
|
||||
isOtherIos,
|
||||
isSignIn,
|
||||
isSignUp,
|
||||
isSignedIn
|
||||
});
|
||||
}
|
||||
|
@ -203,7 +208,8 @@ define(function (require, exports, module) {
|
|||
service: SYNC_SERVICE
|
||||
}),
|
||||
SyncAuthMixin,
|
||||
UserAgentMixin
|
||||
UserAgentMixin,
|
||||
VerificationReasonMixin
|
||||
);
|
||||
|
||||
module.exports = ConnectAnotherDeviceView;
|
||||
|
|
|
@ -35,7 +35,6 @@ define((require, exports, module) => {
|
|||
const REASON_NOT_IN_EXPERIMENT = 'sms.ineligible.not_in_experiment';
|
||||
const REASON_NO_SESSION = 'sms.ineligible.no_session';
|
||||
const REASON_OTHER_USER_SIGNED_IN = 'sms.ineligible.other_user_signed_in';
|
||||
const REASON_SIGNIN = 'sms.ineligible.signin';
|
||||
const REASON_UNSUPPORTED_COUNTRY = 'sms.ineligible.unsupported_country';
|
||||
const REASON_XHR_ERROR = 'sms.ineligible.xhr_error';
|
||||
|
||||
|
@ -46,6 +45,45 @@ define((require, exports, module) => {
|
|||
VerificationReasonMixin
|
||||
],
|
||||
|
||||
/**
|
||||
* Is the user eligible for the CAD on signin?
|
||||
*
|
||||
* @param {any} account
|
||||
* @returns {Booelean}
|
||||
*/
|
||||
isEligibleForConnectAnotherDeviceOnSignin (account) {
|
||||
const isEligibleForCadOnSignin = !! this.getExperimentGroup('cadOnSignin', { account });
|
||||
|
||||
return this.isSignIn() &&
|
||||
this.isEligibleForConnectAnotherDevice(account) &&
|
||||
isEligibleForCadOnSignin;
|
||||
},
|
||||
|
||||
navigateToConnectAnotherDeviceOnSigninScreen (account) {
|
||||
if (! this.isEligibleForConnectAnotherDeviceOnSignin(account)) {
|
||||
// this shouldn't happen IRL.
|
||||
return p.reject(new Error('navigateToConnectAnotherDeviceOnSigninScreen can only be called if user is eligible to connect another device'));
|
||||
}
|
||||
|
||||
return p().then(() => {
|
||||
// Initialize the flow metrics so any flow events are logged.
|
||||
// The flow-events-mixin, even if it were mixed in, does this in
|
||||
// `afterRender` whereas this method can be called in `beforeRender`
|
||||
this.notifier.trigger('flow.initialize');
|
||||
const group = this.getExperimentGroup('cadOnSignin', { account });
|
||||
|
||||
// Note, the cadOnSignin prefix is to help us measure in DataDog.
|
||||
// Metrics sent to DataDog can have one or more exp_group tags,
|
||||
// the prefix allows us to differentiate between results from
|
||||
// the `sendSms` experiment which uses the same group names.
|
||||
this.createExperiment('sendSms', `cadOnSignin.${group}`);
|
||||
|
||||
if (group === 'treatment') {
|
||||
return this.navigateToConnectAnotherDeviceScreen(account);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Is `account` eligible for connect another device?
|
||||
*
|
||||
|
@ -53,12 +91,9 @@ define((require, exports, module) => {
|
|||
* @returns {Boolean}
|
||||
*/
|
||||
isEligibleForConnectAnotherDevice (account) {
|
||||
// Only show to users who are signing up, until we have better text for
|
||||
// users who are signing in.
|
||||
return this.isSignUp() &&
|
||||
// If a user is already signed in to Sync which is different to the
|
||||
// user that just verified, show them the old "Account verified!" screen.
|
||||
! this.user.isAnotherAccountSignedIn(account);
|
||||
// If a user is already signed in to Sync which is different to the
|
||||
// user that just verified, show them the old "Account verified!" screen.
|
||||
return ! this.user.isAnotherAccountSignedIn(account);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -83,6 +118,7 @@ define((require, exports, module) => {
|
|||
|
||||
return this._isEligibleForSms(account)
|
||||
.then(({ ok, country }) => {
|
||||
const type = this.model.get('type');
|
||||
if (ok) {
|
||||
// User is eligible for SMS experiment, now bucket
|
||||
// users into treatment and control groups.
|
||||
|
@ -91,13 +127,13 @@ define((require, exports, module) => {
|
|||
|
||||
if (group === 'control') {
|
||||
this.logFlowEvent(REASON_CONTROL_GROUP);
|
||||
this.navigate('connect_another_device', { account });
|
||||
this.navigate('connect_another_device', { account, type });
|
||||
} else {
|
||||
// all non-control groups go to the sms page.
|
||||
this.navigate('sms', { account, country });
|
||||
this.navigate('sms', { account, country, type });
|
||||
}
|
||||
} else {
|
||||
this.navigate('connect_another_device', { account });
|
||||
this.navigate('connect_another_device', { account, type });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -134,9 +170,7 @@ define((require, exports, module) => {
|
|||
_areSmsRequirementsMet (account) {
|
||||
let reason;
|
||||
|
||||
if (! this.isSignUp()) {
|
||||
reason = REASON_SIGNIN;
|
||||
} else if (this.getUserAgent().isAndroid()) {
|
||||
if (this.getUserAgent().isAndroid()) {
|
||||
// If already on a mobile device, doesn't make sense to send an SMS.
|
||||
reason = REASON_ANDROID;
|
||||
} else if (this.getUserAgent().isIos()) {
|
||||
|
|
|
@ -24,6 +24,7 @@ define(function (require, exports, module) {
|
|||
const SmsErrors = require('lib/sms-errors');
|
||||
const SmsMixin = require('views/mixins/sms-mixin');
|
||||
const Template = require('stache!templates/sms_send');
|
||||
const VerificationReasonMixin = require('views/mixins/verification-reason-mixin');
|
||||
|
||||
class SmsSendView extends FormView {
|
||||
initialize (options) {
|
||||
|
@ -61,9 +62,12 @@ define(function (require, exports, module) {
|
|||
phoneNumber = prefix;
|
||||
}
|
||||
|
||||
const isSignIn = this.isSignIn();
|
||||
|
||||
context.set({
|
||||
country,
|
||||
escapedLearnMoreAttributes,
|
||||
isSignIn,
|
||||
phoneNumber,
|
||||
});
|
||||
}
|
||||
|
@ -178,7 +182,8 @@ define(function (require, exports, module) {
|
|||
service: SYNC_SERVICE
|
||||
}),
|
||||
PulseGraphicMixin,
|
||||
SmsMixin
|
||||
SmsMixin,
|
||||
VerificationReasonMixin
|
||||
);
|
||||
|
||||
module.exports = SmsSendView;
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/* 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/. */
|
||||
|
||||
define(function (require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
const { assert } = require('chai');
|
||||
const Account = require('models/account');
|
||||
const Experiment = require('lib/experiments/grouping-rules/connect-another-device-on-signin');
|
||||
|
||||
describe('lib/experiments/grouping-rules/connect-another-device-on-signin', () => {
|
||||
let account;
|
||||
let experiment;
|
||||
|
||||
|
||||
before(() => {
|
||||
account = new Account();
|
||||
experiment = new Experiment();
|
||||
});
|
||||
|
||||
describe('choose', () => {
|
||||
it('returns false if no subject, or subject.account, or subject.account.email', () => {
|
||||
assert.isFalse(experiment.choose());
|
||||
assert.isFalse(experiment.choose({}));
|
||||
assert.isFalse(experiment.choose({ account: new Account() }));
|
||||
});
|
||||
|
||||
it('returns true for test email addresses', () => {
|
||||
account.set('email', 'testuser@testuser.com');
|
||||
assert.isFalse(experiment.choose({ account }));
|
||||
|
||||
account.set('email', 'testuser@softvision.com');
|
||||
assert.equal(experiment.choose({ account }), 'treatment');
|
||||
account.set('email', 'testuser@softvision.ro');
|
||||
assert.equal(experiment.choose({ account }), 'treatment');
|
||||
account.set('email', 'testuser@mozilla.com');
|
||||
assert.equal(experiment.choose({ account }), 'treatment');
|
||||
account.set('email', 'testuser@mozilla.org');
|
||||
assert.equal(experiment.choose({ account }), 'treatment');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -24,15 +24,6 @@ define(function (require, exports, module) {
|
|||
assert.isFalse(experiment.choose({}));
|
||||
});
|
||||
|
||||
it('returns experiment if forceExperiment', () => {
|
||||
assert.equal(experiment.choose({
|
||||
account,
|
||||
forceExperiment: 'disabledButtonState',
|
||||
forceExperimentGroup: 'control',
|
||||
uniqueUserId: 'user-id'
|
||||
}), 'disabledButtonState');
|
||||
});
|
||||
|
||||
it('returns chooses some group ', () => {
|
||||
assert.ok(experiment.choose({
|
||||
account,
|
||||
|
|
|
@ -6,6 +6,7 @@ define((require, exports, module) => {
|
|||
'use strict';
|
||||
|
||||
const { assert } = require('chai');
|
||||
const Account = require('models/account');
|
||||
const FxSyncAuthenticationBroker = require('models/auth_brokers/fx-sync');
|
||||
const Metrics = require('lib/metrics');
|
||||
const p = require('lib/promise');
|
||||
|
@ -45,7 +46,7 @@ define((require, exports, module) => {
|
|||
}
|
||||
|
||||
beforeEach(() => {
|
||||
account = {};
|
||||
account = new Account();
|
||||
metrics = new Metrics();
|
||||
relier = new Relier();
|
||||
windowMock = new WindowMock();
|
||||
|
@ -141,15 +142,50 @@ define((require, exports, module) => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('broker does not have `cadAfterSignUpConfirmationPoll` capability', () => {
|
||||
it('resolves to the default behavior', () => {
|
||||
sinon.spy(metrics, 'setViewNamePrefix');
|
||||
describe('afterSignInConfirmationPoll', () => {
|
||||
describe('broker has `cadAfterSignInConfirmationPoll` capability', () => {
|
||||
it('sets the metrics viewName prefix, resolves to a `ConnectAnotherDeviceBehavior`', () => {
|
||||
broker.setCapability('cadAfterSignInConfirmationPoll', true);
|
||||
sinon.spy(metrics, 'setViewNamePrefix');
|
||||
|
||||
return broker.afterSignUpConfirmationPoll(account)
|
||||
return broker.afterSignInConfirmationPoll(account)
|
||||
.then((behavior) => {
|
||||
assert.equal(behavior.type, 'connect-another-device-on-signin');
|
||||
|
||||
assert.isTrue(metrics.setViewNamePrefix.calledOnce);
|
||||
assert.isTrue(metrics.setViewNamePrefix.calledWith('signin'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('broker does not have `cadAfterSignInConfirmationPoll` capability', () => {
|
||||
it('resolves to the default behavior', () => {
|
||||
sinon.spy(metrics, 'setViewNamePrefix');
|
||||
|
||||
return broker.afterSignInConfirmationPoll(account)
|
||||
.then((behavior) => {
|
||||
assert.equal(behavior.type, broker.getBehavior('afterSignInConfirmationPoll').type);
|
||||
|
||||
assert.isFalse(metrics.setViewNamePrefix.called);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('afterCompleteSignUp', () => {
|
||||
it('returns a ConnectAnotherDeviceBehavior', () => {
|
||||
return broker.afterCompleteSignUp(account)
|
||||
.then((behavior) => {
|
||||
assert.equal(behavior.type, broker.getBehavior('afterSignUpConfirmationPoll').type);
|
||||
assert.equal(behavior.type, 'connect-another-device');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
assert.isFalse(metrics.setViewNamePrefix.called);
|
||||
describe('afterCompleteSignIn', () => {
|
||||
it('returns a ConnectAnotherDeviceBehavior', () => {
|
||||
return broker.afterCompleteSignIn(account)
|
||||
.then((behavior) => {
|
||||
assert.equal(behavior.type, 'connect-another-device-on-signin');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/* 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/. */
|
||||
|
||||
define((require, exports, module) => {
|
||||
'use strict';
|
||||
|
||||
const { assert } = require('chai');
|
||||
const ConnectAnotherDeviceOnSigninBehavior = require('views/behaviors/connect-another-device-on-signin');
|
||||
const NullBehavior = require('views/behaviors/null');
|
||||
const sinon = require('sinon');
|
||||
|
||||
describe('views/behaviors/connect-another-device-on-signin', () => {
|
||||
let account;
|
||||
let cadOnSigninBehavior;
|
||||
let defaultBehavior;
|
||||
|
||||
before(() => {
|
||||
account = {};
|
||||
defaultBehavior = new NullBehavior();
|
||||
cadOnSigninBehavior = new ConnectAnotherDeviceOnSigninBehavior(defaultBehavior);
|
||||
});
|
||||
|
||||
describe('eligible for CAD', () => {
|
||||
it('delegates to `view.navigateToConnectAnotherDeviceOnSigninScreen`', () => {
|
||||
const view = {
|
||||
hasNavigated: sinon.spy(() => false),
|
||||
isEligibleForConnectAnotherDeviceOnSignin: sinon.spy(() => true),
|
||||
isSignIn: sinon.spy(() => true),
|
||||
navigateToConnectAnotherDeviceOnSigninScreen: sinon.spy()
|
||||
};
|
||||
|
||||
return cadOnSigninBehavior(view, account)
|
||||
.then((behavior) => {
|
||||
assert.strictEqual(behavior, defaultBehavior);
|
||||
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDeviceOnSignin.calledOnce);
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDeviceOnSignin.calledWith(account));
|
||||
|
||||
assert.isTrue(view.navigateToConnectAnotherDeviceOnSigninScreen.calledOnce);
|
||||
assert.isTrue(view.navigateToConnectAnotherDeviceOnSigninScreen.calledWith(account));
|
||||
|
||||
assert.isTrue(view.hasNavigated.calledOnce);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ineligible for CAD', () => {
|
||||
it('invokes the defaultBehavior', () => {
|
||||
const view = {
|
||||
hasNavigated: sinon.spy(() => false),
|
||||
isEligibleForConnectAnotherDeviceOnSignin: sinon.spy(() => false),
|
||||
isSignIn: sinon.spy(() => true),
|
||||
navigateToConnectAnotherDeviceOnSigninScreen: sinon.spy()
|
||||
};
|
||||
|
||||
return cadOnSigninBehavior(view, account)
|
||||
.then((behavior) => {
|
||||
assert.strictEqual(behavior, defaultBehavior);
|
||||
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDeviceOnSignin.calledOnce);
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDeviceOnSignin.calledWith(account));
|
||||
|
||||
assert.isFalse(view.navigateToConnectAnotherDeviceOnSigninScreen.called);
|
||||
|
||||
assert.isTrue(view.hasNavigated.calledOnce);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -24,36 +24,47 @@ define((require, exports, module) => {
|
|||
describe('eligible for CAD', () => {
|
||||
it('delegates to `view.navigateToConnectAnotherDeviceScreen`', () => {
|
||||
const view = {
|
||||
hasNavigated: sinon.spy(() => false),
|
||||
isEligibleForConnectAnotherDevice: sinon.spy(() => true),
|
||||
isSignIn: sinon.spy(() => false),
|
||||
navigateToConnectAnotherDeviceScreen: sinon.spy()
|
||||
};
|
||||
|
||||
const promise = cadBehavior(view, account);
|
||||
assert.ok(promise);
|
||||
assert.isFunction(promise.then);
|
||||
return cadBehavior(view, account)
|
||||
.then((behavior) => {
|
||||
assert.strictEqual(behavior, defaultBehavior);
|
||||
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice.calledOnce);
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice.calledWith(account));
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice.calledOnce);
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice.calledWith(account));
|
||||
|
||||
assert.isTrue(view.navigateToConnectAnotherDeviceScreen.calledOnce);
|
||||
assert.isTrue(view.navigateToConnectAnotherDeviceScreen.calledWith(account));
|
||||
assert.isTrue(view.navigateToConnectAnotherDeviceScreen.calledOnce);
|
||||
assert.isTrue(view.navigateToConnectAnotherDeviceScreen.calledWith(account));
|
||||
|
||||
assert.isTrue(view.hasNavigated.calledOnce);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ineligible for CAD', () => {
|
||||
it('invokes the defaultBehavior', () => {
|
||||
const view = {
|
||||
hasNavigated: sinon.spy(() => false),
|
||||
isEligibleForConnectAnotherDevice: sinon.spy(() => false),
|
||||
isSignIn: sinon.spy(() => false),
|
||||
navigateToConnectAnotherDeviceScreen: sinon.spy()
|
||||
};
|
||||
|
||||
const behavior = cadBehavior(view, account);
|
||||
return cadBehavior(view, account)
|
||||
.then((behavior) => {
|
||||
assert.strictEqual(behavior, defaultBehavior);
|
||||
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice.calledOnce);
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice.calledWith(account));
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice.calledOnce);
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice.calledWith(account));
|
||||
|
||||
assert.isFalse(view.navigateToConnectAnotherDeviceScreen.called);
|
||||
assert.strictEqual(behavior, defaultBehavior);
|
||||
assert.isFalse(view.navigateToConnectAnotherDeviceScreen.called);
|
||||
|
||||
assert.isTrue(view.hasNavigated.calledOnce);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@ define(function (require, exports, module) {
|
|||
|
||||
const { assert } = require('chai');
|
||||
const AuthErrors = require('lib/auth-errors');
|
||||
const Backbone = require('backbone');
|
||||
const BaseView = require('views/base');
|
||||
const ConnectAnotherDeviceMixin = require('views/mixins/connect-another-device-mixin');
|
||||
const Constants = require('lib/constants');
|
||||
|
@ -39,17 +40,20 @@ define(function (require, exports, module) {
|
|||
|
||||
describe('views/mixins/connect-another-device-mixin', () => {
|
||||
let account;
|
||||
let model;
|
||||
let notifier;
|
||||
let relier;
|
||||
let user;
|
||||
let view;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new Backbone.Model({ type: 'signin' });
|
||||
notifier = new Notifier();
|
||||
relier = new Relier();
|
||||
user = new User();
|
||||
|
||||
view = new View({
|
||||
model,
|
||||
notifier,
|
||||
relier,
|
||||
user
|
||||
|
@ -64,64 +68,91 @@ define(function (require, exports, module) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('isEligibleForConnectAnotherDeviceOnSignin', () => {
|
||||
it('returns true if signing in, if eligible for CAD, and is part of the experiment', () => {
|
||||
sinon.stub(view, 'isSignIn').callsFake(() => true);
|
||||
sinon.stub(view, 'isEligibleForConnectAnotherDevice').callsFake(() => true);
|
||||
sinon.stub(view, 'getExperimentGroup').callsFake(() => 'treatment');
|
||||
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDeviceOnSignin(account));
|
||||
});
|
||||
|
||||
it('returns false if signing up, if eligible for CAD, and is part of the experiment', () => {
|
||||
sinon.stub(view, 'isSignIn').callsFake(() => false);
|
||||
sinon.stub(view, 'isEligibleForConnectAnotherDevice').callsFake(() => true);
|
||||
sinon.stub(view, 'getExperimentGroup').callsFake(() => 'treatment');
|
||||
|
||||
assert.isFalse(view.isEligibleForConnectAnotherDeviceOnSignin(account));
|
||||
});
|
||||
|
||||
it('returns false if signing in, not eligible for CAD, and is part of the experiment', () => {
|
||||
sinon.stub(view, 'isSignIn').callsFake(() => true);
|
||||
sinon.stub(view, 'isEligibleForConnectAnotherDevice').callsFake(() => false);
|
||||
sinon.stub(view, 'getExperimentGroup').callsFake(() => 'treatment');
|
||||
|
||||
assert.isFalse(view.isEligibleForConnectAnotherDeviceOnSignin(account));
|
||||
});
|
||||
|
||||
it('returns false if signing in, not eligible for CAD, and is part of the experiment', () => {
|
||||
sinon.stub(view, 'isSignIn').callsFake(() => true);
|
||||
sinon.stub(view, 'isEligibleForConnectAnotherDevice').callsFake(() => true);
|
||||
sinon.stub(view, 'getExperimentGroup').callsFake(() => false);
|
||||
|
||||
assert.isFalse(view.isEligibleForConnectAnotherDeviceOnSignin(account));
|
||||
});
|
||||
});
|
||||
|
||||
describe('navigateToConnectAnotherDeviceOnSigninScreen', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(view, 'isEligibleForConnectAnotherDeviceOnSignin').callsFake(() => true);
|
||||
sinon.stub(view, 'navigateToConnectAnotherDeviceScreen').callsFake(() => p());
|
||||
sinon.spy(view, 'createExperiment');
|
||||
sinon.spy(notifier, 'trigger');
|
||||
});
|
||||
|
||||
describe('user is part of treatment', () => {
|
||||
it('sets up experiment, delegates to `navigateToConnectAnotherDeviceScreen`', () => {
|
||||
sinon.stub(view, 'getExperimentGroup').callsFake(() => 'treatment');
|
||||
|
||||
return view.navigateToConnectAnotherDeviceOnSigninScreen(account)
|
||||
.then(() => {
|
||||
assert.isTrue(notifier.trigger.calledWith('flow.initialize'));
|
||||
|
||||
assert.isTrue(view.createExperiment.calledOnce);
|
||||
assert.isTrue(view.createExperiment.calledWith('sendSms', 'cadOnSignin.treatment'));
|
||||
|
||||
assert.isTrue(view.navigateToConnectAnotherDeviceScreen.calledOnce);
|
||||
assert.isTrue(view.navigateToConnectAnotherDeviceScreen.calledWith(account));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('user is part of control', () => {
|
||||
it('sets up experiment, does nothing more', () => {
|
||||
sinon.stub(view, 'getExperimentGroup').callsFake(() => 'control');
|
||||
|
||||
return view.navigateToConnectAnotherDeviceOnSigninScreen(account)
|
||||
.then(() => {
|
||||
assert.isTrue(notifier.trigger.calledWith('flow.initialize'));
|
||||
|
||||
assert.isTrue(view.createExperiment.calledOnce);
|
||||
assert.isTrue(view.createExperiment.calledWith('sendSms', 'cadOnSignin.control'));
|
||||
|
||||
assert.isFalse(view.navigateToConnectAnotherDeviceScreen.called);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isEligibleForConnectAnotherDevice', () => {
|
||||
describe('user is completing sign-in', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(user, 'getSignedInAccount').callsFake(() => {
|
||||
return {
|
||||
isDefault: () => true
|
||||
};
|
||||
});
|
||||
sinon.stub(view, 'isSignUp').callsFake(() => false);
|
||||
});
|
||||
|
||||
it('returns `false`', () => {
|
||||
assert.isFalse(view.isEligibleForConnectAnotherDevice(account));
|
||||
});
|
||||
it('returns true for signup if a different user is not signed in', () => {
|
||||
sinon.stub(user, 'isAnotherAccountSignedIn').callsFake(() => false);
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice(account));
|
||||
});
|
||||
|
||||
describe('no user signed in', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(user, 'getSignedInAccount').callsFake(() => {
|
||||
return {
|
||||
isDefault: () => true
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
it('returns `true`', () => {
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice(account));
|
||||
});
|
||||
});
|
||||
|
||||
describe('different user signed in', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(user, 'getSignedInAccount').callsFake(() => {
|
||||
return {
|
||||
isDefault: () => false
|
||||
};
|
||||
});
|
||||
sinon.stub(user, 'isSignedInAccount').callsFake(() => false);
|
||||
});
|
||||
|
||||
it('returns `false`', () => {
|
||||
assert.isFalse(view.isEligibleForConnectAnotherDevice(account));
|
||||
});
|
||||
});
|
||||
|
||||
describe('same user signed in', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(user, 'getSignedInAccount').callsFake(() => {
|
||||
return {
|
||||
isDefault: () => false
|
||||
};
|
||||
});
|
||||
sinon.stub(user, 'isSignedInAccount').callsFake(() => true);
|
||||
});
|
||||
|
||||
it('returns `true`', () => {
|
||||
assert.isTrue(view.isEligibleForConnectAnotherDevice(account));
|
||||
});
|
||||
it('returns false for signup if different user signed in', () => {
|
||||
sinon.stub(user, 'isAnotherAccountSignedIn').callsFake(() => true);
|
||||
assert.isFalse(view.isEligibleForConnectAnotherDevice(account));
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -242,26 +273,6 @@ define(function (require, exports, module) {
|
|||
});
|
||||
|
||||
describe('_areSmsRequirementsMet', () => {
|
||||
describe('user is signing in', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(view, 'isSignUp').callsFake(() => false);
|
||||
sinon.stub(view, 'isInExperiment').callsFake(() => true);
|
||||
sinon.stub(view, 'getUserAgent').callsFake(() => {
|
||||
return {
|
||||
isAndroid: () => false,
|
||||
isIos: () => false
|
||||
};
|
||||
});
|
||||
sinon.stub(user, 'isAnotherAccountSignedIn').callsFake(() => false);
|
||||
});
|
||||
|
||||
it('returns `false', () => {
|
||||
assert.isFalse(view._areSmsRequirementsMet(account));
|
||||
assert.isTrue(view.logFlowEvent.calledOnce);
|
||||
assert.isTrue(view.logFlowEvent.calledWith('sms.ineligible.signin'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('user is on Android', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(view, 'isSignUp').callsFake(() => true);
|
||||
|
@ -476,7 +487,7 @@ define(function (require, exports, module) {
|
|||
assert.isTrue(notifier.trigger.calledWith('flow.initialize'));
|
||||
|
||||
assert.isTrue(view.navigate.calledOnce);
|
||||
assert.isTrue(view.navigate.calledWith('connect_another_device', { account }));
|
||||
assert.isTrue(view.navigate.calledWith('connect_another_device', { account, type: 'signin' }));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -495,7 +506,7 @@ define(function (require, exports, module) {
|
|||
assert.isTrue(view.createExperiment.calledWith('sendSms', 'treatment'));
|
||||
|
||||
assert.isTrue(view.navigate.calledOnce);
|
||||
assert.isTrue(view.navigate.calledWith('sms', { account, country: 'GB' }));
|
||||
assert.isTrue(view.navigate.calledWith('sms', { account, country: 'GB', type: 'signin' }));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -509,7 +520,7 @@ define(function (require, exports, module) {
|
|||
assert.isTrue(view.createExperiment.calledWith('sendSms', 'control'));
|
||||
|
||||
assert.isTrue(view.navigate.calledOnce);
|
||||
assert.isTrue(view.navigate.calledWith('connect_another_device', { account }));
|
||||
assert.isTrue(view.navigate.calledWith('connect_another_device', { account, type: 'signin' }));
|
||||
|
||||
assert.isTrue(view.logFlowEvent.calledOnce);
|
||||
assert.isTrue(view.logFlowEvent.calledWith('sms.ineligible.control_group'));
|
||||
|
|
|
@ -133,6 +133,14 @@
|
|||
assert.lengthOf(view.$('.marketing-link'), 2);
|
||||
});
|
||||
});
|
||||
|
||||
it('for signin, renders extra text', () => {
|
||||
sinon.stub(view, 'isSignIn').callsFake(() => true);
|
||||
return view.render()
|
||||
.then(() => {
|
||||
assert.include(view.$('.instructions').text().toLowerCase(), 'still adding devices');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('submit', () => {
|
||||
|
|
|
@ -38,6 +38,7 @@ function (Translator, Session) {
|
|||
'../tests/spec/lib/experiments/base',
|
||||
'../tests/spec/lib/experiments/grouping-rules/base',
|
||||
'../tests/spec/lib/experiments/grouping-rules/communication-prefs',
|
||||
'../tests/spec/lib/experiments/grouping-rules/connect-another-device-on-signin',
|
||||
'../tests/spec/lib/experiments/grouping-rules/disabled-button-state',
|
||||
'../tests/spec/lib/experiments/grouping-rules/email-first',
|
||||
'../tests/spec/lib/experiments/grouping-rules/index',
|
||||
|
@ -126,6 +127,7 @@ function (Translator, Session) {
|
|||
'../tests/spec/views/app',
|
||||
'../tests/spec/views/base',
|
||||
'../tests/spec/views/behaviors/connect-another-device',
|
||||
'../tests/spec/views/behaviors/connect-another-device-on-signin',
|
||||
'../tests/spec/views/behaviors/halt',
|
||||
'../tests/spec/views/behaviors/halt-if-browser-transitions',
|
||||
'../tests/spec/views/behaviors/navigate',
|
||||
|
|
|
@ -140,9 +140,9 @@ define([
|
|||
.then(testUrlInclude(CONNECT_ANOTHER_DEVICE_ENTRYPOINT));
|
||||
},
|
||||
|
||||
'signin Fx Desktop, verify same browser': function () {
|
||||
'signin Fx Desktop, verify same browser - control': function () {
|
||||
const forceUA = UA_STRINGS['desktop_firefox'];
|
||||
const query = { forceUA };
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'control', forceUA };
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: true }))
|
||||
.then(openPage(SIGNIN_DESKTOP_URL, selectors.SIGNIN.HEADER, { query }))
|
||||
|
@ -157,6 +157,23 @@ define([
|
|||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER));
|
||||
},
|
||||
|
||||
'signin Fx Desktop, verify same browser - treatment': function () {
|
||||
const forceUA = UA_STRINGS['desktop_firefox'];
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'treatment', forceUA };
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: true }))
|
||||
.then(openPage(SIGNIN_DESKTOP_URL, selectors.SIGNIN.HEADER, { query }))
|
||||
.then(respondToWebChannelMessage(CHANNEL_COMMAND_CAN_LINK_ACCOUNT, { ok: true } ))
|
||||
.then(fillOutSignIn(email, PASSWORD))
|
||||
.then(testElementExists(selectors.CONFIRM_SIGNIN.HEADER))
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER));
|
||||
},
|
||||
|
||||
'signup Fx Desktop, verify different Fx Desktop with another user already signed in': function () {
|
||||
const signInEmail = TestHelpers.createEmail('sync{id}');
|
||||
const signUpEmail = email;
|
||||
|
|
|
@ -28,22 +28,21 @@ define([
|
|||
const PASSWORD = 'password';
|
||||
let email;
|
||||
|
||||
const setupTest = thenify(function (options) {
|
||||
options = options || {};
|
||||
|
||||
const setupTest = thenify(function (options = {}) {
|
||||
const successSelector = options.blocked ? selectors.SIGNIN_UNBLOCK.HEADER :
|
||||
options.preVerified ? selectors.CONFIRM_SIGNIN.HEADER :
|
||||
selectors.CONFIRM_SIGNUP.HEADER;
|
||||
|
||||
const query = Object.assign({
|
||||
context: 'fx_fennec_v1',
|
||||
email: email,
|
||||
service: 'sync'
|
||||
}, options.query || {});
|
||||
|
||||
return this.parent
|
||||
.then(clearBrowserState())
|
||||
.then(createUser(email, PASSWORD, { preVerified: options.preVerified }))
|
||||
.then(openForceAuth({ query: {
|
||||
context: 'fx_fennec_v1',
|
||||
email: email,
|
||||
service: 'sync'
|
||||
}}))
|
||||
.then(openForceAuth({ query }))
|
||||
.then(respondToWebChannelMessage('fxaccounts:can_link_account', { ok: true } ))
|
||||
.then(fillOutForceAuth(PASSWORD))
|
||||
|
||||
|
@ -64,11 +63,13 @@ define([
|
|||
email = TestHelpers.createEmail('sync{id}');
|
||||
},
|
||||
|
||||
'verified, verify same browser': function () {
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true }))
|
||||
'verified, verify same browser - control': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'control' };
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0))
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true, query }))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
@ -76,6 +77,20 @@ define([
|
|||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER));
|
||||
},
|
||||
|
||||
'verified, verify same browser - treatment': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'treatment' };
|
||||
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true, query }))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER));
|
||||
},
|
||||
|
||||
'verified, verify different browser - from original tab\'s P.O.V.': function () {
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true }))
|
||||
|
|
|
@ -46,7 +46,7 @@ define([
|
|||
return this.parent
|
||||
.then(clearBrowserState())
|
||||
.then(createUser(email, PASSWORD, { preVerified: options.preVerified }))
|
||||
.then(openPage(SIGNIN_PAGE_URL, selectors.SIGNIN.HEADER))
|
||||
.then(openPage(SIGNIN_PAGE_URL, selectors.SIGNIN.HEADER, { query: options.query }))
|
||||
.then(respondToWebChannelMessage('fxaccounts:can_link_account', { ok: true } ))
|
||||
.then(fillOutSignIn(email, PASSWORD))
|
||||
.then(testElementExists(successSelector))
|
||||
|
@ -60,17 +60,18 @@ define([
|
|||
});
|
||||
|
||||
registerSuite({
|
||||
name: 'Fx Fennec Sync v1 sign_in',
|
||||
name: 'Fx Fennec Sync v1 signin',
|
||||
|
||||
beforeEach: function () {
|
||||
email = TestHelpers.createEmail('sync{id}');
|
||||
},
|
||||
|
||||
'verified, verify same browser': function () {
|
||||
'verified, verify same browser - control': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'control' };
|
||||
return this.remote
|
||||
.then(setupTest(selectors.CONFIRM_SIGNIN.HEADER, { preVerified: true }))
|
||||
.then(setupTest(selectors.CONFIRM_SIGNIN.HEADER, { preVerified: true, query }))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0))
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
@ -78,6 +79,19 @@ define([
|
|||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER));
|
||||
},
|
||||
|
||||
'verified, verify same browser - treatment': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'treatment' };
|
||||
return this.remote
|
||||
.then(setupTest(selectors.CONFIRM_SIGNIN.HEADER, { preVerified: true, query }))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER));
|
||||
},
|
||||
|
||||
'verified, verify different browser - from original tab\'s P.O.V.': function () {
|
||||
return this.remote
|
||||
.then(setupTest(selectors.CONFIRM_SIGNIN.HEADER, { preVerified: true }))
|
||||
|
|
|
@ -62,16 +62,18 @@ define([
|
|||
}));
|
||||
},
|
||||
|
||||
'verified, verify same browser': function () {
|
||||
'verified, verify same browser - control': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'control' };
|
||||
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true }))
|
||||
.then(setupTest({ preVerified: true, query }))
|
||||
|
||||
.then(testElementExists(selectors.CONFIRM_SIGNIN.HEADER))
|
||||
|
||||
.then(testIsBrowserNotified('fxaccounts:login'))
|
||||
.then(clearBrowserNotifications())
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0))
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
@ -80,6 +82,26 @@ define([
|
|||
.then(noSuchBrowserNotification('fxaccounts:login'));
|
||||
},
|
||||
|
||||
'verified, verify same browser - treatment': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'treatment' };
|
||||
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true, query }))
|
||||
|
||||
.then(testElementExists(selectors.CONFIRM_SIGNIN.HEADER))
|
||||
|
||||
.then(testIsBrowserNotified('fxaccounts:login'))
|
||||
.then(clearBrowserNotifications())
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
|
||||
.then(noSuchBrowserNotification('fxaccounts:login'));
|
||||
},
|
||||
|
||||
'verified, verify different browser - from original tab\'s P.O.V.': function () {
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true }))
|
||||
|
|
|
@ -38,6 +38,7 @@ define([
|
|||
return this.remote
|
||||
.then(clearBrowserState({ force: true }));
|
||||
},
|
||||
|
||||
'signup': function () {
|
||||
return this.remote
|
||||
.then(openPage(PAGE_URL, selectors.ENTER_EMAIL.HEADER, {
|
||||
|
@ -82,10 +83,13 @@ define([
|
|||
.then(testIsBrowserNotified('fxaccounts:can_link_account'));
|
||||
},
|
||||
|
||||
'signin verified': function () {
|
||||
'signin verified - control': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'control' };
|
||||
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: true }))
|
||||
.then(openPage(PAGE_URL, selectors.ENTER_EMAIL.HEADER, {
|
||||
// Note, query not passed here or else email-first is not used.
|
||||
webChannelResponses: {
|
||||
'fxaccounts:can_link_account': { ok: true }
|
||||
}
|
||||
|
@ -100,7 +104,7 @@ define([
|
|||
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT, selectors.CONFIRM_SIGNIN.HEADER))
|
||||
.then(testIsBrowserNotified('fxaccounts:login'))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0))
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
@ -108,6 +112,35 @@ define([
|
|||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER));
|
||||
},
|
||||
|
||||
'signin verified - treatment': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'treatment' };
|
||||
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: true }))
|
||||
.then(openPage(PAGE_URL, selectors.ENTER_EMAIL.HEADER, {
|
||||
// Note, query not passed here or else email-first is not used.
|
||||
webChannelResponses: {
|
||||
'fxaccounts:can_link_account': { ok: true }
|
||||
}
|
||||
}))
|
||||
.then(visibleByQSA(selectors.ENTER_EMAIL.SUB_HEADER))
|
||||
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
|
||||
.then(click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNIN_PASSWORD.HEADER))
|
||||
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
|
||||
|
||||
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email))
|
||||
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
|
||||
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT, selectors.CONFIRM_SIGNIN.HEADER))
|
||||
.then(testIsBrowserNotified('fxaccounts:login'))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER));
|
||||
},
|
||||
|
||||
'signin unverified': function () {
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: false }))
|
||||
|
@ -141,15 +174,15 @@ define([
|
|||
|
||||
'email specified by relier, not registered': function () {
|
||||
return this.remote
|
||||
.then(openPage(PAGE_URL, selectors.SIGNUP_PASSWORD.HEADER, {
|
||||
query: {
|
||||
email
|
||||
},
|
||||
webChannelResponses: {
|
||||
'fxaccounts:can_link_account': { ok: true }
|
||||
}
|
||||
}))
|
||||
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.EMAIL, email));
|
||||
.then(openPage(PAGE_URL, selectors.SIGNUP_PASSWORD.HEADER, {
|
||||
query: {
|
||||
email
|
||||
},
|
||||
webChannelResponses: {
|
||||
'fxaccounts:can_link_account': { ok: true }
|
||||
}
|
||||
}))
|
||||
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.EMAIL, email));
|
||||
},
|
||||
|
||||
'email specified by relier, registered': function () {
|
||||
|
|
|
@ -79,9 +79,9 @@ define([
|
|||
.then(clearBrowserState({ force: true }));
|
||||
},
|
||||
|
||||
'verified, verify same browser': function () {
|
||||
'verified, verify same browser - control': function () {
|
||||
const forceUA = UA_STRINGS['ios_firefox_6_1'];
|
||||
const query = { forceUA };
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'control', forceUA };
|
||||
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true, query }))
|
||||
|
@ -94,6 +94,21 @@ define([
|
|||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER));
|
||||
},
|
||||
|
||||
'verified, verify same browser - treatment': function () {
|
||||
const forceUA = UA_STRINGS['ios_firefox_6_1'];
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'treatment', forceUA };
|
||||
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true, query }))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER));
|
||||
},
|
||||
|
||||
'verified, verify different browser - from original tab\'s P.O.V.': function () {
|
||||
const forceUA = UA_STRINGS['ios_firefox_6_1'];
|
||||
return this.remote
|
||||
|
|
|
@ -128,10 +128,13 @@ define([
|
|||
.then(testIsBrowserNotified('fxaccounts:can_link_account'));
|
||||
},
|
||||
|
||||
'signin verified': function () {
|
||||
'signin verified - control ': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'control' };
|
||||
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: true }))
|
||||
.then(openPage(INDEX_PAGE_URL, selectors.ENTER_EMAIL.HEADER, {
|
||||
// Note, query not passed here or else email-first is not used.
|
||||
webChannelResponses: {
|
||||
'fxaccounts:can_link_account': { ok: true }
|
||||
}
|
||||
|
@ -147,7 +150,7 @@ define([
|
|||
|
||||
.then(testIsBrowserNotified('fxaccounts:login'))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0))
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
@ -158,6 +161,39 @@ define([
|
|||
.then(noPageTransition(selectors.CONFIRM_SIGNIN.HEADER));
|
||||
},
|
||||
|
||||
'signin verified - treatment': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'treatment' };
|
||||
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: true }))
|
||||
.then(openPage(INDEX_PAGE_URL, selectors.ENTER_EMAIL.HEADER, {
|
||||
// Note, query not passed here or else email-first is not used.
|
||||
webChannelResponses: {
|
||||
'fxaccounts:can_link_account': { ok: true }
|
||||
}
|
||||
}))
|
||||
.then(visibleByQSA(selectors.ENTER_EMAIL.SUB_HEADER))
|
||||
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
|
||||
.then(click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNIN_PASSWORD.HEADER))
|
||||
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
|
||||
|
||||
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email))
|
||||
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
|
||||
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT, selectors.CONFIRM_SIGNIN.HEADER))
|
||||
|
||||
.then(testIsBrowserNotified('fxaccounts:login'))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
||||
// We do not expect the verification poll to occur. The poll
|
||||
// will take a few seconds to complete if it erroneously occurs.
|
||||
// Add an affordance just in case the poll happens unexpectedly.
|
||||
.then(noPageTransition(selectors.CONFIRM_SIGNIN.HEADER));
|
||||
},
|
||||
|
||||
'signin unverified': function () {
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: false }))
|
||||
|
|
|
@ -42,7 +42,7 @@ define([
|
|||
email = TestHelpers.createEmail('sync{id}');
|
||||
},
|
||||
|
||||
'with a registered email, no uid, verify same browser': function () {
|
||||
'with a registered email, no uid, verify same browser - control': function () {
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: true }))
|
||||
.then(function (accountInfo) {
|
||||
|
@ -51,6 +51,8 @@ define([
|
|||
context: 'fx_desktop_v3',
|
||||
email: email,
|
||||
forceAboutAccounts: 'true',
|
||||
forceExperiment: 'cadOnSignin',
|
||||
forceExperimentGroup: 'control',
|
||||
service: 'sync'
|
||||
}
|
||||
}).call(this);
|
||||
|
@ -62,7 +64,7 @@ define([
|
|||
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
|
||||
.then(testIsBrowserNotified('fxaccounts:login'))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0))
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query: { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'control' }}))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
@ -71,6 +73,37 @@ define([
|
|||
.then(noPageTransition(selectors.CONFIRM_SIGNIN.HEADER));
|
||||
},
|
||||
|
||||
'with a registered email, no uid, verify same browser': function () {
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: true }))
|
||||
.then(function (accountInfo) {
|
||||
return openForceAuth({
|
||||
query: {
|
||||
context: 'fx_desktop_v3',
|
||||
email: email,
|
||||
forceAboutAccounts: 'true',
|
||||
forceExperiment: 'cadOnSignin',
|
||||
forceExperimentGroup: 'treatment',
|
||||
service: 'sync'
|
||||
}
|
||||
}).call(this);
|
||||
})
|
||||
.then(respondToWebChannelMessage('fxaccounts:can_link_account', { ok: true } ))
|
||||
.then(fillOutForceAuth(PASSWORD))
|
||||
|
||||
.then(testElementExists(selectors.CONFIRM_SIGNIN.HEADER))
|
||||
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
|
||||
.then(testIsBrowserNotified('fxaccounts:login'))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query: { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'treatment' }}))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
|
||||
.then(closeCurrentWindow())
|
||||
|
||||
// about:accounts will take over post-verification, no transition
|
||||
.then(noPageTransition(selectors.CONFIRM_SIGNIN.HEADER));
|
||||
},
|
||||
|
||||
'with a registered email, registered uid, verify same browser': function () {
|
||||
return this.remote
|
||||
.then(createUser(email, PASSWORD, { preVerified: true }))
|
||||
|
|
|
@ -74,11 +74,26 @@ define([
|
|||
.then(clearBrowserState());
|
||||
},
|
||||
|
||||
'verified, verify same browser, new tab\'s P.O.V.': function () {
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true }))
|
||||
'verified, verify same browser, new tab\'s P.O.V - control': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'control' };
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0))
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true, query }))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER))
|
||||
.then(closeCurrentWindow());
|
||||
// tests for the original tab are below.
|
||||
},
|
||||
|
||||
'verified, verify same browser, new tab\'s P.O.V - treatment': function () {
|
||||
const query = { forceExperiment: 'cadOnSignin', forceExperimentGroup: 'control' };
|
||||
|
||||
return this.remote
|
||||
.then(setupTest({ preVerified: true, query }))
|
||||
|
||||
.then(openVerificationLinkInNewTab(email, 0, { query }))
|
||||
.switchToWindow('newwindow')
|
||||
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER))
|
||||
.then(closeCurrentWindow());
|
||||
|
|
Загрузка…
Ссылка в новой задаче