Merge pull request #3387 from mozilla/email-first-remove-experiment r=@vbudhram

chore(email-first): Remove email-first related experiment code
This commit is contained in:
Shane Tomlinson 2019-11-18 16:28:05 +00:00 коммит произвёл GitHub
Родитель 9a6c142566 46d9b79e28
Коммит 28b3857f5e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 63 добавлений и 464 удалений

Просмотреть файл

@ -20,7 +20,6 @@ const STARTUP_EXPERIMENTS = {};
* after the app has started.
*/
const MANUAL_EXPERIMENTS = {
emailFirst: BaseExperiment,
// For now, the send SMS experiment only needs to log "enrolled", so
// no special experiment is created.
signupCode: BaseExperiment,

Просмотреть файл

@ -1,46 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const BaseGroupingRule = require('./base');
const EXPERIMENT_NAME = 'emailFirst';
class EmailFirstGroupingRule extends BaseGroupingRule {
constructor() {
super();
this.name = EXPERIMENT_NAME;
}
/**
* Use `subject` data to make a choice.
*
* @param {Object} subject data used to decide
* @returns {Any}
*/
choose(subject) {
if (!this._isValidSubject(subject)) {
return false;
} else if (!subject.isEmailFirstSupported) {
// isEmailFirstSupported is `true` for brokers that support the email-first flow.
return false;
}
return 'treatment';
}
/**
* Is the subject valid?
*
* @param {Object} subject
* @returns {Boolean}
* @private
*/
_isValidSubject(subject) {
return subject;
}
}
module.exports = EmailFirstGroupingRule;

Просмотреть файл

@ -13,7 +13,6 @@ const _ = require('underscore');
const experimentGroupingRules = [
require('./communication-prefs'),
require('./cwts-on-signup-password'),
require('./email-first'),
require('./is-sampled-user'),
require('./send-sms-install-link'),
require('./sentry'),

Просмотреть файл

@ -12,7 +12,6 @@ import AuthErrors from '../lib/auth-errors';
import CachedCredentialsMixin from './mixins/cached-credentials-mixin';
import Cocktail from 'cocktail';
import CoppaMixin from './mixins/coppa-mixin';
import EmailFirstExperimentMixin from './mixins/email-first-experiment-mixin';
import FirefoxFamilyServicesTemplate from '../templates/partial/firefox-family-services.mustache';
import TokenCodeExperimentMixin from './mixins/token-code-experiment-mixin';
import FlowBeginMixin from './mixins/flow-begin-mixin';
@ -69,19 +68,14 @@ class IndexView extends FormView {
if (isLegacySigninSignupDisabled && action !== 'force_auth') {
return this.chooseEmailActionPage();
}
if (action && action !== 'email') {
} else if (action === 'force_auth') {
this.replaceCurrentPage(action);
} else if (
this.isInEmailFirstExperimentGroup('treatment') ||
action === 'email'
) {
} else if (action) {
return this.chooseEmailActionPage();
} else if (this.getSignedInAccount().get('sessionToken')) {
this.replaceCurrentPage('settings');
} else {
this.replaceCurrentPage('signup');
return this.chooseEmailActionPage();
}
}
@ -228,7 +222,6 @@ Cocktail.mixin(
IndexView,
CachedCredentialsMixin,
CoppaMixin({}),
EmailFirstExperimentMixin(),
TokenCodeExperimentMixin,
FlowBeginMixin,
FormPrefillMixin,

Просмотреть файл

@ -1,94 +0,0 @@
/* 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/. */
/**
* An EmailFirstExperimentMixin factory.
*
* EmailFirstMixin is consumed by views that deal with the email-first experiment.
*
* @mixin EmailFirstExperimentMixin
*/
import ExperimentMixin from './experiment-mixin';
const EXPERIMENT_NAME = 'emailFirst';
/**
* Creates the mixin
*
* @param {Object} [options={}]
* @param {String} [treatmentPathname] pathname to redirect to if the user is in `treatment`
* @returns {Object} mixin
*/
export default (options = {}) => {
return {
dependsOn: [ExperimentMixin],
beforeRender() {
if (
(this.relier.get('action') === 'email' ||
this.broker.getCapability('disableLegacySigninSignup')) &&
options.treatmentPathname
) {
this.replaceCurrentPage(options.treatmentPathname);
} else if (this.isInEmailFirstExperiment()) {
const experimentGroup = this.getEmailFirstExperimentGroup();
this.createExperiment(EXPERIMENT_NAME, experimentGroup);
if (experimentGroup === 'treatment' && options.treatmentPathname) {
this.replaceCurrentPage(options.treatmentPathname);
}
}
},
/**
* Get the email first experiment group
*
* @returns {String}
*/
getEmailFirstExperimentGroup() {
return this.getExperimentGroup(
EXPERIMENT_NAME,
this._getEmailFirstExperimentSubject()
);
},
/**
* Is the user in the email-first experiment?
*
* @returns {Boolean}
*/
isInEmailFirstExperiment() {
return this.isInExperiment(
EXPERIMENT_NAME,
this._getEmailFirstExperimentSubject()
);
},
/**
* Is the user in email-first experiment's `groupName` group?
*
* @param {String} groupName
* @returns {Boolean}
*/
isInEmailFirstExperimentGroup(groupName) {
return this.isInExperimentGroup(
EXPERIMENT_NAME,
groupName,
this._getEmailFirstExperimentSubject()
);
},
/**
* Get the email-first experiment choice subject
*
* @returns {Object}
* @private
*/
_getEmailFirstExperimentSubject() {
const subject = {
isEmailFirstSupported: this.broker.getCapability('emailFirst'),
};
return subject;
},
};
};

Просмотреть файл

@ -1,48 +0,0 @@
/* 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/. */
import { assert } from 'chai';
import Experiment from 'lib/experiments/grouping-rules/email-first';
import sinon from 'sinon';
describe('lib/experiments/grouping-rules/email-first', () => {
let experiment;
let sandbox;
before(() => {
experiment = new Experiment();
});
beforeEach(() => {
sandbox = sinon.sandbox.create();
});
afterEach(() => {
sandbox.restore();
});
describe('choose', () => {
it('returns `false` if prereqs not met', () => {
assert.isFalse(experiment.choose());
});
it('returns `false` if `isEmailFirstSupported=false`', () => {
assert.isFalse(
experiment.choose({
isEmailFirstSupported: false,
})
);
});
it('returns `treatment` otherwise', () => {
assert.equal(
experiment.choose({
env: 'development',
isEmailFirstSupported: true,
}),
'treatment'
);
});
});
});

Просмотреть файл

@ -9,7 +9,7 @@ import sinon from 'sinon';
describe('lib/experiments/grouping-rules/index', () => {
it('EXPERIMENT_NAMES is exported', () => {
assert.lengthOf(ExperimentGroupingRules.EXPERIMENT_NAMES, 8);
assert.lengthOf(ExperimentGroupingRules.EXPERIMENT_NAMES, 7);
});
describe('choose', () => {

Просмотреть файл

@ -75,6 +75,12 @@ describe('views/index', () => {
sinon.spy(view, 'replaceCurrentPage');
});
it('renders the firefox-family services', () => {
return view.render().then(() => {
assert.lengthOf(view.$(Selectors.FIREFOX_FAMILY_SERVICES), 1);
});
});
describe('account has bounced', () => {
it('prefills the email, shows a tooltip', () => {
const bouncedAccount = user.initAccount({
@ -135,108 +141,77 @@ describe('views/index', () => {
});
describe('no current account', () => {
describe('relier.action set, !== email', () => {
it('replaces current page with page specified by `action`', () => {
relier.set('action', 'signin');
describe('relier.action === force_auth', () => {
it('redirects to /force_auth', () => {
sinon.stub(view, 'chooseEmailActionPage');
relier.set('action', 'force_auth');
return view.render().then(() => {
assert.isTrue(view.replaceCurrentPage.calledOnce);
assert.isTrue(view.replaceCurrentPage.calledWith('signin'));
assert.isFalse(notifier.trigger.calledWith('email-first-flow'));
assert.isTrue(view.replaceCurrentPage.calledOnceWith('force_auth'));
assert.isFalse(view.chooseEmailActionPage.calledOnce);
});
});
});
describe('broker disables legacy signin/signup', () => {
it('renders as expected, starts the flow metrics', () => {
broker.setCapability('disableLegacySigninSignup', true);
describe('relier.action === signin', () => {
it('uses email first flow', () => {
relier.set('action', 'signin');
return renderTestEnterEmailDisplayed(view, '');
});
});
relier.set({
service: 'sync',
serviceName: 'Firefox Sync',
});
sinon
.stub(view, 'isInEmailFirstExperimentGroup')
.callsFake(() => false);
return renderTestEnterEmailDisplayed(view);
describe('relier.action === signup', () => {
it('uses email first flow', () => {
relier.set('action', 'signup');
return renderTestEnterEmailDisplayed(view, '');
});
});
describe('relier.action === email', () => {
it('renders as expected, starts the flow metrics', () => {
it('uses email first flow', () => {
relier.set({
action: 'email',
service: 'sync',
serviceName: 'Firefox Sync',
});
sinon
.stub(view, 'isInEmailFirstExperimentGroup')
.callsFake(() => false);
return renderTestEnterEmailDisplayed(view);
});
it('handles relier specified emails', () => {
relier.set({
action: 'email',
email: 'testuser@testuser.com',
service: 'sync',
serviceName: 'Firefox Sync',
});
sinon
.stub(view, 'isInEmailFirstExperimentGroup')
.callsFake(() => false);
sinon.stub(view, 'checkEmail').callsFake(() => Promise.resolve());
return view.render().then(() => {
assert.isTrue(
view.checkEmail.calledOnceWith('testuser@testuser.com')
);
});
});
it('renders the firefox-family services', () => {
return view.render().then(() => {
assert.lengthOf(view.$(Selectors.FIREFOX_FAMILY_SERVICES), 1);
});
return renderTestEnterEmailDisplayed(view, 'Firefox Sync');
});
});
describe('user is in EmailFirstExperiment `treatment` group', () => {
it('renders as expected, starts the flow metrics', () => {
relier.set({
service: 'sync',
serviceName: 'Firefox Sync',
});
sinon
.stub(view, 'isInEmailFirstExperimentGroup')
.callsFake(() => true);
return renderTestEnterEmailDisplayed(view);
describe('fallback behavior', () => {
it('uses email first flow', () => {
return renderTestEnterEmailDisplayed(view, '');
});
});
});
});
describe('user is not in EmailFirstExperiment `treatment` group', () => {
it('redirects to `/signup`', () => {
sinon
.stub(view, 'isInEmailFirstExperimentGroup')
.callsFake(() => false);
return view.render().then(() => {
assert.isTrue(view.isInEmailFirstExperimentGroup.calledOnce);
assert.isTrue(
view.isInEmailFirstExperimentGroup.calledWith('treatment')
);
assert.isTrue(view.replaceCurrentPage.calledOnce);
assert.isTrue(view.replaceCurrentPage.calledWith('signup'));
});
});
describe('chooseEmailActionPage', () => {
it('handles relier specified emails', () => {
relier.set({
action: 'email',
email: 'testuser@testuser.com',
service: 'sync',
serviceName: 'Firefox Sync',
});
sinon.stub(view, 'checkEmail');
view.chooseEmailActionPage();
assert.isTrue(view.checkEmail.calledOnceWith('testuser@testuser.com'));
});
it('handled suggested account', () => {
sinon.stub(view, 'allowSuggestedAccount').returns(true);
sinon.stub(view, 'replaceCurrentPage');
const account = {
email: 'testuser@testuser.com',
};
sinon.stub(view, 'suggestedAccount').returns(account);
view.chooseEmailActionPage();
assert.isTrue(
view.replaceCurrentPage.calledOnceWith('signin', { account })
);
});
});
@ -392,21 +367,20 @@ describe('views/index', () => {
});
});
function renderTestEnterEmailDisplayed(view) {
function renderTestEnterEmailDisplayed(view, expectedServiceName) {
sinon.spy(view, 'logFlowEventOnce');
sinon.stub(view, 'chooseEmailActionPage');
return view.render().then(() => {
assert.isFalse(view.replaceCurrentPage.called);
assert.lengthOf(view.$(Selectors.HEADER), 1);
assert.lengthOf(view.$(Selectors.EMAIL), 1);
assert.include(view.$(Selectors.SUB_HEADER).text(), 'Firefox Sync');
assert.include(view.$(Selectors.SUB_HEADER).text(), expectedServiceName);
assert.isTrue(view.chooseEmailActionPage.calledOnce);
assert.lengthOf(view.$(Selectors.FIREFOX_FAMILY_SERVICES), 1);
assert.isTrue(notifier.trigger.calledWith('email-first-flow'));
assert.isTrue(view.logFlowEventOnce.calledOnce);
assert.isTrue(view.logFlowEventOnce.calledWith('begin'));
assert.isTrue(view.logFlowEventOnce.calledOnceWith('begin'));
});
}
});

Просмотреть файл

@ -1,170 +0,0 @@
/* 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/. */
import { assert } from 'chai';
import AuthBroker from 'models/auth_brokers/base';
import BaseView from 'views/base';
import Cocktail from 'cocktail';
import EmailFirstExperimentMixin from 'views/mixins/email-first-experiment-mixin';
import Notifier from 'lib/channels/notifier';
import Relier from 'models/reliers/relier';
import sinon from 'sinon';
class View extends BaseView {
constructor(options) {
super(options);
this.className = 'redirects';
}
}
Cocktail.mixin(View, EmailFirstExperimentMixin({ treatmentPathname: '/' }));
describe('views/mixins/email-first-experiment-mixin', () => {
let broker;
let notifier;
let relier;
let sandbox;
let view;
before(() => {
sandbox = sinon.sandbox.create();
broker = new AuthBroker();
broker.setCapability('emailFirst', true);
notifier = new Notifier();
relier = new Relier();
view = new View({
broker,
notifier,
relier,
viewName: 'email',
});
});
afterEach(() => {
sandbox.restore();
relier.unset('action');
});
after(() => {
view.remove();
view.destroy();
view = null;
});
it('exposes the expected interface', () => {
const mixin = EmailFirstExperimentMixin();
assert.lengthOf(Object.keys(mixin), 6);
assert.isArray(mixin.dependsOn);
assert.isFunction(mixin.beforeRender);
assert.isFunction(mixin.getEmailFirstExperimentGroup);
assert.isFunction(mixin.isInEmailFirstExperiment);
assert.isFunction(mixin.isInEmailFirstExperimentGroup);
assert.isFunction(mixin._getEmailFirstExperimentSubject);
});
it('_getEmailFirstExperimentSubject returns the expected object', () => {
assert.deepEqual(view._getEmailFirstExperimentSubject(), {
isEmailFirstSupported: true,
});
});
it('isInEmailFirstExperiment delegates to `isInExperiment` correctly', () => {
sandbox.stub(view, 'isInExperiment').callsFake(() => true);
assert.isTrue(view.isInEmailFirstExperiment());
assert.isTrue(view.isInExperiment.calledOnce);
assert.isTrue(
view.isInExperiment.calledWith('emailFirst', {
isEmailFirstSupported: true,
})
);
});
it('isInEmailFirstExperimentGroup delegates to `isInExperimentGroup` correctly', () => {
sandbox.stub(view, 'isInExperimentGroup').callsFake(() => true);
assert.isTrue(view.isInEmailFirstExperimentGroup('treatment'));
assert.isTrue(view.isInExperimentGroup.calledOnce);
assert.isTrue(
view.isInExperimentGroup.calledWith('emailFirst', 'treatment', {
isEmailFirstSupported: true,
})
);
});
describe('beforeRender', () => {
beforeEach(() => {
sandbox.spy(view, 'createExperiment');
sandbox.spy(view, 'replaceCurrentPage');
broker.unsetCapability('disableLegacySigninSignup');
});
it('redirects to the treatment page if `action=email`', () => {
relier.set('action', 'email');
view.beforeRender();
assert.isTrue(view.replaceCurrentPage.calledOnceWith('/'));
});
it('redirects to the treatment page if legacy signin/signup disabled for broker', () => {
broker.setCapability('disableLegacySigninSignup', true);
view.beforeRender();
assert.isTrue(view.replaceCurrentPage.calledOnceWith('/'));
});
it('does nothing for users not in the experiment', () => {
sandbox.stub(view, 'isInEmailFirstExperiment').callsFake(() => false);
sandbox
.stub(view, 'isInEmailFirstExperimentGroup')
.callsFake(() => false);
view.beforeRender();
assert.isTrue(view.isInEmailFirstExperiment.calledOnce);
assert.isFalse(view.createExperiment.called);
assert.isFalse(view.replaceCurrentPage.called);
});
it('creates the experiment for users in the control group, does not redirect', () => {
sandbox.stub(view, 'isInEmailFirstExperiment').callsFake(() => true);
sandbox
.stub(view, 'getEmailFirstExperimentGroup')
.callsFake(() => 'control');
view.beforeRender();
assert.isTrue(view.isInEmailFirstExperiment.calledOnce);
assert.isTrue(view.createExperiment.calledOnce);
assert.isTrue(view.createExperiment.calledWith('emailFirst', 'control'));
assert.isFalse(view.replaceCurrentPage.called);
});
it('creates the experiment for users in the treatment group, redirects if treatmentPathname specified', () => {
sandbox.stub(view, 'isInEmailFirstExperiment').callsFake(() => true);
sandbox
.stub(view, 'getEmailFirstExperimentGroup')
.callsFake(() => 'treatment');
view.beforeRender();
assert.isTrue(view.createExperiment.calledOnce);
assert.isTrue(
view.createExperiment.calledWith('emailFirst', 'treatment')
);
assert.isTrue(view.replaceCurrentPage.calledOnce);
assert.isTrue(view.replaceCurrentPage.calledWith('/'));
});
});
});

Просмотреть файл

@ -43,7 +43,6 @@ require('./spec/lib/experiments/base');
require('./spec/lib/experiments/grouping-rules/base');
require('./spec/lib/experiments/grouping-rules/cwts-on-signup-password');
require('./spec/lib/experiments/grouping-rules/communication-prefs');
require('./spec/lib/experiments/grouping-rules/email-first');
require('./spec/lib/experiments/grouping-rules/index');
require('./spec/lib/experiments/grouping-rules/is-sampled-user');
require('./spec/lib/experiments/grouping-rules/send-sms-install-link');
@ -177,7 +176,6 @@ require('./spec/views/mixins/coppa-mixin');
require('./spec/views/mixins/disable-form-mixin');
require('./spec/views/mixins/do-not-sync-mixin');
require('./spec/views/mixins/pairing-graphics-mixin');
require('./spec/views/mixins/email-first-experiment-mixin');
require('./spec/views/mixins/email-opt-in-mixin');
require('./spec/views/mixins/experiment-mixin');
require('./spec/views/mixins/external-links-mixin');

Просмотреть файл

@ -150,12 +150,6 @@ registerSuite('cached signin', {
.then(destroySessionForEmail(email))
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
email
)
)
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT))