move to vitest (#18)
* feat: move to vitest * fix: lock file * fix: tests running sequentially on same port * fix lock file --------- Co-authored-by: Paul Carleton <paulcarletonjr@gmail.com>
This commit is contained in:
parent
eed3b222a1
commit
aeceefa9cf
8 changed files with 2069 additions and 4025 deletions
|
|
@ -1,8 +0,0 @@
|
|||
export default {
|
||||
preset: 'ts-jest/presets/default-esm',
|
||||
extensionsToTreatAsEsm: ['.ts'],
|
||||
testEnvironment: 'node',
|
||||
moduleNameMapper: {
|
||||
'^(\\.{1,2}/.*)\\.js$': '$1'
|
||||
}
|
||||
};
|
||||
5067
package-lock.json
generated
5067
package-lock.json
generated
File diff suppressed because it is too large
Load diff
11
package.json
11
package.json
|
|
@ -12,7 +12,8 @@
|
|||
},
|
||||
"scripts": {
|
||||
"start": "tsx src/index.ts",
|
||||
"test": "jest",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"build": "tsdown src/index.ts --minify --clean --target node20",
|
||||
"lint": "eslint src/ examples/ && prettier --check .",
|
||||
"lint:fix": "eslint src/ examples/ --fix && prettier --write .",
|
||||
|
|
@ -29,19 +30,17 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.8.0",
|
||||
"@jest/globals": "^29.7.0",
|
||||
"@types/express": "^5.0.3",
|
||||
"@types/jest": "^29.5.8",
|
||||
"@types/node": "^22.10.2",
|
||||
"@typescript/native-preview": "^7.0.0-dev.20251111.1",
|
||||
"eslint": "^9.8.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "3.6.2",
|
||||
"ts-jest": "^29.1.1",
|
||||
"tsdown": "^0.16.2",
|
||||
"tsx": "^4.7.0",
|
||||
"typescript": "^5.5.4",
|
||||
"typescript-eslint": "^8.0.0"
|
||||
"typescript-eslint": "^8.0.0",
|
||||
"vitest": "^2.1.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.20.1",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { describe, test } from '@jest/globals';
|
||||
import {
|
||||
runClientAgainstScenario,
|
||||
SpawnedClientRunner
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { describe, test } from '@jest/globals';
|
||||
import {
|
||||
runClientAgainstScenario,
|
||||
SpawnedClientRunner
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ import { getClientScenario, listActiveClientScenarios } from '../index.js';
|
|||
import path from 'path';
|
||||
|
||||
describe('Server Scenarios', () => {
|
||||
let serverProcess: ChildProcess;
|
||||
let serverProcess: ChildProcess | null = null;
|
||||
const TEST_PORT = 3001;
|
||||
const SERVER_URL = `http://localhost:${TEST_PORT}/mcp`;
|
||||
const SERVER_STARTUP_TIMEOUT = 10000; // 10 seconds to start
|
||||
const SERVER_STARTUP_TIMEOUT = 30000; // 30 seconds for CI
|
||||
|
||||
beforeAll(async () => {
|
||||
// Start the everything-server once for all scenarios
|
||||
// Start the everything-server once for all scenarios in this file
|
||||
const serverPath = path.join(
|
||||
process.cwd(),
|
||||
'examples/servers/typescript/everything-server.ts'
|
||||
|
|
@ -17,61 +17,85 @@ describe('Server Scenarios', () => {
|
|||
|
||||
serverProcess = spawn('npx', ['tsx', serverPath], {
|
||||
env: { ...process.env, PORT: TEST_PORT.toString() },
|
||||
stdio: ['ignore', 'pipe', 'pipe']
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
detached: false
|
||||
});
|
||||
|
||||
// Capture output for debugging
|
||||
let stdoutData = '';
|
||||
let stderrData = '';
|
||||
|
||||
serverProcess.stdout?.on('data', (data) => {
|
||||
stdoutData += data.toString();
|
||||
});
|
||||
|
||||
serverProcess.stderr?.on('data', (data) => {
|
||||
stderrData += data.toString();
|
||||
});
|
||||
|
||||
// Wait for server to be ready
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
if (serverProcess) {
|
||||
serverProcess.kill('SIGKILL');
|
||||
}
|
||||
reject(
|
||||
new Error(`Server failed to start within ${SERVER_STARTUP_TIMEOUT}ms`)
|
||||
);
|
||||
}, SERVER_STARTUP_TIMEOUT);
|
||||
|
||||
serverProcess.stdout?.on('data', (data) => {
|
||||
let resolved = false;
|
||||
|
||||
serverProcess!.stdout?.on('data', (data) => {
|
||||
const output = data.toString();
|
||||
if (output.includes('running on')) {
|
||||
clearTimeout(timeout);
|
||||
resolved = true;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
serverProcess.on('error', (error) => {
|
||||
serverProcess!.on('error', (error) => {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error(`Failed to start server: ${error.message}`));
|
||||
});
|
||||
|
||||
serverProcess.on('exit', (code) => {
|
||||
if (code !== null && code !== 0) {
|
||||
serverProcess!.on('exit', (code) => {
|
||||
// Only reject if server exits unexpectedly during startup
|
||||
if (!resolved && code !== null && code !== 0) {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error(`Server exited prematurely with code ${code}`));
|
||||
reject(
|
||||
new Error(
|
||||
`Server exited prematurely with code ${code}. STDOUT: ${stdoutData}, STDERR: ${stderrData}`
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, SERVER_STARTUP_TIMEOUT + 5000);
|
||||
|
||||
afterAll(async () => {
|
||||
// Stop the server
|
||||
if (serverProcess) {
|
||||
// Stop the server and clean up
|
||||
if (serverProcess && !serverProcess.killed) {
|
||||
// Try graceful shutdown first
|
||||
serverProcess.kill('SIGTERM');
|
||||
|
||||
// Wait for graceful shutdown
|
||||
// Wait for graceful shutdown with timeout
|
||||
await new Promise<void>((resolve) => {
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
if (!serverProcess.killed) {
|
||||
const killTimeout = setTimeout(() => {
|
||||
if (serverProcess && !serverProcess.killed) {
|
||||
serverProcess.kill('SIGKILL');
|
||||
}
|
||||
resolve();
|
||||
}, 5000);
|
||||
|
||||
const cleanUp = () => {
|
||||
clearTimeout(timeoutHandle);
|
||||
serverProcess.removeListener('exit', cleanUp);
|
||||
serverProcess!.once('exit', () => {
|
||||
clearTimeout(killTimeout);
|
||||
resolve();
|
||||
};
|
||||
|
||||
serverProcess.on('exit', cleanUp);
|
||||
});
|
||||
});
|
||||
|
||||
serverProcess = null;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"types": ["node", "vitest/globals"]
|
||||
},
|
||||
"include": ["src/**/*", "examples/clients/typescript/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
|
|
|
|||
15
vitest.config.ts
Normal file
15
vitest.config.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'node',
|
||||
include: ['**/*.test.ts'],
|
||||
exclude: ['node_modules', 'dist'],
|
||||
// Run test files sequentially to avoid port conflicts
|
||||
fileParallelism: false,
|
||||
// Increase timeout for server tests in CI
|
||||
testTimeout: 15000,
|
||||
hookTimeout: 30000
|
||||
}
|
||||
});
|
||||
Loading…
Reference in a new issue