Skip to content

Commit ab4ce8a

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

File tree

7 files changed

+92
-10
lines changed

7 files changed

+92
-10
lines changed

.changeset/tender-snakes-wash.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 js template

packages/create-mcp-kit/template/server-js/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-js/src/services/web.js.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: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export function waitForValue(getterFn, checkInterval = 100, timeout = 10000) {
2+
return new Promise((resolve, reject) => {
3+
const start = Date.now()
4+
5+
const intervalId = setInterval(() => {
6+
const value = getterFn()
7+
if (value) {
8+
clearInterval(intervalId)
9+
resolve(value)
10+
} else if (Date.now() - start > timeout) {
11+
clearInterval(intervalId)
12+
reject(new Error('Timeout waiting for value'))
13+
}
14+
}, checkInterval)
15+
})
16+
}

packages/create-mcp-kit/template/server-js/vitest.config.js.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.js'],
8+
{{/if}}
69
setupFiles: ['./vitest.setup.js'],
710
coverage: {
811
include: ['src/**/*.js'],
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.js'
4+
5+
export default async function setup() {
6+
const webProcess = spawn('c8', ['--reporter=lcov', '--reporter=text', 'node', './src/index.js', 'web'], {
7+
stdio: 'pipe',
8+
env: {
9+
...process.env,
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 & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +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: ['--merge-async', '--reporter=lcov', '--reporter=text', 'node', './src/index.js'],
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', 'node', './src/index.js'],
923
env: {
1024
...process.env,
1125
NODE_V8_COVERAGE: './coverage/tmp',
1226
},
1327
})
14-
const client = new Client({
15-
name: 'test-mcp-client',
16-
version: '1.0.0',
17-
})
18-
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)
1941

42+
{{/if}}
2043
global.client = client
2144
{{/if}}

0 commit comments

Comments
 (0)