Skip to content

Commit 4cf3a16

Browse files
committed
tests(e2e): Add session tasks setup MFA environment and corresponding E2E tests
1 parent 8bceaff commit 4cf3a16

File tree

3 files changed

+234
-0
lines changed

3 files changed

+234
-0
lines changed

integration/presets/envs.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,13 @@ const withSessionTasksResetPassword = base
153153
.setEnvVariable('private', 'CLERK_SECRET_KEY', instanceKeys.get('with-session-tasks-reset-password').sk)
154154
.setEnvVariable('public', 'CLERK_PUBLISHABLE_KEY', instanceKeys.get('with-session-tasks-reset-password').pk);
155155

156+
const withSessionTasksSetupMfa = base
157+
.clone()
158+
.setId('withSessionTasksSetupMfa')
159+
.setEnvVariable('private', 'CLERK_SECRET_KEY', instanceKeys.get('with-session-tasks-setup-mfa').sk)
160+
.setEnvVariable('public', 'CLERK_PUBLISHABLE_KEY', instanceKeys.get('with-session-tasks-setup-mfa').pk)
161+
.setEnvVariable('private', 'CLERK_ENCRYPTION_KEY', constants.E2E_CLERK_ENCRYPTION_KEY || 'a-key');
162+
156163
const withBillingJwtV2 = base
157164
.clone()
158165
.setId('withBillingJwtV2')
@@ -210,6 +217,7 @@ export const envs = {
210217
withReverification,
211218
withSessionTasks,
212219
withSessionTasksResetPassword,
220+
withSessionTasksSetupMfa,
213221
withSignInOrUpEmailLinksFlow,
214222
withSignInOrUpFlow,
215223
withSignInOrUpwithRestrictedModeFlow,

integration/presets/longRunningApps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const createLongRunningApps = () => {
3131
{ id: 'next.appRouter.withSignInOrUpEmailLinksFlow', config: next.appRouter, env: envs.withSignInOrUpEmailLinksFlow },
3232
{ id: 'next.appRouter.withSessionTasks', config: next.appRouter, env: envs.withSessionTasks },
3333
{ id: 'next.appRouter.withSessionTasksResetPassword', config: next.appRouter, env: envs.withSessionTasksResetPassword },
34+
{ id: 'next.appRouter.withSessionTasksSetupMfa', config: next.appRouter, env: envs.withSessionTasksSetupMfa },
3435
{ id: 'next.appRouter.withLegalConsent', config: next.appRouter, env: envs.withLegalConsent },
3536
{ id: 'next.appRouter.withNeedsClientTrust', config: next.appRouter, env: envs.withNeedsClientTrust },
3637

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
import { expect, test } from '@playwright/test';
2+
3+
import { appConfigs } from '../presets';
4+
import { createTestUtils, testAgainstRunningApps } from '../testUtils';
5+
import { stringPhoneNumber } from '../testUtils/phoneUtils';
6+
7+
testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasksSetupMfa] })(
8+
'session tasks setup-mfa flow @nextjs',
9+
({ app }) => {
10+
test.describe.configure({ mode: 'parallel' });
11+
12+
test.afterAll(async () => {
13+
const u = createTestUtils({ app });
14+
await u.services.organizations.deleteAll();
15+
await app.teardown();
16+
});
17+
18+
test.afterEach(async ({ page, context }) => {
19+
const u = createTestUtils({ app, page, context });
20+
await u.page.signOut();
21+
await u.page.context().clearCookies();
22+
});
23+
24+
test('setup MFA with new phone number - happy path', async ({ page, context }) => {
25+
const u = createTestUtils({ app, page, context });
26+
const user = u.services.users.createFakeUser({
27+
fictionalEmail: true,
28+
withPassword: true,
29+
});
30+
await u.services.users.createBapiUser(user);
31+
32+
await u.po.signIn.goTo();
33+
await u.po.signIn.waitForMounted();
34+
await u.po.signIn.signInWithEmailAndInstantPassword({ email: user.email, password: user.password });
35+
await u.po.expect.toBeSignedIn();
36+
37+
await u.page.goToRelative('/page-protected');
38+
39+
await u.page.getByText(/set up two-step verification/i).waitFor({ state: 'visible' });
40+
41+
await u.page.getByRole('button', { name: /sms code/i }).click();
42+
43+
await u.page.getByRole('button', { name: /use a different phone number/i }).click();
44+
45+
const testPhoneNumber = '+15555550100';
46+
await u.page.getByLabel(/phone number/i).fill(testPhoneNumber);
47+
await u.page.getByRole('button', { name: /continue/i }).click();
48+
49+
await u.page.getByLabel(/enter code/i).waitFor({ state: 'visible' });
50+
await u.page.getByLabel(/enter code/i).fill('424242');
51+
52+
await u.page.getByText(/backup codes/i).waitFor({ state: 'visible', timeout: 10000 });
53+
await u.page.getByText(/save these codes/i).waitFor({ state: 'visible' });
54+
55+
await u.page.getByRole('button', { name: /finish/i }).click();
56+
57+
await u.page.waitForAppUrl('/page-protected');
58+
await u.po.expect.toBeSignedIn();
59+
60+
await user.deleteIfExists();
61+
});
62+
63+
test('setup MFA with existing phone number - happy path', async ({ page, context }) => {
64+
const u = createTestUtils({ app, page, context });
65+
const user = u.services.users.createFakeUser({
66+
fictionalEmail: true,
67+
withPhoneNumber: true,
68+
withPassword: true,
69+
});
70+
await u.services.users.createBapiUser(user);
71+
72+
await u.po.signIn.goTo();
73+
await u.po.signIn.waitForMounted();
74+
await u.po.signIn.signInWithEmailAndInstantPassword({ email: user.email, password: user.password });
75+
await u.po.expect.toBeSignedIn();
76+
77+
await u.page.goToRelative('/page-protected');
78+
79+
await u.page.getByText(/set up two-step verification/i).waitFor({ state: 'visible' });
80+
81+
await u.page.getByRole('button', { name: /sms code/i }).click();
82+
83+
const formattedPhoneNumber = stringPhoneNumber(user.phoneNumber);
84+
await u.page
85+
.getByRole('button', {
86+
name: formattedPhoneNumber,
87+
})
88+
.click();
89+
90+
await u.page.getByLabel(/enter code/i).waitFor({ state: 'visible' });
91+
await u.page.getByLabel(/enter code/i).fill('424242');
92+
93+
await u.page.getByText(/backup codes/i).waitFor({ state: 'visible', timeout: 10000 });
94+
await u.page.getByText(/save these codes/i).waitFor({ state: 'visible' });
95+
96+
await u.page.getByRole('button', { name: /finish/i }).click();
97+
98+
await u.page.waitForAppUrl('/page-protected');
99+
await u.po.expect.toBeSignedIn();
100+
101+
await user.deleteIfExists();
102+
});
103+
104+
test('setup MFA with invalid phone number - error handling', async ({ page, context }) => {
105+
const u = createTestUtils({ app, page, context });
106+
const user = u.services.users.createFakeUser({
107+
fictionalEmail: true,
108+
withPassword: true,
109+
});
110+
await u.services.users.createBapiUser(user);
111+
112+
await u.po.signIn.goTo();
113+
await u.po.signIn.waitForMounted();
114+
await u.po.signIn.signInWithEmailAndInstantPassword({ email: user.email, password: user.password });
115+
await u.po.expect.toBeSignedIn();
116+
117+
await u.page.goToRelative('/page-protected');
118+
119+
await u.page.getByText(/set up two-step verification/i).waitFor({ state: 'visible' });
120+
121+
await u.page.getByRole('button', { name: /sms code/i }).click();
122+
123+
await u.page.getByRole('button', { name: /use a different phone number/i }).click();
124+
125+
const invalidPhoneNumber = '123';
126+
await u.page.getByLabel(/phone number/i).fill(invalidPhoneNumber);
127+
await u.page.getByRole('button', { name: /continue/i }).click();
128+
129+
await expect(u.page.getByText(/is invalid/i)).toBeVisible();
130+
131+
const validPhoneNumber = '+15555550100';
132+
await u.page.getByLabel(/phone number/i).fill(validPhoneNumber);
133+
await u.page.getByRole('button', { name: /continue/i }).click();
134+
135+
await u.page.getByLabel(/enter code/i).waitFor({ state: 'visible' });
136+
await u.page.getByLabel(/enter code/i).fill('424242');
137+
138+
await u.page.getByText(/backup codes/i).waitFor({ state: 'visible', timeout: 10000 });
139+
140+
await u.page.getByRole('button', { name: /finish/i }).click();
141+
142+
await u.page.waitForAppUrl('/page-protected');
143+
144+
await user.deleteIfExists();
145+
});
146+
147+
test('setup MFA with invalid verification code - error handling', async ({ page, context }) => {
148+
const u = createTestUtils({ app, page, context });
149+
const user = u.services.users.createFakeUser({
150+
fictionalEmail: true,
151+
withPassword: true,
152+
});
153+
await u.services.users.createBapiUser(user);
154+
155+
await u.po.signIn.goTo();
156+
await u.po.signIn.waitForMounted();
157+
await u.po.signIn.signInWithEmailAndInstantPassword({ email: user.email, password: user.password });
158+
await u.po.expect.toBeSignedIn();
159+
160+
await u.page.goToRelative('/page-protected');
161+
162+
await u.page.getByText(/set up two-step verification/i).waitFor({ state: 'visible' });
163+
164+
await u.page.getByRole('button', { name: /sms code/i }).click();
165+
166+
await u.page.getByRole('button', { name: /use a different phone number/i }).click();
167+
168+
const testPhoneNumber = '+15555550100';
169+
await u.page.getByLabel(/phone number/i).fill(testPhoneNumber);
170+
await u.page.getByRole('button', { name: /continue/i }).click();
171+
172+
await u.page.getByLabel(/enter code/i).waitFor({ state: 'visible' });
173+
await u.page.getByLabel(/enter code/i).fill('111111');
174+
175+
await expect(u.page.getByText(/incorrect/i)).toBeVisible();
176+
177+
await u.page.getByLabel(/enter code/i).fill('424242');
178+
179+
await u.page.getByText(/backup codes/i).waitFor({ state: 'visible', timeout: 10000 });
180+
await u.page.getByText(/save these codes/i).waitFor({ state: 'visible' });
181+
182+
await u.page.getByRole('button', { name: /finish/i }).click();
183+
184+
await u.page.waitForAppUrl('/page-protected');
185+
await u.po.expect.toBeSignedIn();
186+
187+
await user.deleteIfExists();
188+
});
189+
190+
test('can navigate back during MFA setup', async ({ page, context }) => {
191+
const u = createTestUtils({ app, page, context });
192+
const user = u.services.users.createFakeUser({
193+
fictionalEmail: true,
194+
withPhoneNumber: true,
195+
withPassword: true,
196+
});
197+
await u.services.users.createBapiUser(user);
198+
199+
await u.po.signIn.goTo();
200+
await u.po.signIn.waitForMounted();
201+
await u.po.signIn.signInWithEmailAndInstantPassword({ email: user.email, password: user.password });
202+
await u.po.expect.toBeSignedIn();
203+
204+
await u.page.goToRelative('/page-protected');
205+
206+
await u.page.getByText(/set up two-step verification/i).waitFor({ state: 'visible' });
207+
208+
await u.page.getByRole('button', { name: /sms code/i }).click();
209+
210+
const formattedPhoneNumber = stringPhoneNumber(user.phoneNumber);
211+
await u.page
212+
.getByRole('button', {
213+
name: formattedPhoneNumber,
214+
})
215+
.waitFor({ state: 'visible' });
216+
217+
await u.page.getByRole('link', { name: /back/i }).first().click();
218+
219+
await u.page.getByText(/set up two-step verification/i).waitFor({ state: 'visible' });
220+
await u.page.getByRole('button', { name: /sms code/i }).waitFor({ state: 'visible' });
221+
222+
await user.deleteIfExists();
223+
});
224+
},
225+
);

0 commit comments

Comments
 (0)