Skip to content

Commit 28ef6e5

Browse files
committed
feat: add vitest global setup and improve test configuration in ts template
1 parent e81e494 commit 28ef6e5

File tree

7 files changed

+96
-16
lines changed

7 files changed

+96
-16
lines changed

.changeset/deep-windows-care.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'create-mcp-kit': patch
3+
---
4+
5+
feat: add vitest global setup and improve test configuration in ts template

packages/create-mcp-kit/template/server-ts/package.json.hbs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
{{/if}}
3232
{{#if (includes plugins 'vitest')}}
3333
"test": "vitest run",
34-
"coverage": "rimraf coverage && npm run test && c8 report --reporter=lcov --reporter=html",
34+
"report": "c8 report --reporter=lcov --reporter=html",
35+
"coverage": "rimraf coverage && npm run test && npm run report",
3536
{{/if}}
3637
{{#if (includes plugins 'changelog')}}
3738
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 -n changelog-option.js",

packages/create-mcp-kit/template/server-ts/src/services/web.ts.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{{#if (or (includes transports 'streamable') (includes transports 'sse'))}}
22
{{#if (includes transports 'streamable')}}
3-
import { nanoid } from 'nanoid'
3+
import { nanoid } from 'nanoid'
44
{{/if}}
55
import express from 'express'
66
{{#if (includes transports 'streamable')}}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export function waitForValue<T>(
2+
getterFn: () => T | undefined | null,
3+
checkInterval = 100,
4+
timeout = 10000,
5+
): Promise<T> {
6+
return new Promise((resolve, reject) => {
7+
const start = Date.now()
8+
9+
const intervalId = setInterval(() => {
10+
const value = getterFn()
11+
if (value) {
12+
clearInterval(intervalId)
13+
resolve(value)
14+
} else if (Date.now() - start > timeout) {
15+
clearInterval(intervalId)
16+
reject(new Error('Timeout waiting for value'))
17+
}
18+
}, checkInterval)
19+
})
20+
}

packages/create-mcp-kit/template/server-ts/vitest.config.ts.hbs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,22 @@ import { defineConfig } from 'vitest/config'
33

44
export default defineConfig({
55
test: {
6+
{{#if (or (includes transports 'streamable') (includes transports 'sse'))}}
7+
globalSetup: ['./vitest.global.ts'],
8+
{{/if}}
69
setupFiles: ['./vitest.setup.ts'],
710
coverage: {
811
include: ['src/**/*.ts'],
912
},
13+
{{#if (or (includes transports 'streamable') (includes transports 'sse'))}}
14+
pool: 'threads',
15+
poolOptions: {
16+
threads: {
17+
maxThreads: 1,
18+
minThreads: 1,
19+
},
20+
},
21+
{{/if}}
1022
},
1123
})
1224
{{/if}}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{{#if (and (includes plugins 'vitest') (or (includes transports 'streamable') (includes transports 'sse')))}}
2+
import { spawn } from 'child_process'
3+
import { waitForValue } from './tests/utils'
4+
5+
export default async function setup() {
6+
const webProcess = spawn('c8', ['--reporter=lcov', '--reporter=text', 'tsx', './src/index.ts', 'web'], {
7+
stdio: 'pipe',
8+
env: {
9+
...(process.env as Record<string, string>),
10+
NODE_V8_COVERAGE: './coverage/tmp',
11+
},
12+
})
13+
let webStarted = false
14+
webProcess.stdout?.on('data', async data => {
15+
const output = data.toString()
16+
if (output.includes('MCP server started')) {
17+
webStarted = true
18+
}
19+
})
20+
await waitForValue(() => webStarted)
21+
return () => {
22+
webProcess.kill('SIGINT')
23+
}
24+
}
25+
{{/if}}
Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,44 @@
11
{{#if (includes plugins 'vitest')}}
22
import 'dotenv/config'
33
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
4+
{{#if (includes transports 'stdio')}}
45
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
6+
{{/if}}
7+
{{#if (includes transports 'streamable')}}
8+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
9+
{{/if}}
10+
{{#if (includes transports 'sse')}}
11+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'
12+
{{/if}}
513

6-
const serverParams = new StdioClientTransport({
7-
command: 'nyc',
8-
args: [
9-
'--merge-async',
10-
'--reporter=lcov',
11-
'--reporter=text',
12-
'tsx',
13-
'./src/index.ts',
14-
],
14+
const client = new Client({
15+
name: 'test-mcp-client',
16+
version: '1.0.0',
17+
})
18+
19+
{{#if (includes transports 'stdio')}}
20+
const stdioClientTransport = new StdioClientTransport({
21+
command: 'c8',
22+
args: ['--reporter=lcov', '--reporter=text', 'tsx', './src/index.ts'],
1523
env: {
1624
...process.env as Record<string, string>,
1725
NODE_V8_COVERAGE: './coverage/tmp',
1826
},
1927
})
20-
const client = new Client({
21-
name: 'test-mcp-client',
22-
version: '1.0.0',
23-
})
24-
await client.connect(serverParams)
28+
await client.connect(stdioClientTransport)
29+
30+
{{/if}}
31+
{{#if (includes transports 'streamable')}}
32+
const streamableBaseUrl = new URL('http://localhost:8401/mcp')
33+
const streamableClientTransport = new StreamableHTTPClientTransport(new URL(streamableBaseUrl))
34+
await client.connect(streamableClientTransport)
35+
36+
{{/if}}
37+
{{#if (includes transports 'sse')}}
38+
const sseBaseUrl = new URL('http://localhost:8401/sse')
39+
const sseClientTransport = new SSEClientTransport(new URL(sseBaseUrl))
40+
await client.connect(sseClientTransport)
2541

42+
{{/if}}
2643
global.client = client
2744
{{/if}}

0 commit comments

Comments
 (0)