Skip to content

Commit 18545c7

Browse files
jacekradkobrkalow
andauthored
feat(nextjs): Replace jest with vitest for unit tests (clerk#4298)
Co-authored-by: Bryce Kalow <bryce@clerk.dev>
1 parent 188bf40 commit 18545c7

23 files changed

+1705
-3203
lines changed

.changeset/small-cougars-protect.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ packages/*/examples
1616
package-lock.json
1717
**/integration/templates/**/*
1818
commitlint.config.ts
19+
vitest.workspace.mjs

package-lock.json

+1,631-3,151
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
"turbo-ignore": "^2.0.6",
106106
"typescript": "^5.6.2",
107107
"verdaccio": "^5.26.3",
108+
"vitest": "2.1.3",
108109
"zx": "^7.2.3"
109110
},
110111
"optionalDependencies": {

packages/nextjs/jest.config.js

-16
This file was deleted.

packages/nextjs/jest.setup.js

-1
This file was deleted.

packages/nextjs/package.json

+1-3
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,7 @@
6262
"lint:attw": "attw --pack . --ignore-rules no-resolution unexpected-module-syntax",
6363
"lint:publint": "publint",
6464
"publish:local": "npx yalc push --replace --sig",
65-
"test": "jest",
66-
"test:cache:clear": "jest --clearCache --useStderr",
67-
"test:ci": "jest --maxWorkers=70%"
65+
"test": "vitest"
6866
},
6967
"dependencies": {
7068
"@clerk/backend": "1.15.1",

packages/nextjs/src/pages/__tests__/__snapshots__/exports.test.ts.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// Jest Snapshot v1, https://goo.gl/fbAQLP
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`/client public exports should not include a breaking change 1`] = `
3+
exports[`/client public exports > should not include a breaking change 1`] = `
44
{
55
"ClerkProvider": [Function],
66
}

packages/nextjs/src/pages/__tests__/exports.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { describe, expect, it } from 'vitest';
2+
13
import * as publicExports from '../ClerkProvider';
24

35
describe('/client public exports', () => {

packages/nextjs/src/pages/__tests__/index.test.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { expectTypeOf } from 'expect-type';
2+
import { describe, it } from 'vitest';
23

34
import type { ClerkProvider } from '../ClerkProvider';
45

packages/nextjs/src/server/__tests__/__snapshots__/exports.test.ts.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// Jest Snapshot v1, https://goo.gl/fbAQLP
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`/server public exports should not include a breaking change 1`] = `
3+
exports[`/server public exports > should not include a breaking change 1`] = `
44
[
55
"auth",
66
"buildClerkProps",
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
1-
global.fetch = jest.fn(() => Promise.resolve(new Response(null)));
1+
import { createClerkClient } from '@clerk/backend';
2+
import type { Mock } from 'vitest';
3+
import { describe, expect, it, vi } from 'vitest';
24

35
import { clerkClient } from '../clerkClient';
46

5-
describe('clerkClient', () => {
6-
it('should pass version package to userAgent', async () => {
7-
const resolvedClerkClient = await clerkClient();
7+
vi.mock('@clerk/backend', async importOriginal => {
8+
const mod: any = await importOriginal();
9+
return {
10+
...mod,
11+
// replace some exports
12+
createClerkClient: vi.fn().mockReturnValue({ users: { getUser: vi.fn() } }),
13+
};
14+
});
815

9-
await resolvedClerkClient.users.getUser('user_test');
16+
describe('clerkClient', () => {
17+
it('should pass package-specific userAgent', async () => {
18+
await clerkClient();
1019

11-
expect(global.fetch).toBeCalled();
12-
expect((global.fetch as any).mock.calls[0][1].headers).toMatchObject({
13-
Authorization: 'Bearer TEST_SECRET_KEY',
14-
'Content-Type': 'application/json',
15-
'User-Agent': '@clerk/nextjs@0.0.0-test',
20+
expect((createClerkClient as Mock).mock.lastCall?.[0]).toMatchObject({
21+
userAgent: '@clerk/nextjs@0.0.0-test',
1622
});
1723
});
1824
});

packages/nextjs/src/server/__tests__/clerkMiddleware.test.ts

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
// There is no need to execute the complete authenticateRequest to test clerkMiddleware
22
// This mock SHOULD exist before the import of authenticateRequest
33
import { AuthStatus, constants } from '@clerk/backend/internal';
4-
import { describe, expect } from '@jest/globals';
54
// used to assert the mock
65
import assert from 'assert';
76
import type { NextFetchEvent } from 'next/server';
87
import { NextRequest, NextResponse } from 'next/server';
8+
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
99

1010
import { clerkClient } from '../clerkClient';
1111
import { clerkMiddleware } from '../clerkMiddleware';
1212
import { createRouteMatcher } from '../routeMatcher';
1313
import { decryptClerkRequestData } from '../utils';
1414

1515
const publishableKey = 'pk_test_Y2xlcmsuaW5jbHVkZWQua2F0eWRpZC05Mi5sY2wuZGV2JA';
16-
const authenticateRequestMock = jest.fn().mockResolvedValue({
16+
const authenticateRequestMock = vi.fn().mockResolvedValue({
1717
toAuth: () => ({
1818
debug: (d: any) => d,
1919
}),
2020
headers: new Headers(),
2121
publishableKey,
2222
});
2323

24-
jest.mock('../clerkClient', () => {
24+
vi.mock('../clerkClient', () => {
2525
return {
2626
clerkClient: () => ({
2727
authenticateRequest: authenticateRequestMock,
28-
telemetry: { record: jest.fn() },
28+
telemetry: { record: vi.fn() },
2929
}),
3030
};
3131
});
@@ -37,8 +37,8 @@ const consoleWarn = console.warn;
3737
const consoleLog = console.log;
3838

3939
beforeAll(() => {
40-
global.console.warn = jest.fn();
41-
global.console.log = jest.fn();
40+
global.console.warn = vi.fn();
41+
global.console.log = vi.fn();
4242
});
4343
afterAll(() => {
4444
global.console.warn = consoleWarn;
@@ -47,11 +47,13 @@ afterAll(() => {
4747

4848
// Removing this mock will cause the clerkMiddleware tests to fail due to missing publishable key
4949
// This mock SHOULD exist before the imports
50-
jest.mock('../constants', () => {
50+
vi.mock(import('../constants.js'), async importOriginal => {
51+
const actual = await importOriginal();
5152
return {
53+
...actual,
54+
ENCRYPTION_KEY: 'encryption-key',
5255
PUBLISHABLE_KEY: 'pk_test_Y2xlcmsuaW5jbHVkZWQua2F0eWRpZC05Mi5sY2wuZGV2JA',
5356
SECRET_KEY: 'sk_test_xxxxxxxxxxxxxxxxxx',
54-
ENCRYPTION_KEY: 'encryption-key',
5557
};
5658
});
5759

@@ -74,7 +76,7 @@ const mockRequest = (params: MockRequestParams) => {
7476
describe('ClerkMiddleware type tests', () => {
7577
// create a copy to test the types only
7678
// running this function does nothing, it is used purely for type checking
77-
const clerkMiddlewareMock = jest.fn() as typeof clerkMiddleware;
79+
const clerkMiddlewareMock = vi.fn() as typeof clerkMiddleware;
7880
it('can receive the appropriate keys', () => {
7981
clerkMiddlewareMock({ publishableKey: '', secretKey: '' });
8082
clerkMiddlewareMock({ secretKey: '' });
@@ -589,7 +591,7 @@ describe('clerkMiddleware(params)', () => {
589591

590592
describe('debug', () => {
591593
beforeEach(() => {
592-
(global.console.log as jest.Mock).mockClear();
594+
global.console.log.mockClear();
593595
});
594596

595597
it('outputs debug logs when used with only params', async () => {

packages/nextjs/src/server/__tests__/createGetAuth.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { AuthStatus, constants } from '@clerk/backend/internal';
22
import hmacSHA1 from 'crypto-js/hmac-sha1';
33
import { NextRequest } from 'next/server';
4+
import { describe, expect, it } from 'vitest';
45

56
import { createGetAuth, getAuth } from '../createGetAuth';
67

packages/nextjs/src/server/__tests__/exports.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
jest.mock('server-only', () => null);
1+
import { describe, expect, it } from 'vitest';
22

33
import * as publicExports from '../index';
44

packages/nextjs/src/utils/__tests__/debugLogger.test.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { expectTypeOf } from 'expect-type';
2+
import { beforeEach, describe, expect, it, vi } from 'vitest';
23

34
import { withLogger } from '../debugLogger';
45

@@ -7,9 +8,9 @@ describe('withLogger', () => {
78

89
beforeEach(() => {
910
logger = {
10-
enable: jest.fn(),
11-
log: jest.fn(),
12-
commit: jest.fn(),
11+
enable: vi.fn(),
12+
log: vi.fn(),
13+
commit: vi.fn(),
1314
};
1415
});
1516

@@ -116,7 +117,7 @@ describe('withLogger', () => {
116117
// setup: mock vercel environment, mock console log so we can intercept its value
117118
process.env.VERCEL = 'true';
118119
const oldConsoleLog = console.log.bind(console);
119-
const log = jest.fn();
120+
const log = vi.fn();
120121
console.log = log;
121122

122123
const veryLongString = new Array(6000).join('a');

packages/nextjs/src/utils/__tests__/matcher.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { pathToRegexp } from '@clerk/shared/pathToRegexp';
2+
import { describe, expect, it } from 'vitest';
23

34
const createMatcher = (config: { matcher: string[] }) => (path: string) => {
45
return config.matcher.some(matcher => {

packages/nextjs/src/utils/__tests__/removeBasePath.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { afterAll, describe, expect, it } from 'vitest';
2+
13
import { removeBasePath } from '../removeBasePath';
24

35
describe('removeBasePath', () => {

packages/nextjs/vitest.config.mts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { defineConfig } from 'vitest/config';
2+
3+
export default defineConfig({
4+
plugins: [],
5+
test: {
6+
env: {
7+
CLERK_SECRET_KEY: 'TEST_SECRET_KEY',
8+
},
9+
environment: 'jsdom',
10+
includeSource: ['**/*.{js,ts,jsx,tsx}'],
11+
setupFiles: './vitest.setup.mts',
12+
},
13+
});

packages/nextjs/vitest.setup.mts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { beforeAll } from 'vitest';
2+
3+
globalThis.PACKAGE_NAME = '@clerk/nextjs';
4+
globalThis.PACKAGE_VERSION = '0.0.0-test';
5+
6+
beforeAll(() => {});

packages/ui/package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
"@vitejs/plugin-react": "^4.3.1",
6969
"bundlewatch": "^0.4.0",
7070
"concurrently": "^8.2.2",
71-
"jsdom": "^24.1.1",
72-
"vitest": "^2.0.5"
71+
"jsdom": "^24.1.1"
7372
}
7473
}

packages/upgrade/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"@babel/preset-react": "^7.24.7",
5454
"@types/jscodeshift": "^0.12.0",
5555
"eslint-config-custom": "*",
56-
"vitest": "^2.1.3"
56+
"vitest": "2.1.3"
5757
},
5858
"engines": {
5959
"node": ">=18.17.0"

vitest.workspace.mjs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { defineWorkspace } from 'vitest/config';
2+
3+
export default defineWorkspace(['./packages/*/vitest.config.{mts,mjs,js,ts}']);

0 commit comments

Comments
 (0)