Skip to content

Commit bc5c7b3

Browse files
committed
feat: vitest
1 parent ee9fed2 commit bc5c7b3

29 files changed

+1762
-4067
lines changed

jest.config.js

Lines changed: 0 additions & 14 deletions
This file was deleted.

package-lock.json

Lines changed: 1390 additions & 3691 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
"prepack": "npm run build:esm && npm run build:cjs",
7070
"lint": "eslint src/ && prettier --check .",
7171
"lint:fix": "eslint src/ --fix && prettier --write .",
72-
"test": "npm run fetch:spec-types && jest",
72+
"test": "npm run fetch:spec-types && vitest run",
7373
"start": "npm run server",
7474
"server": "tsx watch --clear-screen=false src/cli.ts server",
7575
"client": "tsx src/cli.ts client"
@@ -100,26 +100,23 @@
100100
"devDependencies": {
101101
"@cfworker/json-schema": "^4.1.1",
102102
"@eslint/js": "^9.8.0",
103-
"@jest-mock/express": "^3.0.0",
104103
"@types/content-type": "^1.1.8",
105104
"@types/cors": "^2.8.17",
106105
"@types/cross-spawn": "^6.0.6",
107106
"@types/eslint__js": "^8.42.3",
108107
"@types/eventsource": "^1.1.15",
109108
"@types/express": "^5.0.0",
110-
"@types/jest": "^29.5.12",
111109
"@types/node": "^22.0.2",
112110
"@types/supertest": "^6.0.2",
113111
"@types/ws": "^8.5.12",
114112
"eslint": "^9.8.0",
115113
"eslint-config-prettier": "^10.1.8",
116-
"jest": "^29.7.0",
117114
"prettier": "3.6.2",
118115
"supertest": "^7.0.0",
119-
"ts-jest": "^29.2.4",
120116
"tsx": "^4.16.5",
121117
"typescript": "^5.5.4",
122118
"typescript-eslint": "^8.0.0",
119+
"vitest": "^4.0.6",
123120
"ws": "^8.18.0"
124121
},
125122
"resolutions": {

src/client/auth.test.ts

Lines changed: 73 additions & 76 deletions
Large diffs are not rendered by default.

src/client/cross-spawn.test.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,31 @@ import { JSONRPCMessage } from '../types.js';
44
import { ChildProcess } from 'node:child_process';
55

66
// mock cross-spawn
7-
jest.mock('cross-spawn');
8-
const mockSpawn = spawn as jest.MockedFunction<typeof spawn>;
7+
vi.mock('cross-spawn');
8+
const mockSpawn = spawn as vi.MockedFunction<typeof spawn>;
99

1010
describe('StdioClientTransport using cross-spawn', () => {
1111
beforeEach(() => {
1212
// mock cross-spawn's return value
1313
mockSpawn.mockImplementation(() => {
1414
const mockProcess: {
15-
on: jest.Mock;
16-
stdin?: { on: jest.Mock; write: jest.Mock };
17-
stdout?: { on: jest.Mock };
15+
on: vi.Mock;
16+
stdin?: { on: vi.Mock; write: vi.Mock };
17+
stdout?: { on: vi.Mock };
1818
stderr?: null;
1919
} = {
20-
on: jest.fn((event: string, callback: () => void) => {
20+
on: vi.fn((event: string, callback: () => void) => {
2121
if (event === 'spawn') {
2222
callback();
2323
}
2424
return mockProcess;
2525
}),
2626
stdin: {
27-
on: jest.fn(),
28-
write: jest.fn().mockReturnValue(true)
27+
on: vi.fn(),
28+
write: vi.fn().mockReturnValue(true)
2929
},
3030
stdout: {
31-
on: jest.fn()
31+
on: vi.fn()
3232
},
3333
stderr: null
3434
};
@@ -37,7 +37,7 @@ describe('StdioClientTransport using cross-spawn', () => {
3737
});
3838

3939
afterEach(() => {
40-
jest.clearAllMocks();
40+
vi.clearAllMocks();
4141
});
4242

4343
test('should call cross-spawn correctly', async () => {
@@ -105,30 +105,30 @@ describe('StdioClientTransport using cross-spawn', () => {
105105

106106
// get the mock process object
107107
const mockProcess: {
108-
on: jest.Mock;
108+
on: vi.Mock;
109109
stdin: {
110-
on: jest.Mock;
111-
write: jest.Mock;
112-
once: jest.Mock;
110+
on: vi.Mock;
111+
write: vi.Mock;
112+
once: vi.Mock;
113113
};
114114
stdout: {
115-
on: jest.Mock;
115+
on: vi.Mock;
116116
};
117117
stderr: null;
118118
} = {
119-
on: jest.fn((event: string, callback: () => void) => {
119+
on: vi.fn((event: string, callback: () => void) => {
120120
if (event === 'spawn') {
121121
callback();
122122
}
123123
return mockProcess;
124124
}),
125125
stdin: {
126-
on: jest.fn(),
127-
write: jest.fn().mockReturnValue(true),
128-
once: jest.fn()
126+
on: vi.fn(),
127+
write: vi.fn().mockReturnValue(true),
128+
once: vi.fn()
129129
},
130130
stdout: {
131-
on: jest.fn()
131+
on: vi.fn()
132132
},
133133
stderr: null
134134
};

src/client/index.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ import { InMemoryTransport } from '../inMemory.js';
2727
*/
2828
test('should initialize with matching protocol version', async () => {
2929
const clientTransport: Transport = {
30-
start: jest.fn().mockResolvedValue(undefined),
31-
close: jest.fn().mockResolvedValue(undefined),
32-
send: jest.fn().mockImplementation(message => {
30+
start: vi.fn().mockResolvedValue(undefined),
31+
close: vi.fn().mockResolvedValue(undefined),
32+
send: vi.fn().mockImplementation(message => {
3333
if (message.method === 'initialize') {
3434
clientTransport.onmessage?.({
3535
jsonrpc: '2.0',
@@ -86,9 +86,9 @@ test('should initialize with matching protocol version', async () => {
8686
test('should initialize with supported older protocol version', async () => {
8787
const OLD_VERSION = SUPPORTED_PROTOCOL_VERSIONS[1];
8888
const clientTransport: Transport = {
89-
start: jest.fn().mockResolvedValue(undefined),
90-
close: jest.fn().mockResolvedValue(undefined),
91-
send: jest.fn().mockImplementation(message => {
89+
start: vi.fn().mockResolvedValue(undefined),
90+
close: vi.fn().mockResolvedValue(undefined),
91+
send: vi.fn().mockImplementation(message => {
9292
if (message.method === 'initialize') {
9393
clientTransport.onmessage?.({
9494
jsonrpc: '2.0',
@@ -136,9 +136,9 @@ test('should initialize with supported older protocol version', async () => {
136136
*/
137137
test('should reject unsupported protocol version', async () => {
138138
const clientTransport: Transport = {
139-
start: jest.fn().mockResolvedValue(undefined),
140-
close: jest.fn().mockResolvedValue(undefined),
141-
send: jest.fn().mockImplementation(message => {
139+
start: vi.fn().mockResolvedValue(undefined),
140+
close: vi.fn().mockResolvedValue(undefined),
141+
send: vi.fn().mockImplementation(message => {
142142
if (message.method === 'initialize') {
143143
clientTransport.onmessage?.({
144144
jsonrpc: '2.0',

src/client/middleware.test.ts

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,26 @@ import { withOAuth, withLogging, applyMiddlewares, createMiddleware } from './mi
22
import { OAuthClientProvider } from './auth.js';
33
import { FetchLike } from '../shared/transport.js';
44

5-
jest.mock('../client/auth.js', () => {
6-
const actual = jest.requireActual('../client/auth.js');
5+
vi.mock('../client/auth.js', async () => {
6+
const actual = await vi.importActual('../client/auth.js');
77
return {
88
...actual,
9-
auth: jest.fn(),
10-
extractWWWAuthenticateParams: jest.fn()
9+
auth: vi.fn(),
10+
extractWWWAuthenticateParams: vi.fn()
1111
};
1212
});
1313

1414
import { auth, extractWWWAuthenticateParams } from './auth.js';
1515

16-
const mockAuth = auth as jest.MockedFunction<typeof auth>;
17-
const mockExtractWWWAuthenticateParams = extractWWWAuthenticateParams as jest.MockedFunction<typeof extractWWWAuthenticateParams>;
16+
const mockAuth = auth as vi.MockedFunction<typeof auth>;
17+
const mockExtractWWWAuthenticateParams = extractWWWAuthenticateParams as vi.MockedFunction<typeof extractWWWAuthenticateParams>;
1818

1919
describe('withOAuth', () => {
20-
let mockProvider: jest.Mocked<OAuthClientProvider>;
21-
let mockFetch: jest.MockedFunction<FetchLike>;
20+
let mockProvider: vi.Mocked<OAuthClientProvider>;
21+
let mockFetch: vi.MockedFunction<FetchLike>;
2222

2323
beforeEach(() => {
24-
jest.clearAllMocks();
24+
vi.clearAllMocks();
2525

2626
mockProvider = {
2727
get redirectUrl() {
@@ -30,16 +30,16 @@ describe('withOAuth', () => {
3030
get clientMetadata() {
3131
return { redirect_uris: ['http://localhost/callback'] };
3232
},
33-
tokens: jest.fn(),
34-
saveTokens: jest.fn(),
35-
clientInformation: jest.fn(),
36-
redirectToAuthorization: jest.fn(),
37-
saveCodeVerifier: jest.fn(),
38-
codeVerifier: jest.fn(),
39-
invalidateCredentials: jest.fn()
33+
tokens: vi.fn(),
34+
saveTokens: vi.fn(),
35+
clientInformation: vi.fn(),
36+
redirectToAuthorization: vi.fn(),
37+
saveCodeVerifier: vi.fn(),
38+
codeVerifier: vi.fn(),
39+
invalidateCredentials: vi.fn()
4040
};
4141

42-
mockFetch = jest.fn();
42+
mockFetch = vi.fn();
4343
});
4444

4545
it('should add Authorization header when tokens are available (with explicit baseUrl)', async () => {
@@ -371,8 +371,8 @@ describe('withOAuth', () => {
371371
});
372372

373373
describe('withLogging', () => {
374-
let mockFetch: jest.MockedFunction<FetchLike>;
375-
let mockLogger: jest.MockedFunction<
374+
let mockFetch: vi.MockedFunction<FetchLike>;
375+
let mockLogger: vi.MockedFunction<
376376
(input: {
377377
method: string;
378378
url: string | URL;
@@ -384,17 +384,17 @@ describe('withLogging', () => {
384384
error?: Error;
385385
}) => void
386386
>;
387-
let consoleErrorSpy: jest.SpyInstance;
388-
let consoleLogSpy: jest.SpyInstance;
387+
let consoleErrorSpy: vi.SpyInstance;
388+
let consoleLogSpy: vi.SpyInstance;
389389

390390
beforeEach(() => {
391-
jest.clearAllMocks();
391+
vi.clearAllMocks();
392392

393-
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
394-
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
393+
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
394+
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
395395

396-
mockFetch = jest.fn();
397-
mockLogger = jest.fn();
396+
mockFetch = vi.fn();
397+
mockLogger = vi.fn();
398398
});
399399

400400
afterEach(() => {
@@ -614,11 +614,11 @@ describe('withLogging', () => {
614614
});
615615

616616
describe('applyMiddleware', () => {
617-
let mockFetch: jest.MockedFunction<FetchLike>;
617+
let mockFetch: vi.MockedFunction<FetchLike>;
618618

619619
beforeEach(() => {
620-
jest.clearAllMocks();
621-
mockFetch = jest.fn();
620+
vi.clearAllMocks();
621+
mockFetch = vi.fn();
622622
});
623623

624624
it('should compose no middleware correctly', () => {
@@ -703,7 +703,7 @@ describe('applyMiddleware', () => {
703703
};
704704

705705
// Use custom logger to avoid console output
706-
const mockLogger = jest.fn();
706+
const mockLogger = vi.fn();
707707
const composedFetch = applyMiddlewares(oauthMiddleware, withLogging({ logger: mockLogger, statusLevel: 0 }))(mockFetch);
708708

709709
await composedFetch('https://api.example.com/data');
@@ -743,11 +743,11 @@ describe('applyMiddleware', () => {
743743
});
744744

745745
describe('Integration Tests', () => {
746-
let mockProvider: jest.Mocked<OAuthClientProvider>;
747-
let mockFetch: jest.MockedFunction<FetchLike>;
746+
let mockProvider: vi.Mocked<OAuthClientProvider>;
747+
let mockFetch: vi.MockedFunction<FetchLike>;
748748

749749
beforeEach(() => {
750-
jest.clearAllMocks();
750+
vi.clearAllMocks();
751751

752752
mockProvider = {
753753
get redirectUrl() {
@@ -756,16 +756,16 @@ describe('Integration Tests', () => {
756756
get clientMetadata() {
757757
return { redirect_uris: ['http://localhost/callback'] };
758758
},
759-
tokens: jest.fn(),
760-
saveTokens: jest.fn(),
761-
clientInformation: jest.fn(),
762-
redirectToAuthorization: jest.fn(),
763-
saveCodeVerifier: jest.fn(),
764-
codeVerifier: jest.fn(),
765-
invalidateCredentials: jest.fn()
759+
tokens: vi.fn(),
760+
saveTokens: vi.fn(),
761+
clientInformation: vi.fn(),
762+
redirectToAuthorization: vi.fn(),
763+
saveCodeVerifier: vi.fn(),
764+
codeVerifier: vi.fn(),
765+
invalidateCredentials: vi.fn()
766766
};
767767

768-
mockFetch = jest.fn();
768+
mockFetch = vi.fn();
769769
});
770770

771771
it('should work with SSE transport pattern', async () => {
@@ -783,7 +783,7 @@ describe('Integration Tests', () => {
783783
mockFetch.mockResolvedValue(response);
784784

785785
// Use custom logger to avoid console output
786-
const mockLogger = jest.fn();
786+
const mockLogger = vi.fn();
787787
const enhancedFetch = applyMiddlewares(
788788
withOAuth(mockProvider as OAuthClientProvider, 'https://mcp-server.example.com'),
789789
withLogging({ logger: mockLogger, statusLevel: 400 }) // Only log errors
@@ -830,7 +830,7 @@ describe('Integration Tests', () => {
830830
mockFetch.mockResolvedValue(response);
831831

832832
// Use custom logger to avoid console output
833-
const mockLogger = jest.fn();
833+
const mockLogger = vi.fn();
834834
const enhancedFetch = applyMiddlewares(
835835
withOAuth(mockProvider as OAuthClientProvider, 'https://streamable-server.example.com'),
836836
withLogging({
@@ -891,7 +891,7 @@ describe('Integration Tests', () => {
891891
mockAuth.mockResolvedValue('AUTHORIZED');
892892

893893
// Use custom logger to avoid console output
894-
const mockLogger = jest.fn();
894+
const mockLogger = vi.fn();
895895
const enhancedFetch = applyMiddlewares(
896896
withOAuth(mockProvider as OAuthClientProvider, 'https://mcp-server.example.com'),
897897
withLogging({ logger: mockLogger, statusLevel: 0 })
@@ -914,11 +914,11 @@ describe('Integration Tests', () => {
914914
});
915915

916916
describe('createMiddleware', () => {
917-
let mockFetch: jest.MockedFunction<FetchLike>;
917+
let mockFetch: vi.MockedFunction<FetchLike>;
918918

919919
beforeEach(() => {
920-
jest.clearAllMocks();
921-
mockFetch = jest.fn();
920+
vi.clearAllMocks();
921+
mockFetch = vi.fn();
922922
});
923923

924924
it('should create middleware with cleaner syntax', async () => {

0 commit comments

Comments
 (0)