67 lines
2.9 KiB
JavaScript
67 lines
2.9 KiB
JavaScript
import { z } from 'zod';
|
|
import { config } from '../../config.js';
|
|
import { detectJsPackageManager, runScriptCommandFor } from '../../lib/frameworks/packageManager.js';
|
|
import { runCommand } from '../../lib/runCommand.js';
|
|
import { errorResult, jsonResult, toErrorMessage } from '../shared.js';
|
|
import { requireReact } from './requireReact.js';
|
|
function parseReactTestingLibraryOutput(output) {
|
|
// Extract failing test names and common RTL errors for a quick summary.
|
|
const failingTests = output
|
|
.split(/\n(?=\s*FAIL|●)/)
|
|
.filter((chunk) => chunk.includes('●'))
|
|
.map((chunk) => {
|
|
const match = chunk.match(/●\s*(.+?)(?:\n|$)/);
|
|
return match?.[1]?.trim() ?? null;
|
|
})
|
|
.filter((item) => Boolean(item));
|
|
const rtlErrors = [];
|
|
if (/Unable to find an element/i.test(output))
|
|
rtlErrors.push('Unable to find an element (getBy/queryBy failed)');
|
|
if (/Found multiple elements/i.test(output))
|
|
rtlErrors.push('Found multiple elements with the same query');
|
|
if (/found accessibility element/i.test(output))
|
|
rtlErrors.push('Role/name based query mismatch');
|
|
if (/Timed out in waitFor/i.test(output))
|
|
rtlErrors.push('waitFor timeout (async assertion not satisfied)');
|
|
if (/Warning: An update to .* inside a test was not wrapped in act/i.test(output)) {
|
|
rtlErrors.push('Missing act() wrapper around state update');
|
|
}
|
|
const totalMatch = output.match(/Tests\s+(\d+)\s+passed/i) || output.match(/Test Suites?:\s*(\d+)\s+passed/i);
|
|
return {
|
|
failingTestCount: failingTests.length,
|
|
failingTests: failingTests.slice(0, 10),
|
|
rtlErrors: rtlErrors.slice(0, 10),
|
|
testsPassed: totalMatch ? Number(totalMatch[1]) : null,
|
|
};
|
|
}
|
|
export function registerRunReactTestsTool(server) {
|
|
server.registerTool('run_react_tests', {
|
|
title: 'Run React Tests',
|
|
description: 'Run the React test runner (Jest/Vitest + React Testing Library) via package.json "test" script and surface RTL-specific failures.',
|
|
inputSchema: {
|
|
extraArgs: z
|
|
.array(z.string())
|
|
.optional()
|
|
.describe('Extra CLI args, e.g. ["--filter", "UserCard"].'),
|
|
},
|
|
}, async ({ extraArgs }) => {
|
|
try {
|
|
const react = requireReact();
|
|
const pm = detectJsPackageManager(react.root);
|
|
const { command, args } = runScriptCommandFor(pm, 'test', extraArgs ?? []);
|
|
const result = await runCommand(command, args, {
|
|
cwd: react.root,
|
|
timeoutMs: config.scaffoldCommandTimeoutMs,
|
|
});
|
|
return jsonResult({
|
|
runner: 'npm-test-script',
|
|
summary: parseReactTestingLibraryOutput(result.output),
|
|
...result,
|
|
});
|
|
}
|
|
catch (error) {
|
|
return errorResult(toErrorMessage(error));
|
|
}
|
|
});
|
|
}
|
|
//# sourceMappingURL=runReactTests.js.map
|