Merge pull request #16169 from mozilla/FXA-8759

feat(content): Remove experiment logic around third party auth
This commit is contained in:
Valerie Pomerleau 2023-12-13 09:25:55 -08:00 коммит произвёл GitHub
Родитель 51ca439c66 e3e4f151f1
Коммит f793fba3f1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 62 добавлений и 223 удалений

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

@ -23,11 +23,7 @@ test.describe('severity-1 #smoke', () => {
'Please contact FxA admin to get credentials for Google account'
);
test.slow();
await page.goto(
target.contentServerUrl +
'?forceExperiment=thirdPartyAuth&forceExperimentGroup=treatment',
{ waitUntil: 'load' }
);
await page.goto(target.contentServerUrl, { waitUntil: 'load' });
await login.clickContinueWithGoogle();

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

@ -15,7 +15,6 @@ const experimentGroupingRules = [
require('./is-sampled-user'),
require('./sentry'),
require('./push'),
require('./third-party-auth'),
require('./generalized-react-app'),
].map((ExperimentGroupingRule) => new ExperimentGroupingRule());

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

@ -1,53 +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 GROUPS = [
// Treatment branches
'treatment',
];
// This experiment is disabled by default. If you would like to go through
// the flow, load email-first screen and append query params
// `?forceExperiment=thirdPartyAuth&forceExperimentGroup=treatment`
const ROLLOUT_RATE = 1.0;
module.exports = class ThirdPartyAuth extends BaseGroupingRule {
constructor() {
super();
this.name = 'thirdPartyAuth';
// Easier to set class properties for testability
this.groups = GROUPS;
this.rolloutRate = ROLLOUT_RATE;
}
/**
* For this experiment, we are doing a staged rollout.
*
* @param {Object} subject data used to decide
* @param {String} clientId clientId
* @returns {Any}
*/
choose(subject = {}) {
let choice = false;
const { relier } = subject;
if (!relier) {
return;
}
if (relier.isSync()) {
return;
}
if (this.bernoulliTrial(this.rolloutRate, subject.uniqueUserId)) {
choice = this.uniformChoice(GROUPS, subject.uniqueUserId);
}
return choice;
}
};

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

@ -43,21 +43,9 @@
</div>
</form>
{{#isInThirdPartyAuthExperiment}}
{{^isSync}}
{{{ unsafeThirdPartyAuthHTML }}}
{{/isSync}}
{{/isInThirdPartyAuthExperiment}}
{{^isInThirdPartyAuthExperiment}}
{{^isSync}}
<div class="text-xs text-grey-500 mb-0 mt-5">
<p id="firefox-family-services">
{{#t}}A Mozilla account also unlocks access to more privacy-protecting products from Mozilla.{{/t}}
</p>
</div>
{{/isSync}}
{{/isInThirdPartyAuthExperiment}}
{{^isSync}}
{{{ unsafeThirdPartyAuthHTML }}}
{{/isSync}}
<div class="text-xs text-grey-500 mb-0 mt-5">
{{#isSync}}

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

@ -1,18 +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 ExperimentMixin from './experiment-mixin';
const EXPERIMENT_NAME = 'thirdPartyAuth';
export default {
dependsOn: [ExperimentMixin],
isInThirdPartyAuthExperiment() {
const experimentGroup = this.getAndReportExperimentGroup(EXPERIMENT_NAME, {
relier: this.relier,
});
return experimentGroup === 'treatment';
},
};

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

@ -5,13 +5,12 @@
import SigninMixin from './signin-mixin';
import Storage from '../../lib/storage';
import Url from '../../lib/url';
import ThirdPartyAuthExperimentMixin from '../../views/mixins/third-party-auth-experiment-mixin';
import FlowEventsMixin from '../mixins/flow-events-mixin';
const DEFAULT_SCOPES = 'openid email profile';
export default {
dependsOn: [SigninMixin, ThirdPartyAuthExperimentMixin, FlowEventsMixin],
dependsOn: [SigninMixin, FlowEventsMixin],
events: {
'click #google-login-button': 'googleSignIn',
@ -24,12 +23,6 @@ export default {
this.initializeFlowEvents();
},
setInitialContext(context) {
context.set({
isInThirdPartyAuthExperiment: this.isInThirdPartyAuthExperiment(),
});
},
beforeRender() {
// Check to see if this is a request to deeplink into Google/Apple login
// flow. A bit of a hack but we do a promise to keep our loading indicator on while
@ -53,17 +46,17 @@ export default {
const thirdPartyAuth = Storage.factory('localStorage', this.window).get(
'fxa_third_party_params'
);
// Since this mixin is loaded from multiple views it is possible to have
// a race condition and call complete multiple times. We only want to call it
// on the `enter-email` view.
if (thirdPartyAuth && this.viewName ==='enter-email') {
if (thirdPartyAuth && this.viewName === 'enter-email') {
return this.completeSignIn();
}
if (this.isInThirdPartyAuthExperiment()) {
this.logViewEvent('thirdPartyAuth');
}
// TODO: determine if we want to log this event for all views,
// or not at all since this component is no longer behind an experiment flag
this.logViewEvent('thirdPartyAuth');
},
clearStoredParams() {
@ -107,7 +100,7 @@ export default {
prompt: 'consent',
response_type: 'code',
disallow_webview: true,
ack_webview_shutdown:'2024-09-30'
ack_webview_shutdown: '2024-09-30',
};
/* eslint-enable camelcase */
for (const p in params) {
@ -154,7 +147,7 @@ export default {
access_type: 'offline',
prompt: 'consent',
response_type: 'code id_token',
response_mode: 'form_post'
response_mode: 'form_post',
};
/* eslint-enable camelcase */
for (const p in params) {
@ -201,7 +194,7 @@ export default {
);
const code = authParams.code;
const provider = authParams.provider || 'google';
return this.user
.verifyAccountThirdParty(account, this.relier, code, provider)
.then((updatedAccount) => {
@ -210,12 +203,14 @@ export default {
this.logFlowEvent(`${provider}.signin-complete`);
this.metrics.flush();
// Sync service requires a password to be set before it can be used.
// Note that once a password is set, the user will not have an option to use
// third party login for Sync since it always requires a password.
if (this.relier.isSync()) {
return this.navigate('/post_verify/third_party_auth/set_password', { provider });
return this.navigate('/post_verify/third_party_auth/set_password', {
provider,
});
}
return this.signIn(updatedAccount);

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

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

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

@ -1,59 +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/third-party-auth';
describe('lib/experiments/grouping-rules/third-party-auth', () => {
let experiment;
beforeEach(() => {
experiment = new Experiment();
});
describe('choose', () => {
it('returns false if no relier', () => {
assert.isFalse(
experiment.choose({
experimentGroupingRules: { choose: () => experiment.name },
uniqueUserId: 'user-id',
})
);
});
it('returns false if sync service', () => {
assert.isFalse(
experiment.choose({
experimentGroupingRules: { choose: () => experiment.name },
relier: { isSync: () => true },
uniqueUserId: 'user-id',
})
);
});
it('returns treatment if valid', () => {
const rules = experiment.groups;
assert.isTrue(
rules.include(
experiment.choose({
experimentGroupingRules: { choose: () => experiment.name },
relier: { isSync: () => false },
uniqueUserId: 'user-id',
})
)
);
});
it('returns false if rollout 0%', () => {
experiment.rolloutRate = 0;
assert.isFalse(
experiment.choose({
experimentGroupingRules: { choose: () => experiment.name },
relier: { isSync: () => true },
uniqueUserId: 'user-id',
})
);
});
});
});

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

@ -88,15 +88,6 @@ describe('views/index', () => {
sinon.spy(view, 'replaceCurrentPage');
});
it('renders the firefox-family services copy', () => {
return view.render().then(() => {
assert.include(
view.$(Selectors.FIREFOX_FAMILY_SERVICES).text(),
'A Mozilla account also unlocks access to more privacy-protecting products from Mozilla.'
);
});
});
it('prefills the email with React prefillEmail=email and does not navigate', () => {
const prefillEmail = 'mycoolemail@gmail.com';
relier.set('prefillEmail', prefillEmail);
@ -156,7 +147,7 @@ describe('views/index', () => {
});
describe('current account', () => {
it('replaces current page with to `/settings`', () => {
it('replaces current page with `/settings`', () => {
const signedInAccount = user.initAccount({
sessionToken: 'token',
});
@ -237,33 +228,51 @@ describe('views/index', () => {
});
});
describe('user is in thirdPartyAuth experiment', () => {
beforeEach(() => {
sinon
.stub(view, 'isInThirdPartyAuthExperiment')
.callsFake(() => true);
it('renders third party auth options when not sync', () => {
return view.render().then(() => {
assert.lengthOf(view.$(Selectors.FIREFOX_FAMILY_SERVICES), 0);
assert.lengthOf(view.$(Selectors.THIRD_PARTY_AUTH.GOOGLE), 1);
assert.lengthOf(view.$(Selectors.THIRD_PARTY_AUTH.APPLE), 1);
});
});
it('renders as expected when not sync', () => {
return view.render().then(() => {
assert.lengthOf(view.$(Selectors.FIREFOX_FAMILY_SERVICES), 0);
assert.lengthOf(view.$(Selectors.THIRD_PARTY_AUTH.GOOGLE), 1);
assert.lengthOf(view.$(Selectors.THIRD_PARTY_AUTH.APPLE), 1);
});
it('does not render the firefox-family services copy when not sync', () => {
return view.render().then(() => {
assert.notInclude(
view.$(Selectors.FIREFOX_FAMILY_SERVICES).text(),
'A Mozilla account also unlocks access to more privacy-protecting products from Mozilla.'
);
});
it('renders as expected when sync', () => {
relier.set({
action: 'email',
service: 'sync',
serviceName: 'Firefox Sync',
});
sinon.stub(relier, 'isSync').callsFake(() => true);
});
return view.render().then(() => {
assert.lengthOf(view.$(Selectors.FIREFOX_FAMILY_SERVICES), 1);
assert.lengthOf(view.$(Selectors.THIRD_PARTY_AUTH.GOOGLE), 0);
assert.lengthOf(view.$(Selectors.THIRD_PARTY_AUTH.APPLE), 0);
});
it('does not render third party auth options when sync', () => {
relier.set({
action: 'email',
service: 'sync',
serviceName: 'Firefox Sync',
});
sinon.stub(relier, 'isSync').callsFake(() => true);
return view.render().then(() => {
assert.lengthOf(view.$(Selectors.FIREFOX_FAMILY_SERVICES), 1);
assert.lengthOf(view.$(Selectors.THIRD_PARTY_AUTH.GOOGLE), 0);
assert.lengthOf(view.$(Selectors.THIRD_PARTY_AUTH.APPLE), 0);
});
});
it('renders the firefox-family services copy when sync', () => {
relier.set({
action: 'email',
service: 'sync',
serviceName: 'Firefox Sync',
});
sinon.stub(relier, 'isSync').callsFake(() => true);
return view.render().then(() => {
assert.include(
view.$(Selectors.FIREFOX_FAMILY_SERVICES).text(),
'A Mozilla account also unlocks access to more privacy-protecting products from Mozilla.'
);
});
});
});
@ -521,7 +530,6 @@ describe('views/index', () => {
assert.lengthOf(view.$(Selectors.EMAIL), 1);
assert.include(view.$(Selectors.SUB_HEADER).text(), expectedServiceName);
assert.isTrue(view.chooseEmailActionPage.calledOnce);
assert.lengthOf(view.$(Selectors.FIREFOX_FAMILY_SERVICES), 1);
assert.isTrue(view.logFlowEventOnce.calledOnceWith('begin'));
});

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

@ -78,7 +78,6 @@ describe('views/mixins/third-party-auth-mixin', function () {
user,
});
sinon.spy(notifier, 'trigger');
sinon.stub(view, 'isInThirdPartyAuthExperiment').callsFake(() => true);
await view.render();
});

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

@ -16,14 +16,6 @@ export default {
} as Meta;
export const Default = () => {
return (
<AppLayout>
<Subject enabled showSeparator />
</AppLayout>
);
};
export const Disabled = () => {
return (
<AppLayout>
<Subject showSeparator />
@ -34,7 +26,7 @@ export const Disabled = () => {
export const NoSeparator = () => {
return (
<AppLayout>
<Subject enabled showSeparator={false} />
<Subject showSeparator={false} />
</AppLayout>
);
};

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

@ -14,7 +14,6 @@ import { AUTH_PROVIDER } from 'fxa-auth-client/browser';
import { ReactElement } from 'react-markdown/lib/react-markdown';
export type ThirdPartyAuthProps = {
enabled?: boolean;
onContinueWithGoogle?: FormEventHandler<HTMLFormElement>;
onContinueWithApple?: FormEventHandler<HTMLFormElement>;
showSeparator?: boolean;
@ -26,7 +25,6 @@ export type ThirdPartyAuthProps = {
* It handles user sign-in with the respective provider when the buttons are clicked.
*/
const ThirdPartyAuth = ({
enabled = false,
onContinueWithGoogle,
onContinueWithApple,
showSeparator = true,
@ -44,10 +42,6 @@ const ThirdPartyAuth = ({
}
});
if (!enabled) {
return null;
}
async function completeSignIn() {
try {
const authParams = Storage.factory('localStorage', window).get(

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

@ -167,9 +167,7 @@ const Signin = ({
</div>
</form>
{/* TODO: We will need to pull the enabled flag from feature flags or experiment data
*/}
<ThirdPartyAuth {...{ enabled: false }} />
<ThirdPartyAuth />
<TermsPrivacyAgreement {...{ isPocketClient, isMonitorClient }} />