@workos-inc/authkit-nextjs 2.13.0 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,25 +3,25 @@ import { render, waitFor } from '@testing-library/react';
3
3
  import React from 'react';
4
4
  import { useAuth } from './authkit-provider.js';
5
5
 
6
- jest.mock('../actions.js', () => ({
7
- getAccessTokenAction: jest.fn(),
8
- refreshAccessTokenAction: jest.fn(),
6
+ vi.mock('../actions.js', () => ({
7
+ getAccessTokenAction: vi.fn(),
8
+ refreshAccessTokenAction: vi.fn(),
9
9
  }));
10
10
 
11
- jest.mock('./authkit-provider.js', () => {
12
- const originalModule = jest.requireActual('./authkit-provider.js');
11
+ vi.mock('./authkit-provider.js', async () => {
12
+ const originalModule = await vi.importActual<typeof import('./authkit-provider.js')>('./authkit-provider.js');
13
13
  return {
14
14
  ...originalModule,
15
- useAuth: jest.fn(),
15
+ useAuth: vi.fn(),
16
16
  };
17
17
  });
18
18
 
19
- jest.mock('./useAccessToken.js', () => ({
20
- useAccessToken: jest.fn(() => ({ accessToken: undefined })),
19
+ vi.mock('./useAccessToken.js', () => ({
20
+ useAccessToken: vi.fn(() => ({ accessToken: undefined })),
21
21
  }));
22
22
 
23
- jest.mock('jose', () => ({
24
- decodeJwt: jest.fn((token: string) => {
23
+ vi.mock('jose', () => ({
24
+ decodeJwt: vi.fn((token: string) => {
25
25
  if (token === 'malformed-token' || token === 'throw-error-token') {
26
26
  throw new Error('Invalid JWT');
27
27
  }
@@ -42,21 +42,21 @@ import { useTokenClaims } from './useTokenClaims.js';
42
42
 
43
43
  describe('useTokenClaims', () => {
44
44
  beforeEach(() => {
45
- jest.clearAllMocks();
46
- jest.useFakeTimers();
45
+ vi.clearAllMocks();
46
+ vi.useFakeTimers({ shouldAdvanceTime: true });
47
47
 
48
- (useAuth as jest.Mock).mockImplementation(() => ({
48
+ (useAuth as Mock).mockImplementation(() => ({
49
49
  user: { id: 'user_123' },
50
50
  sessionId: 'session_123',
51
- refreshAuth: jest.fn().mockResolvedValue({}),
51
+ refreshAuth: vi.fn().mockResolvedValue({}),
52
52
  }));
53
53
 
54
54
  // Reset useAccessToken mock to default
55
- (useAccessToken as jest.Mock).mockReturnValue({ accessToken: undefined });
55
+ (useAccessToken as Mock).mockReturnValue({ accessToken: undefined });
56
56
  });
57
57
 
58
58
  afterEach(() => {
59
- jest.useRealTimers();
59
+ vi.useRealTimers();
60
60
  });
61
61
 
62
62
  const TokenClaimsTestComponent = () => {
@@ -69,7 +69,7 @@ describe('useTokenClaims', () => {
69
69
  };
70
70
 
71
71
  it('should return empty object when no access token is available', async () => {
72
- (useAccessToken as jest.Mock).mockReturnValue({ accessToken: undefined });
72
+ (useAccessToken as Mock).mockReturnValue({ accessToken: undefined });
73
73
 
74
74
  const { getByTestId } = render(<TokenClaimsTestComponent />);
75
75
 
@@ -101,7 +101,7 @@ describe('useTokenClaims', () => {
101
101
  };
102
102
  const token = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.${btoa(JSON.stringify(payload))}.mock-signature`;
103
103
 
104
- (useAccessToken as jest.Mock).mockReturnValue({ accessToken: token });
104
+ (useAccessToken as Mock).mockReturnValue({ accessToken: token });
105
105
 
106
106
  const { getByTestId } = render(<TokenClaimsTestComponent />);
107
107
 
@@ -129,7 +129,7 @@ describe('useTokenClaims', () => {
129
129
  };
130
130
  const token = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.${btoa(JSON.stringify(payload))}.mock-signature`;
131
131
 
132
- (useAccessToken as jest.Mock).mockReturnValue({ accessToken: token });
132
+ (useAccessToken as Mock).mockReturnValue({ accessToken: token });
133
133
 
134
134
  const { getByTestId } = render(<TokenClaimsTestComponent />);
135
135
 
@@ -147,7 +147,7 @@ describe('useTokenClaims', () => {
147
147
  };
148
148
  const token = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.${btoa(JSON.stringify(payload))}.mock-signature`;
149
149
 
150
- (useAccessToken as jest.Mock).mockReturnValue({ accessToken: token });
150
+ (useAccessToken as Mock).mockReturnValue({ accessToken: token });
151
151
 
152
152
  const { getByTestId } = render(<TokenClaimsTestComponent />);
153
153
 
@@ -175,7 +175,7 @@ describe('useTokenClaims', () => {
175
175
  };
176
176
  const token = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.${btoa(JSON.stringify(payload))}.mock-signature`;
177
177
 
178
- (useAccessToken as jest.Mock).mockReturnValue({ accessToken: token });
178
+ (useAccessToken as Mock).mockReturnValue({ accessToken: token });
179
179
 
180
180
  const { getByTestId } = render(<TokenClaimsTestComponent />);
181
181
 
@@ -185,7 +185,7 @@ describe('useTokenClaims', () => {
185
185
  });
186
186
 
187
187
  it('should return empty object when decodeJwt throws an error', async () => {
188
- (useAccessToken as jest.Mock).mockReturnValue({ accessToken: 'malformed-token' });
188
+ (useAccessToken as Mock).mockReturnValue({ accessToken: 'malformed-token' });
189
189
 
190
190
  const { getByTestId } = render(<TokenClaimsTestComponent />);
191
191
 
@@ -1,14 +1,13 @@
1
- import { describe, it, expect } from '@jest/globals';
2
-
3
- // Mock at the top of the file
4
- jest.mock('./env-variables');
5
-
6
1
  describe('cookie.ts', () => {
7
2
  beforeEach(() => {
8
3
  // Clear all mocks before each test
9
- jest.clearAllMocks();
10
- // Reset modules
11
- jest.resetModules();
4
+ vi.clearAllMocks();
5
+ // Reset modules to ensure fresh imports
6
+ vi.resetModules();
7
+ // Re-mock env-variables with a fresh copy each time
8
+ vi.doMock('./env-variables', async (importOriginal) => {
9
+ return { ...(await importOriginal<typeof import('./env-variables')>()) };
10
+ });
12
11
  });
13
12
 
14
13
  describe('getCookieOptions', () => {
@@ -1,25 +1,24 @@
1
- import { describe, it, expect, beforeEach, jest } from '@jest/globals';
2
1
  import { getAuthorizationUrl } from './get-authorization-url.js';
3
2
  import { headers } from 'next/headers';
4
3
  import { getWorkOS } from './workos.js';
5
4
 
6
- jest.mock('next/headers');
7
-
8
5
  // Mock dependencies
9
- const fakeWorkosInstance = {
10
- userManagement: {
11
- getAuthorizationUrl: jest.fn(),
6
+ const { fakeWorkosInstance } = vi.hoisted(() => ({
7
+ fakeWorkosInstance: {
8
+ userManagement: {
9
+ getAuthorizationUrl: vi.fn(),
10
+ },
12
11
  },
13
- };
12
+ }));
14
13
 
15
- jest.mock('./workos', () => ({
16
- getWorkOS: jest.fn(() => fakeWorkosInstance),
14
+ vi.mock('./workos', () => ({
15
+ getWorkOS: vi.fn(() => fakeWorkosInstance),
17
16
  }));
18
17
 
19
18
  describe('getAuthorizationUrl', () => {
20
19
  const workos = getWorkOS();
21
20
  beforeEach(() => {
22
- jest.clearAllMocks();
21
+ vi.clearAllMocks();
23
22
  });
24
23
 
25
24
  it('uses x-redirect-uri header when redirectUri option is not provided', async () => {
@@ -27,7 +26,7 @@ describe('getAuthorizationUrl', () => {
27
26
  nextHeaders.set('x-redirect-uri', 'http://test-redirect.com');
28
27
 
29
28
  // Mock workos.userManagement.getAuthorizationUrl
30
- jest.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
29
+ vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
31
30
 
32
31
  await getAuthorizationUrl({});
33
32
 
@@ -39,7 +38,7 @@ describe('getAuthorizationUrl', () => {
39
38
  });
40
39
 
41
40
  it('works when called with no arguments', async () => {
42
- jest.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
41
+ vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
43
42
 
44
43
  await getAuthorizationUrl(); // Call with no arguments
45
44
 
@@ -47,7 +46,7 @@ describe('getAuthorizationUrl', () => {
47
46
  });
48
47
 
49
48
  it('works when prompt is provided', async () => {
50
- jest.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
49
+ vi.mocked(workos.userManagement.getAuthorizationUrl).mockReturnValue('mock-url');
51
50
 
52
51
  await getAuthorizationUrl({ prompt: 'consent' });
53
52
 
@@ -10,12 +10,15 @@ import { jwtVerify } from 'jose';
10
10
  import { sealData } from 'iron-session';
11
11
  import { User } from '@workos-inc/node';
12
12
 
13
- jest.mock('jose', () => ({
14
- jwtVerify: jest.fn(),
15
- createRemoteJWKSet: jest.fn(),
16
- SignJWT: jest.requireActual('jose').SignJWT,
17
- decodeJwt: jest.requireActual('jose').decodeJwt,
18
- }));
13
+ vi.mock('jose', async () => {
14
+ const actual = await vi.importActual<typeof import('jose')>('jose');
15
+ return {
16
+ jwtVerify: vi.fn(),
17
+ createRemoteJWKSet: vi.fn(),
18
+ SignJWT: actual.SignJWT,
19
+ decodeJwt: actual.decodeJwt,
20
+ };
21
+ });
19
22
 
20
23
  // logging is disabled by default, flip this to true to still have logs in the console
21
24
  const DEBUG = false;
@@ -47,11 +50,11 @@ describe('session.ts', () => {
47
50
  } as User,
48
51
  };
49
52
 
50
- let consoleLogSpy: jest.SpyInstance;
53
+ let consoleLogSpy: MockInstance;
51
54
 
52
55
  beforeEach(async () => {
53
56
  // Clear all mocks between tests
54
- jest.clearAllMocks();
57
+ vi.clearAllMocks();
55
58
 
56
59
  // Reset the cookie store
57
60
  const nextCookies = await cookies();
@@ -63,9 +66,9 @@ describe('session.ts', () => {
63
66
  nextHeaders._reset();
64
67
  nextHeaders.set('x-workos-middleware', 'true');
65
68
 
66
- (jwtVerify as jest.Mock).mockReset();
69
+ (jwtVerify as Mock).mockReset();
67
70
 
68
- consoleLogSpy = jest.spyOn(console, 'log').mockImplementation((...args) => {
71
+ consoleLogSpy = vi.spyOn(console, 'log').mockImplementation((...args) => {
69
72
  if (DEBUG) {
70
73
  console.info(...args);
71
74
  }
@@ -74,7 +77,7 @@ describe('session.ts', () => {
74
77
 
75
78
  afterEach(() => {
76
79
  consoleLogSpy.mockRestore();
77
- jest.resetModules();
80
+ vi.resetModules();
78
81
  });
79
82
 
80
83
  describe('withAuth', () => {
@@ -159,7 +162,7 @@ describe('session.ts', () => {
159
162
  it('should throw an error if the redirect URI is not set', async () => {
160
163
  const originalWorkosRedirectUri = envVariables.WORKOS_REDIRECT_URI;
161
164
 
162
- jest.replaceProperty(envVariables, 'WORKOS_REDIRECT_URI', '');
165
+ Object.defineProperty(envVariables, 'WORKOS_REDIRECT_URI', { value: '', configurable: true });
163
166
 
164
167
  await expect(async () => {
165
168
  await updateSessionMiddleware(
@@ -174,13 +177,16 @@ describe('session.ts', () => {
174
177
  );
175
178
  }).rejects.toThrow('You must provide a redirect URI in the AuthKit middleware or in the environment variables.');
176
179
 
177
- jest.replaceProperty(envVariables, 'WORKOS_REDIRECT_URI', originalWorkosRedirectUri);
180
+ Object.defineProperty(envVariables, 'WORKOS_REDIRECT_URI', {
181
+ value: originalWorkosRedirectUri,
182
+ configurable: true,
183
+ });
178
184
  });
179
185
 
180
186
  it('should throw an error if the cookie password is not set', async () => {
181
187
  const originalWorkosCookiePassword = envVariables.WORKOS_COOKIE_PASSWORD;
182
188
 
183
- jest.replaceProperty(envVariables, 'WORKOS_COOKIE_PASSWORD', '');
189
+ Object.defineProperty(envVariables, 'WORKOS_COOKIE_PASSWORD', { value: '', configurable: true });
184
190
 
185
191
  await expect(async () => {
186
192
  await updateSessionMiddleware(
@@ -197,13 +203,16 @@ describe('session.ts', () => {
197
203
  'You must provide a valid cookie password that is at least 32 characters in the environment variables.',
198
204
  );
199
205
 
200
- jest.replaceProperty(envVariables, 'WORKOS_COOKIE_PASSWORD', originalWorkosCookiePassword);
206
+ Object.defineProperty(envVariables, 'WORKOS_COOKIE_PASSWORD', {
207
+ value: originalWorkosCookiePassword,
208
+ configurable: true,
209
+ });
201
210
  });
202
211
 
203
212
  it('should throw an error if the cookie password is less than 32 characters', async () => {
204
213
  const originalWorkosCookiePassword = envVariables.WORKOS_COOKIE_PASSWORD;
205
214
 
206
- jest.replaceProperty(envVariables, 'WORKOS_COOKIE_PASSWORD', 'short');
215
+ Object.defineProperty(envVariables, 'WORKOS_COOKIE_PASSWORD', { value: 'short', configurable: true });
207
216
 
208
217
  await expect(async () => {
209
218
  await updateSessionMiddleware(
@@ -220,7 +229,10 @@ describe('session.ts', () => {
220
229
  'You must provide a valid cookie password that is at least 32 characters in the environment variables.',
221
230
  );
222
231
 
223
- jest.replaceProperty(envVariables, 'WORKOS_COOKIE_PASSWORD', originalWorkosCookiePassword);
232
+ Object.defineProperty(envVariables, 'WORKOS_COOKIE_PASSWORD', {
233
+ value: originalWorkosCookiePassword,
234
+ configurable: true,
235
+ });
224
236
  });
225
237
 
226
238
  it('should return early if there is no session', async () => {
@@ -241,7 +253,7 @@ describe('session.ts', () => {
241
253
  });
242
254
 
243
255
  it('should return 200 if the session is valid', async () => {
244
- jest.spyOn(console, 'log').mockImplementation(() => {});
256
+ vi.spyOn(console, 'log').mockImplementation(() => {});
245
257
 
246
258
  const nextCookies = await cookies();
247
259
  nextCookies.set(
@@ -249,7 +261,7 @@ describe('session.ts', () => {
249
261
  await sealData(mockSession, { password: process.env.WORKOS_COOKIE_PASSWORD as string }),
250
262
  );
251
263
 
252
- (jwtVerify as jest.Mock).mockImplementation(() => {
264
+ (jwtVerify as Mock).mockImplementation(() => {
253
265
  return true;
254
266
  });
255
267
 
@@ -272,11 +284,11 @@ describe('session.ts', () => {
272
284
  it('should attempt to refresh the session when the access token is invalid', async () => {
273
285
  mockSession.accessToken = await generateTestToken({}, true);
274
286
 
275
- (jwtVerify as jest.Mock).mockImplementation(() => {
287
+ (jwtVerify as Mock).mockImplementation(() => {
276
288
  throw new Error('Invalid token');
277
289
  });
278
290
 
279
- jest.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
291
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
280
292
  accessToken: await generateTestToken(),
281
293
  refreshToken: 'new-refresh-token',
282
294
  user: mockSession.user,
@@ -308,17 +320,15 @@ describe('session.ts', () => {
308
320
  });
309
321
 
310
322
  it('should delete the cookie when refreshing fails', async () => {
311
- jest.spyOn(console, 'log').mockImplementation(() => {});
323
+ vi.spyOn(console, 'log').mockImplementation(() => {});
312
324
 
313
325
  mockSession.accessToken = await generateTestToken({}, true);
314
326
 
315
- (jwtVerify as jest.Mock).mockImplementation(() => {
327
+ (jwtVerify as Mock).mockImplementation(() => {
316
328
  throw new Error('Invalid token');
317
329
  });
318
330
 
319
- jest
320
- .spyOn(workos.userManagement, 'authenticateWithRefreshToken')
321
- .mockRejectedValue(new Error('Failed to refresh'));
331
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue(new Error('Failed to refresh'));
322
332
 
323
333
  const request = new NextRequest(new URL('http://example.com'));
324
334
 
@@ -354,7 +364,7 @@ describe('session.ts', () => {
354
364
 
355
365
  describe('middleware auth', () => {
356
366
  it('should redirect unauthenticated users on protected routes', async () => {
357
- jest.spyOn(console, 'log').mockImplementation(() => {});
367
+ vi.spyOn(console, 'log').mockImplementation(() => {});
358
368
 
359
369
  const request = new NextRequest(new URL('http://example.com/protected'));
360
370
  const result = await updateSessionMiddleware(
@@ -476,11 +486,11 @@ describe('session.ts', () => {
476
486
 
477
487
  it('should throw an error if the provided regex is invalid and a non-Error object is thrown', async () => {
478
488
  // Reset modules to ensure clean import state
479
- jest.resetModules();
489
+ vi.resetModules();
480
490
 
481
491
  // Import first, then spy
482
492
  const pathToRegexp = await import('path-to-regexp');
483
- const parseSpy = jest.spyOn(pathToRegexp, 'parse').mockImplementation(() => {
493
+ const parseSpy = vi.spyOn(pathToRegexp, 'parse').mockImplementation(() => {
484
494
  throw 'invalid regex';
485
495
  });
486
496
 
@@ -504,6 +514,9 @@ describe('session.ts', () => {
504
514
 
505
515
  // Verify the mock was called
506
516
  expect(parseSpy).toHaveBeenCalled();
517
+
518
+ // Restore the spy to prevent leaking to subsequent tests
519
+ parseSpy.mockRestore();
507
520
  });
508
521
 
509
522
  it('should default to the WORKOS_REDIRECT_URI environment variable if no redirect URI is provided', async () => {
@@ -523,17 +536,17 @@ describe('session.ts', () => {
523
536
  });
524
537
 
525
538
  it('should delete the cookie and redirect when refreshing fails', async () => {
526
- jest.spyOn(console, 'log').mockImplementation(() => {});
539
+ vi.spyOn(console, 'log').mockImplementation(() => {});
527
540
 
528
541
  mockSession.accessToken = await generateTestToken({}, true);
529
542
 
530
- (jwtVerify as jest.Mock).mockImplementation(() => {
543
+ (jwtVerify as Mock).mockImplementation(() => {
531
544
  throw new Error('Invalid token');
532
545
  });
533
546
 
534
- jest
535
- .spyOn(workos.userManagement, 'authenticateWithRefreshToken')
536
- .mockRejectedValue(new Error('Failed to refresh'));
547
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue(
548
+ new Error('Failed to refresh'),
549
+ );
537
550
 
538
551
  const request = new NextRequest(new URL('http://example.com'));
539
552
 
@@ -634,12 +647,12 @@ describe('session.ts', () => {
634
647
  mockSession.accessToken = await generateTestToken({}, true);
635
648
 
636
649
  // Mock token verification to fail
637
- (jwtVerify as jest.Mock).mockImplementation(() => {
650
+ (jwtVerify as Mock).mockImplementation(() => {
638
651
  throw new Error('Invalid token');
639
652
  });
640
653
 
641
654
  // Mock successful refresh
642
- jest.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
655
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
643
656
  accessToken: await generateTestToken(),
644
657
  refreshToken: 'new-refresh-token',
645
658
  user: mockSession.user,
@@ -667,12 +680,12 @@ describe('session.ts', () => {
667
680
  mockSession.accessToken = await generateTestToken({}, true);
668
681
 
669
682
  // Mock token verification to fail
670
- (jwtVerify as jest.Mock).mockImplementation(() => {
683
+ (jwtVerify as Mock).mockImplementation(() => {
671
684
  throw new Error('Invalid token');
672
685
  });
673
686
 
674
687
  // Mock refresh failure
675
- jest.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue(new Error('Refresh failed'));
688
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue(new Error('Refresh failed'));
676
689
 
677
690
  const request = new NextRequest(new URL('http://example.com/protected'));
678
691
  request.cookies.set(
@@ -694,15 +707,15 @@ describe('session.ts', () => {
694
707
  mockSession.accessToken = await generateTestToken({}, true);
695
708
 
696
709
  // Mock token verification to fail
697
- (jwtVerify as jest.Mock).mockImplementation(() => {
710
+ (jwtVerify as Mock).mockImplementation(() => {
698
711
  throw new Error('Invalid token');
699
712
  });
700
713
 
701
714
  const newAccessToken = await generateTestToken();
702
- const mockSuccessCallback = jest.fn();
715
+ const mockSuccessCallback = vi.fn();
703
716
 
704
717
  // Mock successful refresh
705
- jest.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
718
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
706
719
  accessToken: newAccessToken,
707
720
  refreshToken: 'new-refresh-token',
708
721
  user: mockSession.user,
@@ -733,15 +746,15 @@ describe('session.ts', () => {
733
746
  mockSession.accessToken = await generateTestToken({}, true);
734
747
 
735
748
  // Mock token verification to fail
736
- (jwtVerify as jest.Mock).mockImplementation(() => {
749
+ (jwtVerify as Mock).mockImplementation(() => {
737
750
  throw new Error('Invalid token');
738
751
  });
739
752
 
740
753
  const mockError = new Error('Refresh failed');
741
- const mockErrorCallback = jest.fn();
754
+ const mockErrorCallback = vi.fn();
742
755
 
743
756
  // Mock refresh failure
744
- jest.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue(mockError);
757
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue(mockError);
745
758
 
746
759
  const request = new NextRequest(new URL('http://example.com/protected'));
747
760
  request.cookies.set(
@@ -764,15 +777,15 @@ describe('session.ts', () => {
764
777
 
765
778
  describe('refreshSession', () => {
766
779
  it('should refresh session successfully', async () => {
767
- jest.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
780
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
768
781
  accessToken: await generateTestToken(),
769
782
  refreshToken: 'new-refresh-token',
770
783
  user: mockSession.user,
771
784
  });
772
785
 
773
- jest
774
- .spyOn(workos.userManagement, 'getJwksUrl')
775
- .mockReturnValue('https://api.workos.com/sso/jwks/client_1234567890');
786
+ vi.spyOn(workos.userManagement, 'getJwksUrl').mockReturnValue(
787
+ 'https://api.workos.com/sso/jwks/client_1234567890',
788
+ );
776
789
 
777
790
  const nextCookies = await cookies();
778
791
  nextCookies.set(
@@ -808,15 +821,15 @@ describe('session.ts', () => {
808
821
  await sealData(mockSession, { password: process.env.WORKOS_COOKIE_PASSWORD as string }),
809
822
  );
810
823
 
811
- jest.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
824
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
812
825
  accessToken: await generateTestToken({ org_id: 'org_456' }),
813
826
  refreshToken: 'new-refresh-token',
814
827
  user: mockSession.user,
815
828
  });
816
829
 
817
- jest
818
- .spyOn(workos.userManagement, 'getJwksUrl')
819
- .mockReturnValue('https://api.workos.com/sso/jwks/client_1234567890');
830
+ vi.spyOn(workos.userManagement, 'getJwksUrl').mockReturnValue(
831
+ 'https://api.workos.com/sso/jwks/client_1234567890',
832
+ );
820
833
 
821
834
  const result = await refreshSession({ organizationId: 'org_456' });
822
835
 
@@ -835,8 +848,8 @@ describe('session.ts', () => {
835
848
  'wos-session',
836
849
  await sealData(mockSessionWithValidJWT, { password: process.env.WORKOS_COOKIE_PASSWORD as string }),
837
850
  );
838
- jest.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue('fail');
839
- expect(refreshSession({ ensureSignedIn: false })).rejects.toThrow('Failed to refresh session: fail');
851
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue('fail');
852
+ await expect(refreshSession({ ensureSignedIn: false })).rejects.toThrow('Failed to refresh session: fail');
840
853
  });
841
854
 
842
855
  it('throws if authenticateWithRefreshToken fails with error', async () => {
@@ -850,7 +863,7 @@ describe('session.ts', () => {
850
863
  'wos-session',
851
864
  await sealData(mockSessionWithValidJWT, { password: process.env.WORKOS_COOKIE_PASSWORD as string }),
852
865
  );
853
- jest.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue(new Error('error'));
866
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue(new Error('error'));
854
867
  await expect(refreshSession()).rejects.toThrow('Failed to refresh session: error');
855
868
  });
856
869
  });
@@ -860,7 +873,7 @@ describe('session.ts', () => {
860
873
  const nextCookies = await cookies();
861
874
  // @ts-expect-error - _reset is part of the mock
862
875
  nextCookies._reset();
863
- jest.clearAllMocks();
876
+ vi.clearAllMocks();
864
877
  });
865
878
 
866
879
  it('should return all token claims when accessToken is provided', async () => {
@@ -954,7 +967,7 @@ describe('session.ts', () => {
954
967
 
955
968
  describe('eager auth functionality', () => {
956
969
  beforeEach(() => {
957
- jest.clearAllMocks();
970
+ vi.clearAllMocks();
958
971
  });
959
972
 
960
973
  describe('isInitialDocumentRequest', () => {
@@ -1048,12 +1061,12 @@ describe('session.ts', () => {
1048
1061
  // Setup invalid session that needs refresh
1049
1062
  mockSession.accessToken = await generateTestToken({}, true);
1050
1063
 
1051
- (jwtVerify as jest.Mock).mockImplementation(() => {
1064
+ (jwtVerify as Mock).mockImplementation(() => {
1052
1065
  throw new Error('Invalid token');
1053
1066
  });
1054
1067
 
1055
1068
  const newAccessToken = await generateTestToken();
1056
- jest.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
1069
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockResolvedValue({
1057
1070
  accessToken: newAccessToken,
1058
1071
  refreshToken: 'new-refresh-token',
1059
1072
  user: mockSession.user,
@@ -1079,13 +1092,11 @@ describe('session.ts', () => {
1079
1092
  // Setup invalid session
1080
1093
  mockSession.accessToken = await generateTestToken({}, true);
1081
1094
 
1082
- (jwtVerify as jest.Mock).mockImplementation(() => {
1095
+ (jwtVerify as Mock).mockImplementation(() => {
1083
1096
  throw new Error('Invalid token');
1084
1097
  });
1085
1098
 
1086
- jest
1087
- .spyOn(workos.userManagement, 'authenticateWithRefreshToken')
1088
- .mockRejectedValue(new Error('Refresh failed'));
1099
+ vi.spyOn(workos.userManagement, 'authenticateWithRefreshToken').mockRejectedValue(new Error('Refresh failed'));
1089
1100
 
1090
1101
  const request = new NextRequest(new URL('http://example.com/page'));
1091
1102
  request.headers.set('accept', 'text/html');