@paretools/test 0.8.5 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -18
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/formatters.d.ts +3 -0
- package/dist/lib/formatters.d.ts.map +1 -1
- package/dist/lib/formatters.js +23 -6
- package/dist/lib/formatters.js.map +1 -1
- package/dist/lib/parsers/jest.d.ts +4 -0
- package/dist/lib/parsers/jest.d.ts.map +1 -1
- package/dist/lib/parsers/jest.js +39 -2
- package/dist/lib/parsers/jest.js.map +1 -1
- package/dist/lib/parsers/mocha.d.ts +4 -0
- package/dist/lib/parsers/mocha.d.ts.map +1 -1
- package/dist/lib/parsers/mocha.js +47 -2
- package/dist/lib/parsers/mocha.js.map +1 -1
- package/dist/lib/parsers/playwright.d.ts.map +1 -1
- package/dist/lib/parsers/playwright.js +4 -0
- package/dist/lib/parsers/playwright.js.map +1 -1
- package/dist/lib/parsers/pytest.d.ts +4 -0
- package/dist/lib/parsers/pytest.d.ts.map +1 -1
- package/dist/lib/parsers/pytest.js +35 -2
- package/dist/lib/parsers/pytest.js.map +1 -1
- package/dist/lib/parsers/vitest.d.ts +4 -0
- package/dist/lib/parsers/vitest.d.ts.map +1 -1
- package/dist/lib/parsers/vitest.js +39 -2
- package/dist/lib/parsers/vitest.js.map +1 -1
- package/dist/lib/timeouts.d.ts +3 -0
- package/dist/lib/timeouts.d.ts.map +1 -0
- package/dist/lib/timeouts.js +3 -0
- package/dist/lib/timeouts.js.map +1 -0
- package/dist/schemas/index.d.ts +19 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +14 -0
- package/dist/schemas/index.js.map +1 -1
- package/dist/tools/coverage.d.ts +11 -1
- package/dist/tools/coverage.d.ts.map +1 -1
- package/dist/tools/coverage.js +258 -35
- package/dist/tools/coverage.js.map +1 -1
- package/dist/tools/playwright.d.ts +21 -0
- package/dist/tools/playwright.d.ts.map +1 -1
- package/dist/tools/playwright.js +149 -24
- package/dist/tools/playwright.js.map +1 -1
- package/dist/tools/run.d.ts +19 -1
- package/dist/tools/run.d.ts.map +1 -1
- package/dist/tools/run.js +263 -39
- package/dist/tools/run.js.map +1 -1
- package/package.json +6 -3
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
/** Build extra CLI args for the `playwright` tool. Exported for unit testing. */
|
|
3
|
+
export declare function buildPlaywrightExtraArgs(opts: {
|
|
4
|
+
filter?: string;
|
|
5
|
+
project?: string;
|
|
6
|
+
grep?: string;
|
|
7
|
+
browser?: string;
|
|
8
|
+
shard?: string;
|
|
9
|
+
trace?: "on" | "off" | "retain-on-failure";
|
|
10
|
+
config?: string;
|
|
11
|
+
headed?: boolean;
|
|
12
|
+
updateSnapshots?: boolean;
|
|
13
|
+
workers?: number;
|
|
14
|
+
retries?: number;
|
|
15
|
+
maxFailures?: number;
|
|
16
|
+
timeout?: number;
|
|
17
|
+
lastFailed?: boolean;
|
|
18
|
+
onlyChanged?: boolean;
|
|
19
|
+
forbidOnly?: boolean;
|
|
20
|
+
passWithNoTests?: boolean;
|
|
21
|
+
args?: string[];
|
|
22
|
+
}): string[];
|
|
2
23
|
/** Registers the `playwright` tool on the given MCP server. */
|
|
3
24
|
export declare function registerPlaywrightTool(server: McpServer): void;
|
|
4
25
|
//# sourceMappingURL=playwright.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../../src/tools/playwright.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../../src/tools/playwright.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWzE,iFAAiF;AACjF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,mBAAmB,CAAC;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,GAAG,MAAM,EAAE,CAiEX;AAED,+DAA+D;AAC/D,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,QAwMvD"}
|
package/dist/tools/playwright.js
CHANGED
|
@@ -7,17 +7,70 @@ import { compactDualOutput, run, assertNoFlagInjection, INPUT_LIMITS } from "@pa
|
|
|
7
7
|
import { parsePlaywrightJson } from "../lib/parsers/playwright.js";
|
|
8
8
|
import { formatPlaywrightResult, compactPlaywrightResultMap, formatPlaywrightResultCompact, } from "../lib/formatters.js";
|
|
9
9
|
import { PlaywrightResultSchema } from "../schemas/index.js";
|
|
10
|
+
import { TEST_CLI_TIMEOUT_MS } from "../lib/timeouts.js";
|
|
11
|
+
/** Build extra CLI args for the `playwright` tool. Exported for unit testing. */
|
|
12
|
+
export function buildPlaywrightExtraArgs(opts) {
|
|
13
|
+
const extraArgs = [...(opts.args || [])];
|
|
14
|
+
if (opts.filter) {
|
|
15
|
+
extraArgs.push(opts.filter);
|
|
16
|
+
}
|
|
17
|
+
if (opts.project) {
|
|
18
|
+
extraArgs.push("--project", opts.project);
|
|
19
|
+
}
|
|
20
|
+
if (opts.grep) {
|
|
21
|
+
extraArgs.push("--grep", opts.grep);
|
|
22
|
+
}
|
|
23
|
+
if (opts.browser) {
|
|
24
|
+
extraArgs.push("--browser", opts.browser);
|
|
25
|
+
}
|
|
26
|
+
if (opts.shard) {
|
|
27
|
+
extraArgs.push("--shard", opts.shard);
|
|
28
|
+
}
|
|
29
|
+
if (opts.trace) {
|
|
30
|
+
extraArgs.push("--trace", opts.trace);
|
|
31
|
+
}
|
|
32
|
+
if (opts.config) {
|
|
33
|
+
extraArgs.push("--config", opts.config);
|
|
34
|
+
}
|
|
35
|
+
if (opts.headed) {
|
|
36
|
+
extraArgs.push("--headed");
|
|
37
|
+
}
|
|
38
|
+
if (opts.updateSnapshots) {
|
|
39
|
+
extraArgs.push("--update-snapshots");
|
|
40
|
+
}
|
|
41
|
+
if (opts.workers !== undefined) {
|
|
42
|
+
extraArgs.push(`--workers=${opts.workers}`);
|
|
43
|
+
}
|
|
44
|
+
if (opts.retries !== undefined) {
|
|
45
|
+
extraArgs.push(`--retries=${opts.retries}`);
|
|
46
|
+
}
|
|
47
|
+
if (opts.maxFailures !== undefined) {
|
|
48
|
+
extraArgs.push(`--max-failures=${opts.maxFailures}`);
|
|
49
|
+
}
|
|
50
|
+
if (opts.timeout !== undefined) {
|
|
51
|
+
extraArgs.push(`--timeout=${opts.timeout}`);
|
|
52
|
+
}
|
|
53
|
+
if (opts.lastFailed) {
|
|
54
|
+
extraArgs.push("--last-failed");
|
|
55
|
+
}
|
|
56
|
+
if (opts.onlyChanged) {
|
|
57
|
+
extraArgs.push("--only-changed");
|
|
58
|
+
}
|
|
59
|
+
if (opts.forbidOnly) {
|
|
60
|
+
extraArgs.push("--forbid-only");
|
|
61
|
+
}
|
|
62
|
+
if (opts.passWithNoTests) {
|
|
63
|
+
extraArgs.push("--pass-with-no-tests");
|
|
64
|
+
}
|
|
65
|
+
return extraArgs;
|
|
66
|
+
}
|
|
10
67
|
/** Registers the `playwright` tool on the given MCP server. */
|
|
11
68
|
export function registerPlaywrightTool(server) {
|
|
12
69
|
server.registerTool("playwright", {
|
|
13
70
|
title: "Playwright Tests",
|
|
14
|
-
description: "Runs Playwright tests with JSON reporter and returns structured results with pass/fail status, duration, and error messages.
|
|
71
|
+
description: "Runs Playwright tests with JSON reporter and returns structured results with pass/fail status, duration, and error messages.",
|
|
15
72
|
inputSchema: {
|
|
16
|
-
path: z
|
|
17
|
-
.string()
|
|
18
|
-
.max(INPUT_LIMITS.PATH_MAX)
|
|
19
|
-
.optional()
|
|
20
|
-
.describe("Project root path (default: cwd)"),
|
|
73
|
+
path: z.string().max(INPUT_LIMITS.PATH_MAX).optional().describe("Project root path"),
|
|
21
74
|
filter: z
|
|
22
75
|
.string()
|
|
23
76
|
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
@@ -28,52 +81,124 @@ export function registerPlaywrightTool(server) {
|
|
|
28
81
|
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
29
82
|
.optional()
|
|
30
83
|
.describe("Playwright project name (e.g., 'chromium', 'firefox', 'webkit')"),
|
|
84
|
+
grep: z
|
|
85
|
+
.string()
|
|
86
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
87
|
+
.optional()
|
|
88
|
+
.describe("Regex pattern for matching tests by title (--grep)"),
|
|
89
|
+
browser: z
|
|
90
|
+
.string()
|
|
91
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
92
|
+
.optional()
|
|
93
|
+
.describe('Browser to use (e.g., "chromium", "firefox", "webkit") via --browser'),
|
|
94
|
+
shard: z
|
|
95
|
+
.string()
|
|
96
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
97
|
+
.optional()
|
|
98
|
+
.describe('Shard spec for distributed E2E test execution (e.g., "1/3") via --shard'),
|
|
99
|
+
trace: z
|
|
100
|
+
.enum(["on", "off", "retain-on-failure"])
|
|
101
|
+
.optional()
|
|
102
|
+
.describe("Trace recording mode (--trace)"),
|
|
103
|
+
config: z
|
|
104
|
+
.string()
|
|
105
|
+
.max(INPUT_LIMITS.PATH_MAX)
|
|
106
|
+
.optional()
|
|
107
|
+
.describe("Path to non-default Playwright config file (--config)"),
|
|
31
108
|
headed: z.boolean().optional().default(false).describe("Run tests in headed browser mode"),
|
|
32
109
|
updateSnapshots: z
|
|
33
110
|
.boolean()
|
|
34
111
|
.optional()
|
|
35
112
|
.default(false)
|
|
36
113
|
.describe("Update snapshots (adds --update-snapshots flag)"),
|
|
114
|
+
workers: z
|
|
115
|
+
.number()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe("Number of parallel workers for test execution (maps to --workers)"),
|
|
118
|
+
retries: z
|
|
119
|
+
.number()
|
|
120
|
+
.optional()
|
|
121
|
+
.describe("Number of retries for failed tests (maps to --retries)"),
|
|
122
|
+
maxFailures: z
|
|
123
|
+
.number()
|
|
124
|
+
.optional()
|
|
125
|
+
.describe("Stop after this many test failures (maps to --max-failures)"),
|
|
126
|
+
timeout: z
|
|
127
|
+
.number()
|
|
128
|
+
.optional()
|
|
129
|
+
.describe("Per-test timeout in milliseconds (maps to --timeout)"),
|
|
130
|
+
lastFailed: z
|
|
131
|
+
.boolean()
|
|
132
|
+
.optional()
|
|
133
|
+
.describe("Re-run only previously failed tests (maps to --last-failed)"),
|
|
134
|
+
onlyChanged: z
|
|
135
|
+
.boolean()
|
|
136
|
+
.optional()
|
|
137
|
+
.describe("Run only tests affected by recent changes (maps to --only-changed)"),
|
|
138
|
+
forbidOnly: z
|
|
139
|
+
.boolean()
|
|
140
|
+
.optional()
|
|
141
|
+
.describe("Fail if test.only is found — CI safety check (maps to --forbid-only)"),
|
|
142
|
+
passWithNoTests: z
|
|
143
|
+
.boolean()
|
|
144
|
+
.optional()
|
|
145
|
+
.describe("Exit successfully when no tests are found (maps to --pass-with-no-tests)"),
|
|
37
146
|
args: z
|
|
38
147
|
.array(z.string().max(INPUT_LIMITS.STRING_MAX))
|
|
39
148
|
.max(INPUT_LIMITS.ARRAY_MAX)
|
|
40
149
|
.optional()
|
|
41
150
|
.default([])
|
|
42
151
|
.describe("Additional arguments to pass to Playwright test runner"),
|
|
43
|
-
compact: z
|
|
44
|
-
.boolean()
|
|
45
|
-
.optional()
|
|
46
|
-
.default(true)
|
|
47
|
-
.describe("Auto-compact when structured output exceeds raw CLI tokens. Set false to always get full schema."),
|
|
152
|
+
compact: z.boolean().optional().default(true).describe("Prefer compact output"),
|
|
48
153
|
},
|
|
49
154
|
outputSchema: PlaywrightResultSchema,
|
|
50
|
-
}, async ({ path, filter, project, headed, updateSnapshots, args, compact }) => {
|
|
51
|
-
for (const a of args ?? []) {
|
|
52
|
-
assertNoFlagInjection(a, "args");
|
|
53
|
-
}
|
|
54
|
-
const cwd = path || process.cwd();
|
|
55
|
-
const extraArgs = [...(args || [])];
|
|
155
|
+
}, async ({ path, filter, project, grep, browser, shard, trace, config, headed, updateSnapshots, workers, retries, maxFailures, timeout, lastFailed, onlyChanged, forbidOnly, passWithNoTests, args, compact, }) => {
|
|
56
156
|
if (filter) {
|
|
57
157
|
assertNoFlagInjection(filter, "filter");
|
|
58
|
-
extraArgs.push(filter);
|
|
59
158
|
}
|
|
60
159
|
if (project) {
|
|
61
160
|
assertNoFlagInjection(project, "project");
|
|
62
|
-
extraArgs.push("--project", project);
|
|
63
161
|
}
|
|
64
|
-
if (
|
|
65
|
-
|
|
162
|
+
if (grep) {
|
|
163
|
+
assertNoFlagInjection(grep, "grep");
|
|
66
164
|
}
|
|
67
|
-
if (
|
|
68
|
-
|
|
165
|
+
if (browser) {
|
|
166
|
+
assertNoFlagInjection(browser, "browser");
|
|
69
167
|
}
|
|
168
|
+
if (shard) {
|
|
169
|
+
assertNoFlagInjection(shard, "shard");
|
|
170
|
+
}
|
|
171
|
+
if (config) {
|
|
172
|
+
assertNoFlagInjection(config, "config");
|
|
173
|
+
}
|
|
174
|
+
const cwd = path || process.cwd();
|
|
175
|
+
const extraArgs = buildPlaywrightExtraArgs({
|
|
176
|
+
filter,
|
|
177
|
+
project,
|
|
178
|
+
grep,
|
|
179
|
+
browser,
|
|
180
|
+
shard,
|
|
181
|
+
trace,
|
|
182
|
+
config,
|
|
183
|
+
headed,
|
|
184
|
+
updateSnapshots,
|
|
185
|
+
workers,
|
|
186
|
+
retries,
|
|
187
|
+
maxFailures,
|
|
188
|
+
timeout,
|
|
189
|
+
lastFailed,
|
|
190
|
+
onlyChanged,
|
|
191
|
+
forbidOnly,
|
|
192
|
+
passWithNoTests,
|
|
193
|
+
args,
|
|
194
|
+
});
|
|
70
195
|
// Write JSON output to a temp file to avoid stdout parsing issues on Windows
|
|
71
196
|
const tempPath = join(tmpdir(), `pare-playwright-${randomUUID()}.json`);
|
|
72
197
|
const cmdArgs = ["playwright", "test", `--reporter=json`, ...extraArgs];
|
|
73
198
|
// Set PLAYWRIGHT_JSON_OUTPUT_NAME env var to direct JSON to temp file
|
|
74
199
|
const result = await run("npx", cmdArgs, {
|
|
75
200
|
cwd,
|
|
76
|
-
timeout:
|
|
201
|
+
timeout: TEST_CLI_TIMEOUT_MS,
|
|
77
202
|
env: { PLAYWRIGHT_JSON_OUTPUT_NAME: tempPath },
|
|
78
203
|
});
|
|
79
204
|
let jsonStr;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwright.js","sourceRoot":"","sources":["../../src/tools/playwright.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAChG,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,6BAA6B,GAC9B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"playwright.js","sourceRoot":"","sources":["../../src/tools/playwright.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/run.d.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { type Framework } from "../lib/detect.js";
|
|
3
3
|
/** Exported for unit testing. */
|
|
4
|
-
export declare function getRunCommand(framework: Framework, args: string[]
|
|
4
|
+
export declare function getRunCommand(framework: Framework, args: string[], opts?: {
|
|
5
|
+
coverage?: boolean;
|
|
6
|
+
}): {
|
|
5
7
|
cmd: string;
|
|
6
8
|
cmdArgs: string[];
|
|
7
9
|
};
|
|
10
|
+
/** Build the extra CLI args for the `run` tool. Exported for unit testing. */
|
|
11
|
+
export declare function buildRunExtraArgs(framework: Framework, opts: {
|
|
12
|
+
filter?: string;
|
|
13
|
+
shard?: string;
|
|
14
|
+
config?: string;
|
|
15
|
+
updateSnapshots?: boolean;
|
|
16
|
+
coverage?: boolean;
|
|
17
|
+
onlyChanged?: boolean;
|
|
18
|
+
exitFirst?: boolean;
|
|
19
|
+
passWithNoTests?: boolean;
|
|
20
|
+
bail?: number | boolean;
|
|
21
|
+
testNamePattern?: string;
|
|
22
|
+
workers?: number;
|
|
23
|
+
timeout?: number;
|
|
24
|
+
args?: string[];
|
|
25
|
+
}): string[];
|
|
8
26
|
/** Registers the `run` tool on the given MCP server. */
|
|
9
27
|
export declare function registerRunTool(server: McpServer): void;
|
|
10
28
|
/**
|
package/dist/tools/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/tools/run.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/tools/run.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AASnE,iCAAiC;AACjC,wBAAgB,aAAa,CAC3B,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5B;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAwBpC;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE;IACJ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,GACA,MAAM,EAAE,CAmLV;AAED,wDAAwD;AACxD,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,QAoMhD;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAatF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAUlD"}
|
package/dist/tools/run.js
CHANGED
|
@@ -11,8 +11,9 @@ import { parseVitestJson } from "../lib/parsers/vitest.js";
|
|
|
11
11
|
import { parseMochaJson } from "../lib/parsers/mocha.js";
|
|
12
12
|
import { formatTestRun, compactTestRunMap, formatTestRunCompact } from "../lib/formatters.js";
|
|
13
13
|
import { TestRunSchema } from "../schemas/index.js";
|
|
14
|
+
import { TEST_CLI_TIMEOUT_MS } from "../lib/timeouts.js";
|
|
14
15
|
/** Exported for unit testing. */
|
|
15
|
-
export function getRunCommand(framework, args) {
|
|
16
|
+
export function getRunCommand(framework, args, opts) {
|
|
16
17
|
switch (framework) {
|
|
17
18
|
case "pytest":
|
|
18
19
|
return { cmd: "python", cmdArgs: ["-m", "pytest", "-v", ...args] };
|
|
@@ -21,20 +22,197 @@ export function getRunCommand(framework, args) {
|
|
|
21
22
|
case "vitest":
|
|
22
23
|
return { cmd: "npx", cmdArgs: ["vitest", "run", "--reporter=json", ...args] };
|
|
23
24
|
case "mocha":
|
|
24
|
-
return
|
|
25
|
+
return opts?.coverage
|
|
26
|
+
? {
|
|
27
|
+
cmd: "npx",
|
|
28
|
+
cmdArgs: [
|
|
29
|
+
"nyc",
|
|
30
|
+
"--reporter=text",
|
|
31
|
+
"--reporter=json-summary",
|
|
32
|
+
"mocha",
|
|
33
|
+
"--reporter",
|
|
34
|
+
"json",
|
|
35
|
+
...args,
|
|
36
|
+
],
|
|
37
|
+
}
|
|
38
|
+
: { cmd: "npx", cmdArgs: ["mocha", "--reporter", "json", ...args] };
|
|
25
39
|
}
|
|
26
40
|
}
|
|
41
|
+
/** Build the extra CLI args for the `run` tool. Exported for unit testing. */
|
|
42
|
+
export function buildRunExtraArgs(framework, opts) {
|
|
43
|
+
const extraArgs = [...(opts.args || [])];
|
|
44
|
+
if (opts.filter) {
|
|
45
|
+
switch (framework) {
|
|
46
|
+
case "pytest":
|
|
47
|
+
extraArgs.push("-k", opts.filter);
|
|
48
|
+
break;
|
|
49
|
+
case "jest":
|
|
50
|
+
extraArgs.push("--testPathPattern", opts.filter);
|
|
51
|
+
break;
|
|
52
|
+
case "vitest":
|
|
53
|
+
extraArgs.push(opts.filter);
|
|
54
|
+
break;
|
|
55
|
+
case "mocha":
|
|
56
|
+
extraArgs.push("--grep", opts.filter);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Shard support (jest/vitest)
|
|
61
|
+
if (opts.shard) {
|
|
62
|
+
switch (framework) {
|
|
63
|
+
case "jest":
|
|
64
|
+
case "vitest":
|
|
65
|
+
extraArgs.push("--shard", opts.shard);
|
|
66
|
+
break;
|
|
67
|
+
case "pytest":
|
|
68
|
+
case "mocha":
|
|
69
|
+
// pytest/mocha don't have native --shard; ignore silently
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Config file support
|
|
74
|
+
if (opts.config) {
|
|
75
|
+
switch (framework) {
|
|
76
|
+
case "pytest":
|
|
77
|
+
extraArgs.push(`--override-ini=config=${opts.config}`);
|
|
78
|
+
break;
|
|
79
|
+
case "jest":
|
|
80
|
+
extraArgs.push("--config", opts.config);
|
|
81
|
+
break;
|
|
82
|
+
case "vitest":
|
|
83
|
+
extraArgs.push("--config", opts.config);
|
|
84
|
+
break;
|
|
85
|
+
case "mocha":
|
|
86
|
+
extraArgs.push("--config", opts.config);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (opts.updateSnapshots && (framework === "vitest" || framework === "jest")) {
|
|
91
|
+
extraArgs.push("-u");
|
|
92
|
+
}
|
|
93
|
+
if (opts.coverage) {
|
|
94
|
+
switch (framework) {
|
|
95
|
+
case "vitest":
|
|
96
|
+
case "jest":
|
|
97
|
+
extraArgs.push("--coverage");
|
|
98
|
+
break;
|
|
99
|
+
case "pytest":
|
|
100
|
+
extraArgs.push("--cov");
|
|
101
|
+
break;
|
|
102
|
+
case "mocha":
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (opts.onlyChanged) {
|
|
107
|
+
switch (framework) {
|
|
108
|
+
case "pytest":
|
|
109
|
+
extraArgs.push("--lf");
|
|
110
|
+
break;
|
|
111
|
+
case "jest":
|
|
112
|
+
extraArgs.push("--onlyChanged");
|
|
113
|
+
break;
|
|
114
|
+
case "vitest":
|
|
115
|
+
extraArgs.push("--changed");
|
|
116
|
+
break;
|
|
117
|
+
case "mocha":
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (opts.exitFirst) {
|
|
122
|
+
switch (framework) {
|
|
123
|
+
case "pytest":
|
|
124
|
+
extraArgs.push("-x");
|
|
125
|
+
break;
|
|
126
|
+
case "jest":
|
|
127
|
+
case "vitest":
|
|
128
|
+
extraArgs.push("--bail=1");
|
|
129
|
+
break;
|
|
130
|
+
case "mocha":
|
|
131
|
+
extraArgs.push("-b");
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (opts.passWithNoTests && (framework === "jest" || framework === "vitest")) {
|
|
136
|
+
extraArgs.push("--passWithNoTests");
|
|
137
|
+
}
|
|
138
|
+
// Bail: fail-fast with optional count
|
|
139
|
+
if (opts.bail !== undefined && opts.bail !== false) {
|
|
140
|
+
const n = opts.bail === true ? 1 : opts.bail;
|
|
141
|
+
switch (framework) {
|
|
142
|
+
case "pytest":
|
|
143
|
+
extraArgs.push(`--maxfail=${n}`);
|
|
144
|
+
break;
|
|
145
|
+
case "jest":
|
|
146
|
+
extraArgs.push(`--bail=${n}`);
|
|
147
|
+
break;
|
|
148
|
+
case "vitest":
|
|
149
|
+
extraArgs.push(`--bail=${n}`);
|
|
150
|
+
break;
|
|
151
|
+
case "mocha":
|
|
152
|
+
extraArgs.push("--bail");
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Test name pattern: filter tests by name
|
|
157
|
+
if (opts.testNamePattern) {
|
|
158
|
+
switch (framework) {
|
|
159
|
+
case "pytest":
|
|
160
|
+
extraArgs.push("-k", opts.testNamePattern);
|
|
161
|
+
break;
|
|
162
|
+
case "jest":
|
|
163
|
+
extraArgs.push(`--testNamePattern=${opts.testNamePattern}`);
|
|
164
|
+
break;
|
|
165
|
+
case "vitest":
|
|
166
|
+
extraArgs.push(`--grep=${opts.testNamePattern}`);
|
|
167
|
+
break;
|
|
168
|
+
case "mocha":
|
|
169
|
+
extraArgs.push("--grep", opts.testNamePattern);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Workers: parallel execution
|
|
174
|
+
if (opts.workers !== undefined) {
|
|
175
|
+
switch (framework) {
|
|
176
|
+
case "pytest":
|
|
177
|
+
extraArgs.push("-n", String(opts.workers));
|
|
178
|
+
break;
|
|
179
|
+
case "jest":
|
|
180
|
+
extraArgs.push(`--maxWorkers=${opts.workers}`);
|
|
181
|
+
break;
|
|
182
|
+
case "vitest":
|
|
183
|
+
extraArgs.push(`--pool.threads.maxThreads=${opts.workers}`);
|
|
184
|
+
break;
|
|
185
|
+
case "mocha":
|
|
186
|
+
extraArgs.push("--jobs", String(opts.workers));
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Timeout: per-test timeout
|
|
191
|
+
if (opts.timeout !== undefined) {
|
|
192
|
+
switch (framework) {
|
|
193
|
+
case "pytest":
|
|
194
|
+
extraArgs.push(`--timeout=${opts.timeout}`);
|
|
195
|
+
break;
|
|
196
|
+
case "jest":
|
|
197
|
+
extraArgs.push(`--testTimeout=${opts.timeout}`);
|
|
198
|
+
break;
|
|
199
|
+
case "vitest":
|
|
200
|
+
extraArgs.push(`--testTimeout=${opts.timeout}`);
|
|
201
|
+
break;
|
|
202
|
+
case "mocha":
|
|
203
|
+
extraArgs.push("--timeout", String(opts.timeout));
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return extraArgs;
|
|
208
|
+
}
|
|
27
209
|
/** Registers the `run` tool on the given MCP server. */
|
|
28
210
|
export function registerRunTool(server) {
|
|
29
211
|
server.registerTool("run", {
|
|
30
212
|
title: "Run Tests",
|
|
31
|
-
description: "Auto-detects test framework (pytest/jest/vitest/mocha), runs tests, returns structured results with failures.
|
|
213
|
+
description: "Auto-detects test framework (pytest/jest/vitest/mocha), runs tests, returns structured results with failures.",
|
|
32
214
|
inputSchema: {
|
|
33
|
-
path: z
|
|
34
|
-
.string()
|
|
35
|
-
.max(INPUT_LIMITS.PATH_MAX)
|
|
36
|
-
.optional()
|
|
37
|
-
.describe("Project root path (default: cwd)"),
|
|
215
|
+
path: z.string().max(INPUT_LIMITS.PATH_MAX).optional().describe("Project root path"),
|
|
38
216
|
framework: z
|
|
39
217
|
.enum(["pytest", "jest", "vitest", "mocha"])
|
|
40
218
|
.optional()
|
|
@@ -44,63 +222,109 @@ export function registerRunTool(server) {
|
|
|
44
222
|
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
45
223
|
.optional()
|
|
46
224
|
.describe("Test filter pattern (file path or test name pattern)"),
|
|
225
|
+
shard: z
|
|
226
|
+
.string()
|
|
227
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
228
|
+
.optional()
|
|
229
|
+
.describe('Shard spec for distributed test execution (e.g., "1/3") via --shard (jest/vitest)'),
|
|
230
|
+
config: z
|
|
231
|
+
.string()
|
|
232
|
+
.max(INPUT_LIMITS.PATH_MAX)
|
|
233
|
+
.optional()
|
|
234
|
+
.describe("Path to test config file (--config for all frameworks)"),
|
|
47
235
|
updateSnapshots: z
|
|
48
236
|
.boolean()
|
|
49
237
|
.optional()
|
|
50
238
|
.default(false)
|
|
51
239
|
.describe("Update snapshots (vitest/jest only, adds -u flag)"),
|
|
240
|
+
coverage: z
|
|
241
|
+
.boolean()
|
|
242
|
+
.optional()
|
|
243
|
+
.default(false)
|
|
244
|
+
.describe("Run with coverage (adds --coverage for vitest/jest, --cov for pytest)"),
|
|
245
|
+
onlyChanged: z
|
|
246
|
+
.boolean()
|
|
247
|
+
.optional()
|
|
248
|
+
.describe("Run only tests affected by recent changes (maps to --lf for pytest, --onlyChanged for jest, --changed for vitest)"),
|
|
249
|
+
exitFirst: z
|
|
250
|
+
.boolean()
|
|
251
|
+
.optional()
|
|
252
|
+
.describe("Stop on first test failure (maps to -x for pytest, --bail=1 for jest/vitest, -b for mocha)"),
|
|
253
|
+
passWithNoTests: z
|
|
254
|
+
.boolean()
|
|
255
|
+
.optional()
|
|
256
|
+
.describe("Exit successfully when no tests are found (maps to --passWithNoTests for jest/vitest)"),
|
|
257
|
+
bail: z
|
|
258
|
+
.union([z.number().int().min(1), z.boolean()])
|
|
259
|
+
.optional()
|
|
260
|
+
.describe("Fail fast after N failures (maps to --maxfail=N for pytest, --bail=N for jest/vitest, --bail for mocha). Pass true for 1."),
|
|
261
|
+
testNamePattern: z
|
|
262
|
+
.string()
|
|
263
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
264
|
+
.optional()
|
|
265
|
+
.describe("Filter tests by name pattern (maps to -k for pytest, --testNamePattern for jest, --grep for vitest/mocha)"),
|
|
266
|
+
workers: z
|
|
267
|
+
.number()
|
|
268
|
+
.int()
|
|
269
|
+
.min(1)
|
|
270
|
+
.optional()
|
|
271
|
+
.describe("Number of parallel workers (maps to -n for pytest-xdist, --maxWorkers for jest, --pool.threads.maxThreads for vitest, --jobs for mocha)"),
|
|
272
|
+
timeout: z
|
|
273
|
+
.number()
|
|
274
|
+
.int()
|
|
275
|
+
.min(0)
|
|
276
|
+
.optional()
|
|
277
|
+
.describe("Per-test timeout in milliseconds (maps to --timeout for pytest-timeout, --testTimeout for jest/vitest, --timeout for mocha)"),
|
|
52
278
|
args: z
|
|
53
279
|
.array(z.string().max(INPUT_LIMITS.STRING_MAX))
|
|
54
280
|
.max(INPUT_LIMITS.ARRAY_MAX)
|
|
55
281
|
.optional()
|
|
56
282
|
.default([])
|
|
57
283
|
.describe("Additional arguments to pass to the test runner"),
|
|
58
|
-
compact: z
|
|
59
|
-
.boolean()
|
|
60
|
-
.optional()
|
|
61
|
-
.default(true)
|
|
62
|
-
.describe("Auto-compact when structured output exceeds raw CLI tokens. Set false to always get full schema."),
|
|
284
|
+
compact: z.boolean().optional().default(true).describe("Prefer compact output"),
|
|
63
285
|
},
|
|
64
286
|
outputSchema: TestRunSchema,
|
|
65
|
-
}, async ({ path, framework, filter, updateSnapshots, args, compact }) => {
|
|
66
|
-
for (const a of args ?? []) {
|
|
67
|
-
assertNoFlagInjection(a, "args");
|
|
68
|
-
}
|
|
69
|
-
const cwd = path || process.cwd();
|
|
70
|
-
const detected = framework || (await detectFramework(cwd));
|
|
71
|
-
const extraArgs = [...(args || [])];
|
|
287
|
+
}, async ({ path, framework, filter, shard, config, updateSnapshots, coverage, onlyChanged, exitFirst, passWithNoTests, bail, testNamePattern, workers, timeout, args, compact, }) => {
|
|
72
288
|
if (filter) {
|
|
73
289
|
assertNoFlagInjection(filter, "filter");
|
|
74
|
-
switch (detected) {
|
|
75
|
-
case "pytest":
|
|
76
|
-
extraArgs.push("-k", filter);
|
|
77
|
-
break;
|
|
78
|
-
case "jest":
|
|
79
|
-
extraArgs.push("--testPathPattern", filter);
|
|
80
|
-
break;
|
|
81
|
-
case "vitest":
|
|
82
|
-
extraArgs.push(filter);
|
|
83
|
-
break;
|
|
84
|
-
case "mocha":
|
|
85
|
-
extraArgs.push("--grep", filter);
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
290
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
291
|
+
if (shard) {
|
|
292
|
+
assertNoFlagInjection(shard, "shard");
|
|
293
|
+
}
|
|
294
|
+
if (config) {
|
|
295
|
+
assertNoFlagInjection(config, "config");
|
|
92
296
|
}
|
|
297
|
+
if (testNamePattern) {
|
|
298
|
+
assertNoFlagInjection(testNamePattern, "testNamePattern");
|
|
299
|
+
}
|
|
300
|
+
const cwd = path || process.cwd();
|
|
301
|
+
const detected = framework || (await detectFramework(cwd));
|
|
302
|
+
const extraArgs = buildRunExtraArgs(detected, {
|
|
303
|
+
filter,
|
|
304
|
+
shard,
|
|
305
|
+
config,
|
|
306
|
+
updateSnapshots,
|
|
307
|
+
coverage,
|
|
308
|
+
onlyChanged,
|
|
309
|
+
exitFirst,
|
|
310
|
+
passWithNoTests,
|
|
311
|
+
bail,
|
|
312
|
+
testNamePattern,
|
|
313
|
+
workers,
|
|
314
|
+
timeout,
|
|
315
|
+
args,
|
|
316
|
+
});
|
|
93
317
|
// For vitest/jest, write JSON to a temp file instead of relying on
|
|
94
318
|
// stdout capture. On Windows, npx.cmd can swallow or mangle stdout,
|
|
95
319
|
// causing "No JSON output found" errors.
|
|
96
320
|
// Mocha outputs JSON to stdout, so we don't use --outputFile for it.
|
|
97
321
|
const useOutputFile = detected === "jest" || detected === "vitest";
|
|
98
322
|
const tempPath = useOutputFile ? join(tmpdir(), `pare-test-${randomUUID()}.json`) : "";
|
|
99
|
-
const { cmd, cmdArgs } = getRunCommand(detected, extraArgs);
|
|
323
|
+
const { cmd, cmdArgs } = getRunCommand(detected, extraArgs, { coverage });
|
|
100
324
|
if (useOutputFile) {
|
|
101
325
|
cmdArgs.push(`--outputFile=${tempPath}`);
|
|
102
326
|
}
|
|
103
|
-
const result = await run(cmd, cmdArgs, { cwd, timeout:
|
|
327
|
+
const result = await run(cmd, cmdArgs, { cwd, timeout: TEST_CLI_TIMEOUT_MS });
|
|
104
328
|
// Combine stdout and stderr for parsing (some frameworks write to stderr)
|
|
105
329
|
const output = result.stdout + "\n" + result.stderr;
|
|
106
330
|
let testRun;
|