Skip to content

Commit

Permalink
chore(abtest): set up test for passcodes to 10% of audience
Browse files Browse the repository at this point in the history
  • Loading branch information
coldlink committed Jan 13, 2025
1 parent 64e74a2 commit 68c378a
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 7 deletions.
19 changes: 16 additions & 3 deletions src/client/pages/SignInPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { SignIn } from '@/client/pages/SignIn';
import useClientState from '@/client/lib/hooks/useClientState';
import { useRemoveEncryptedEmailParam } from '@/client/lib/hooks/useRemoveEncryptedEmailParam';
import { useAB } from '@/client/components/ABReact';

interface Props {
isReauthenticate?: boolean;
Expand All @@ -14,6 +15,7 @@ export const SignInPage = ({
hideSocialButtons = false,
forcePasswordPage = false,
}: Props) => {
const ABTestAPI = useAB();
const clientState = useClientState();
const {
pageData = {},
Expand All @@ -27,6 +29,19 @@ export const SignInPage = ({

// we use the encryptedEmail parameter to pre-fill the email field, but then want to remove it from the url
useRemoveEncryptedEmailParam();

const usePasscodeSignIn: boolean = (() => {
if (forcePasswordPage) {
return false;
}

if (ABTestAPI.isUserInVariant('PasscodeSignInTest', 'variant')) {
return true;
}

return !!queryParams.usePasscodeSignIn;
})();

return (
<SignIn
email={email}
Expand All @@ -36,9 +51,7 @@ export const SignInPage = ({
recaptchaSiteKey={recaptchaSiteKey}
isReauthenticate={isReauthenticate}
shortRequestId={clientState.shortRequestId}
usePasscodeSignIn={
forcePasswordPage ? false : queryParams.usePasscodeSignIn
}
usePasscodeSignIn={usePasscodeSignIn}
hideSocialButtons={hideSocialButtons}
/>
);
Expand Down
8 changes: 6 additions & 2 deletions src/server/controllers/signInControllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,14 @@ export const oktaIdxApiSignInController = async ({
// get the email and password from the request body
const { email = '', password = '', passcode } = req.body;

const usePasscodeSignInFlag =
res.locals.queryParams.usePasscodeSignIn ||
res.locals.abTestAPI.isUserInVariant('PasscodeSignInTest', 'variant');

try {
// only attempt to sign in with a passcode if the user currently has the query parameter set
// this should be removed when we're ready to enable this for all users
if (res.locals.queryParams.usePasscodeSignIn) {
if (usePasscodeSignInFlag) {
// if the value exists, we're using passcodes
const usePasscode = !!passcode;

Expand Down Expand Up @@ -588,7 +592,7 @@ export const oktaIdxApiSignInController = async ({

// if we're using passcodes, and the user is attempting to sign in with a password
// on error show the password sign in page
const errorPage: RoutePaths = res.locals.queryParams.usePasscodeSignIn
const errorPage: RoutePaths = usePasscodeSignInFlag
? '/signin/password'
: '/signin';

Expand Down
2 changes: 1 addition & 1 deletion src/shared/model/QueryParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export interface PersistableQueryParams
appClientId?: string;
// fallback to Okta Classic if needed
useOktaClassic?: boolean;
// Flag to enable sign in with passcode
// Flag to force enable sign in with passcode
usePasscodeSignIn?: boolean;
}

Expand Down
1 change: 1 addition & 0 deletions src/shared/model/experiments/abSwitches.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const abSwitches = {
abExampleTest: false,
abPasscodeSignInTest: true,
};
3 changes: 2 additions & 1 deletion src/shared/model/experiments/abTests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AB, ABTest, Participations } from '@guardian/ab-core';
import { abSwitches } from './abSwitches';
import { passcodeSignInTest } from './tests/passcode-signin-test';

interface ABTestConfiguration {
abTestSwitches: Record<string, boolean>;
Expand All @@ -9,7 +10,7 @@ interface ABTestConfiguration {
}

// Add AB tests to run in this array
export const tests: ABTest[] = [];
export const tests: ABTest[] = [passcodeSignInTest];

const getDefaultABTestConfiguration = (): ABTestConfiguration => ({
abTestSwitches: abSwitches,
Expand Down
25 changes: 25 additions & 0 deletions src/shared/model/experiments/tests/passcode-signin-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ABTest } from '@guardian/ab-core';

export const passcodeSignInTest: ABTest = {
id: 'PasscodeSignInTest', // This ID must match the Server Side AB Test
start: '2025-01-13',
expiry: '2025-01-31', // Remember that the server side test expiry can be different
author: '[email protected]',
description:
'Testing the release of one time passcodes as the default sign in option',
audience: 0.1, // 10% (1 is 100%)
audienceOffset: 0, // 0% (1 is 100%). Prevent overlapping with other tests.
successMeasure: 'Users sign in successfully with passcodes',
audienceCriteria: 'Everyone',
idealOutcome: 'Users sign in successfully with passcodes',
showForSensitive: true, // Should this A/B test run on sensitive articles?
canRun: () => true, // Check for things like user or page sections
variants: [
{
id: 'variant',
test: (): string => {
return 'variant';
},
},
],
};

0 comments on commit 68c378a

Please sign in to comment.