scripts/test-mcp.mjs
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env node
/**
* `npm run test:mcp`: the per-PR fast check for the management MCP program.
* It covers the 5.0 tools, the cards' models and renders, test runs, the
* confirmations and tool policies behind them, and the Worker startup budget.
* It does not replace the full suite (`npm test`), which a train still needs.
*
* A test file joins by its name. Any file matching a pattern below is in, so
* a new tests/management-*.test.ts, tests/mcp-*.test.ts or
* tests/test-run-*.test.ts runs here with no edit. A file with another name
* joins by adding its path to the list. Every pattern must match at least one
* file: a rename or a typo stops the run instead of shrinking the subset.
*
* Files named `*-workerd.test.ts` start `wrangler dev`, which needs a host
* reservation (qa/live/operator/host-checks.md). They stay in the full suite,
* so this check runs anywhere without waiting for a slot.
*
* Its arguments go to scripts/run-tests.mjs ahead of the files (--typecheck,
* --fail-on-retry). `--list` prints the selected files and runs nothing.
*/
import { spawnSync } from 'node:child_process';
import { globSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
export const MCP_TEST_PATTERNS = [
// The management service and MCP server: 4.x and 5.0 tools, the card host,
// prompts, confirmations, undo, proposals, previews and the write rules MCP
// shares with Admin.
'tests/management-*.test.ts',
// The cards' models and renders, MCP OAuth and clients, tool policy.
'tests/mcp-*.test.ts',
// Test runs and the read-only test turn they start.
'tests/test-run-*.test.ts',
'tests/test-turn-*.test.ts',
// The change tools the management service applies.
'tests/workspace-change-tools.test.ts',
// A test run's model access, its call limit and fee, and its Usage rows.
'tests/model-access.test.ts',
'tests/run-fees-flue.test.ts',
'tests/admin-usage-report.test.ts',
// The startup budget every program PR has grown.
'tests/worker-startup-imports.test.ts',
];
const HOST_RESERVED = /-workerd\.test\.ts$/;
/** The selected test files, sorted; throws naming every pattern that matched nothing. */
export function selectMcpTests(root, patterns = MCP_TEST_PATTERNS) {
const empty = [];
const files = new Set();
for (const pattern of patterns) {
const matches = globSync(pattern, { cwd: root }).filter((file) => !HOST_RESERVED.test(file));
if (matches.length === 0) empty.push(pattern);
for (const file of matches) files.add(file);
}
if (empty.length > 0) {
throw new Error(`test:mcp patterns match no test file: ${empty.join(', ')}. ` +
'Fix or remove each in scripts/test-mcp.mjs.');
}
return [...files].sort();
}
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
const root = fileURLToPath(new URL('..', import.meta.url));
const args = process.argv.slice(2);
try {
const files = selectMcpTests(root);
if (args.includes('--list')) {
console.log(files.join('\n'));
} else {
console.log(`[test:mcp] ${files.length} files`);
const result = spawnSync(process.execPath, ['scripts/run-tests.mjs', ...args, ...files], { cwd: root, stdio: 'inherit' });
process.exitCode = result.status ?? 1;
}
} catch (error) {
console.error(error.message);
process.exitCode = 2;
}
}