зеркало из https://github.com/mozilla/fxa.git
feat(experiments): Add mutally exclusive experiment logic for CAD QR and newsletters
This commit is contained in:
Родитель
3a6a83ac76
Коммит
6b2f84f5af
|
@ -26,6 +26,7 @@ const MANUAL_EXPERIMENTS = {
|
|||
sendSms: BaseExperiment,
|
||||
newsletterSync: BaseExperiment,
|
||||
qrCodeCad: BaseExperiment,
|
||||
newsletterCadChooser: BaseExperiment,
|
||||
};
|
||||
|
||||
const ALL_EXPERIMENTS = _.extend({}, STARTUP_EXPERIMENTS, MANUAL_EXPERIMENTS);
|
||||
|
|
|
@ -18,6 +18,7 @@ const experimentGroupingRules = [
|
|||
require('./email-mx-validation'),
|
||||
require('./newsletter-sync'),
|
||||
require('./qr-code-cad'),
|
||||
require('./newsletter-cad-chooser'),
|
||||
].map(ExperimentGroupingRule => new ExperimentGroupingRule());
|
||||
|
||||
class ExperimentChoiceIndex {
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* 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/. */
|
||||
|
||||
/**
|
||||
* To ensure that the newsletter and qr cad experiment are mutually
|
||||
* exclusive, we create a new experiment rule to select only one of them.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const BaseGroupingRule = require('./base');
|
||||
const GROUPS = ['newsletterSync', 'qrCodeCad'];
|
||||
|
||||
module.exports = class ExperimentChooser extends BaseGroupingRule {
|
||||
constructor() {
|
||||
super();
|
||||
this.name = 'newsletterCadChooser';
|
||||
|
||||
// Easier to set class properties for testability
|
||||
this.groups = GROUPS;
|
||||
}
|
||||
|
||||
choose(subject = {}) {
|
||||
return this.uniformChoice(this.groups, subject.uniqueUserId);
|
||||
}
|
||||
};
|
|
@ -37,21 +37,34 @@ module.exports = class NewsletterSync extends BaseGroupingRule {
|
|||
*
|
||||
* @param {Object} subject data used to decide
|
||||
* @param {Boolean} isSync is this a sync signup?
|
||||
* @param {String} lang language of user
|
||||
* @returns {Any}
|
||||
*/
|
||||
choose(subject = {}) {
|
||||
let choice = false;
|
||||
|
||||
// Only enroll for sync users
|
||||
if (!subject.isSync) {
|
||||
if (
|
||||
subject.experimentGroupingRules.choose('newsletterCadChooser') !==
|
||||
this.name
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO Add restriction to `EN` locales
|
||||
let choice = false;
|
||||
const { isSync, lang } = subject;
|
||||
|
||||
// Only enroll for sync users
|
||||
if (!isSync || !lang) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only en users are eligible for experiment
|
||||
if (lang.slice(0, 2) !== 'en') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.bernoulliTrial(this.rolloutRate, subject.uniqueUserId)) {
|
||||
choice = this.uniformChoice(GROUPS, subject.uniqueUserId);
|
||||
}
|
||||
|
||||
return choice;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ const GROUPS = [
|
|||
'treatment-b', // Screen displayed in non-sms markets
|
||||
];
|
||||
|
||||
const ROLLOUT_RATE = 0.0;
|
||||
const ROLLOUT_RATE = 1.0;
|
||||
|
||||
module.exports = class QrCodeCad extends BaseGroupingRule {
|
||||
constructor() {
|
||||
|
@ -41,6 +41,13 @@ module.exports = class QrCodeCad extends BaseGroupingRule {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
subject.experimentGroupingRules.choose('newsletterCadChooser') !==
|
||||
this.name
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let telephoneInfo = CountryTelephoneInfo[subject.country];
|
||||
const { featureFlags } = subject;
|
||||
if (featureFlags && featureFlags.smsCountries) {
|
||||
|
@ -58,7 +65,7 @@ module.exports = class QrCodeCad extends BaseGroupingRule {
|
|||
|
||||
if (this.isTestEmail(subject.account.get('email'))) {
|
||||
// Test users always get the new experience
|
||||
choice = 'treatment-b';
|
||||
choice = 'treatment-a';
|
||||
} else if (countryRollOut >= 1) {
|
||||
// This experiment should only be shown to countries that are fully
|
||||
// rolled out with sms
|
||||
|
|
|
@ -12,6 +12,7 @@ import AuthErrors from '../lib/auth-errors';
|
|||
import CachedCredentialsMixin from './mixins/cached-credentials-mixin';
|
||||
import Cocktail from 'cocktail';
|
||||
import CoppaMixin from './mixins/coppa-mixin';
|
||||
import ExperimentMixin from './mixins/experiment-mixin';
|
||||
import EmailMxValidationExperimentMixin from './mixins/email-mx-validation-experiment-mixin';
|
||||
import FirefoxFamilyServicesTemplate from '../templates/partial/firefox-family-services.mustache';
|
||||
import FlowBeginMixin from './mixins/flow-begin-mixin';
|
||||
|
@ -89,6 +90,11 @@ class IndexView extends FormView {
|
|||
AuthErrors.toError('SIGNUP_EMAIL_BOUNCE')
|
||||
);
|
||||
}
|
||||
|
||||
// The CAD via QR and newsletters experiment are mutally exclusive
|
||||
// so a user can only be enrolled in one of them at a time. This
|
||||
// select the experiment the user will belong to.
|
||||
this.getAndReportExperimentGroup('newsletterCadChooser');
|
||||
}
|
||||
|
||||
chooseEmailActionPage() {
|
||||
|
@ -235,6 +241,7 @@ Cocktail.mixin(
|
|||
CoppaMixin({}),
|
||||
EmailAutocompleteDomainsMixin,
|
||||
EmailMxValidationExperimentMixin,
|
||||
ExperimentMixin,
|
||||
FlowBeginMixin,
|
||||
FormPrefillMixin,
|
||||
ServiceMixin,
|
||||
|
|
|
@ -18,6 +18,7 @@ export default {
|
|||
isInNewsletterSyncExperimentTrailheadCopy() {
|
||||
const experimentGroup = this.getAndReportExperimentGroup(EXPERIMENT_NAME, {
|
||||
isSync: this.relier.isSync(),
|
||||
lang: this.navigator.language,
|
||||
});
|
||||
|
||||
return experimentGroup === 'trailhead-copy';
|
||||
|
@ -26,6 +27,7 @@ export default {
|
|||
isInNewsletterSyncExperimentNewCopy() {
|
||||
const experimentGroup = this.getAndReportExperimentGroup(EXPERIMENT_NAME, {
|
||||
isSync: this.relier.isSync(),
|
||||
lang: this.navigator.language,
|
||||
});
|
||||
|
||||
return experimentGroup === 'new-copy';
|
||||
|
|
|
@ -9,7 +9,7 @@ import sinon from 'sinon';
|
|||
|
||||
describe('lib/experiments/grouping-rules/index', () => {
|
||||
it('EXPERIMENT_NAMES is exported', () => {
|
||||
assert.lengthOf(ExperimentGroupingRules.EXPERIMENT_NAMES, 7);
|
||||
assert.lengthOf(ExperimentGroupingRules.EXPERIMENT_NAMES, 8);
|
||||
});
|
||||
|
||||
describe('choose', () => {
|
||||
|
|
|
@ -15,14 +15,35 @@ describe('lib/experiments/grouping-rules/newsletter-sync', () => {
|
|||
describe('choose', () => {
|
||||
it('returns false if not Sync', () => {
|
||||
assert.isFalse(
|
||||
experiment.choose({ isSync: false, uniqueUserId: 'user-id' })
|
||||
experiment.choose({
|
||||
experimentGroupingRules: { choose: () => experiment.name },
|
||||
isSync: false,
|
||||
uniqueUserId: 'user-id',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('returns false if not `en` locale', () => {
|
||||
experiment.rolloutRate = 0;
|
||||
assert.isFalse(
|
||||
experiment.choose({
|
||||
experimentGroupingRules: { choose: () => experiment.name },
|
||||
isSync: true,
|
||||
lang: 'de',
|
||||
uniqueUserId: 'user-id',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('returns false if rollout 0%', () => {
|
||||
experiment.rolloutRate = 0;
|
||||
assert.isFalse(
|
||||
experiment.choose({ isSync: true, uniqueUserId: 'user-id' })
|
||||
experiment.choose({
|
||||
experimentGroupingRules: { choose: () => experiment.name },
|
||||
isSync: true,
|
||||
lang: 'en',
|
||||
uniqueUserId: 'user-id',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -30,7 +51,12 @@ describe('lib/experiments/grouping-rules/newsletter-sync', () => {
|
|||
experiment.rolloutRate = 1;
|
||||
assert.isTrue(
|
||||
experiment.groups.includes(
|
||||
experiment.choose({ isSync: true, uniqueUserId: 'user-id' })
|
||||
experiment.choose({
|
||||
experimentGroupingRules: { choose: () => experiment.name },
|
||||
isSync: true,
|
||||
lang: 'en',
|
||||
uniqueUserId: 'user-id',
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
|
|
|
@ -48,6 +48,7 @@ require('./spec/lib/experiments/grouping-rules/communication-prefs');
|
|||
require('./spec/lib/experiments/grouping-rules/email-mx-validation');
|
||||
require('./spec/lib/experiments/grouping-rules/index');
|
||||
require('./spec/lib/experiments/grouping-rules/is-sampled-user');
|
||||
require('./spec/lib/experiments/grouping-rules/newsletter-sync');
|
||||
require('./spec/lib/experiments/grouping-rules/send-sms-install-link');
|
||||
require('./spec/lib/experiments/grouping-rules/sentry');
|
||||
require('./spec/lib/fxa-client');
|
||||
|
|
Загрузка…
Ссылка в новой задаче