@boolesai/tspec-cli 1.1.0 → 1.2.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 +21 -21
- package/dist/index.js +209 -17
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/types/utils/files.d.ts +43 -4
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ npx @boolesai/tspec-cli <command>
|
|
|
21
21
|
|
|
22
22
|
### `tspec validate`
|
|
23
23
|
|
|
24
|
-
Validate `.
|
|
24
|
+
Validate `.tcase` files for schema correctness.
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
tspec validate <files...> [options]
|
|
@@ -34,13 +34,13 @@ tspec validate <files...> [options]
|
|
|
34
34
|
**Examples:**
|
|
35
35
|
```bash
|
|
36
36
|
# Validate a single file
|
|
37
|
-
tspec validate tests/login.http.
|
|
37
|
+
tspec validate tests/login.http.tcase
|
|
38
38
|
|
|
39
39
|
# Validate multiple files with glob pattern
|
|
40
|
-
tspec validate "tests/**/*.
|
|
40
|
+
tspec validate "tests/**/*.tcase"
|
|
41
41
|
|
|
42
42
|
# JSON output for CI/CD
|
|
43
|
-
tspec validate tests/*.
|
|
43
|
+
tspec validate tests/*.tcase --output json
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
### `tspec run`
|
|
@@ -63,25 +63,25 @@ tspec run <files...> [options]
|
|
|
63
63
|
**Examples:**
|
|
64
64
|
```bash
|
|
65
65
|
# Run tests with default settings
|
|
66
|
-
tspec run tests/*.http.
|
|
66
|
+
tspec run tests/*.http.tcase
|
|
67
67
|
|
|
68
68
|
# Run with environment variables
|
|
69
|
-
tspec run tests/*.
|
|
69
|
+
tspec run tests/*.tcase -e API_HOST=api.example.com -e API_KEY=secret
|
|
70
70
|
|
|
71
71
|
# Run with parameters
|
|
72
|
-
tspec run tests/*.
|
|
72
|
+
tspec run tests/*.tcase -p username=testuser -p timeout=5000
|
|
73
73
|
|
|
74
74
|
# Run with higher concurrency
|
|
75
|
-
tspec run tests/*.
|
|
75
|
+
tspec run tests/*.tcase -c 10
|
|
76
76
|
|
|
77
77
|
# Verbose output for debugging
|
|
78
|
-
tspec run tests/*.
|
|
78
|
+
tspec run tests/*.tcase -v
|
|
79
79
|
|
|
80
80
|
# JSON output for CI/CD
|
|
81
|
-
tspec run tests/*.
|
|
81
|
+
tspec run tests/*.tcase --output json
|
|
82
82
|
|
|
83
83
|
# Stop on first failure
|
|
84
|
-
tspec run tests/*.
|
|
84
|
+
tspec run tests/*.tcase --fail-fast
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
### `tspec parse`
|
|
@@ -102,13 +102,13 @@ tspec parse <files...> [options]
|
|
|
102
102
|
**Examples:**
|
|
103
103
|
```bash
|
|
104
104
|
# Parse and display test cases
|
|
105
|
-
tspec parse tests/login.http.
|
|
105
|
+
tspec parse tests/login.http.tcase
|
|
106
106
|
|
|
107
107
|
# JSON output for inspection
|
|
108
|
-
tspec parse tests/*.
|
|
108
|
+
tspec parse tests/*.tcase --output json
|
|
109
109
|
|
|
110
110
|
# With variable substitution
|
|
111
|
-
tspec parse tests/*.
|
|
111
|
+
tspec parse tests/*.tcase -e API_HOST=localhost
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
### `tspec list`
|
|
@@ -150,7 +150,7 @@ TSpec CLI can run as an MCP server, exposing all commands as tools for AI assist
|
|
|
150
150
|
| Tool | Description |
|
|
151
151
|
|------|-------------|
|
|
152
152
|
| `tspec_run` | Execute test cases and report results |
|
|
153
|
-
| `tspec_validate` | Validate .
|
|
153
|
+
| `tspec_validate` | Validate .tcase files for schema correctness |
|
|
154
154
|
| `tspec_parse` | Parse and display test case information |
|
|
155
155
|
| `tspec_list` | List supported protocols |
|
|
156
156
|
|
|
@@ -191,7 +191,7 @@ Or if installed globally:
|
|
|
191
191
|
|
|
192
192
|
```json
|
|
193
193
|
{
|
|
194
|
-
"files": ["tests/*.
|
|
194
|
+
"files": ["tests/*.tcase"],
|
|
195
195
|
"concurrency": 5,
|
|
196
196
|
"env": { "API_HOST": "localhost" },
|
|
197
197
|
"params": { "timeout": "5000" },
|
|
@@ -204,7 +204,7 @@ Or if installed globally:
|
|
|
204
204
|
|
|
205
205
|
```json
|
|
206
206
|
{
|
|
207
|
-
"files": ["tests/*.
|
|
207
|
+
"files": ["tests/*.tcase"],
|
|
208
208
|
"output": "text"
|
|
209
209
|
}
|
|
210
210
|
```
|
|
@@ -213,7 +213,7 @@ Or if installed globally:
|
|
|
213
213
|
|
|
214
214
|
```json
|
|
215
215
|
{
|
|
216
|
-
"files": ["tests/*.
|
|
216
|
+
"files": ["tests/*.tcase"],
|
|
217
217
|
"env": { "API_HOST": "localhost" },
|
|
218
218
|
"params": { "timeout": "5000" },
|
|
219
219
|
"verbose": true,
|
|
@@ -244,10 +244,10 @@ Or if installed globally:
|
|
|
244
244
|
```yaml
|
|
245
245
|
- name: Run TSpec tests
|
|
246
246
|
run: |
|
|
247
|
-
npx @boolesai/tspec-cli run tests/*.
|
|
247
|
+
npx @boolesai/tspec-cli run tests/*.tcase --output json > results.json
|
|
248
248
|
|
|
249
249
|
- name: Validate TSpec files
|
|
250
|
-
run: npx @boolesai/tspec-cli validate tests/*.
|
|
250
|
+
run: npx @boolesai/tspec-cli validate tests/*.tcase
|
|
251
251
|
```
|
|
252
252
|
|
|
253
253
|
### GitLab CI
|
|
@@ -255,7 +255,7 @@ Or if installed globally:
|
|
|
255
255
|
```yaml
|
|
256
256
|
test:
|
|
257
257
|
script:
|
|
258
|
-
- npx @boolesai/tspec-cli run tests/*.
|
|
258
|
+
- npx @boolesai/tspec-cli run tests/*.tcase --output json
|
|
259
259
|
artifacts:
|
|
260
260
|
reports:
|
|
261
261
|
junit: results.json
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
+
import { existsSync, statSync, readFileSync } from "fs";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { isAbsolute, resolve as resolve$1, basename, relative, dirname, join } from "path";
|
|
2
5
|
import ora from "ora";
|
|
3
|
-
import { getTypeFromFilePath, validateTestCase, clearTemplateCache, parseTestCases, scheduler, registry as registry$1 } from "@boolesai/tspec";
|
|
6
|
+
import { getTypeFromFilePath, isSuiteFile, getSuiteProtocolType, validateTestCase, clearTemplateCache, executeSuite, parseTestCases, scheduler, registry as registry$1 } from "@boolesai/tspec";
|
|
4
7
|
import { glob } from "glob";
|
|
5
|
-
import { isAbsolute, resolve as resolve$1, basename, relative } from "path";
|
|
6
|
-
import { existsSync, statSync } from "fs";
|
|
7
8
|
import chalk from "chalk";
|
|
8
9
|
import process$2 from "node:process";
|
|
9
10
|
async function discoverTSpecFiles(patterns, cwd) {
|
|
@@ -15,14 +16,14 @@ async function discoverTSpecFiles(patterns, cwd) {
|
|
|
15
16
|
if (existsSync(absolutePath)) {
|
|
16
17
|
const stat = statSync(absolutePath);
|
|
17
18
|
if (stat.isFile()) {
|
|
18
|
-
if (absolutePath.endsWith(".
|
|
19
|
+
if (absolutePath.endsWith(".tcase")) {
|
|
19
20
|
filePaths.push(absolutePath);
|
|
20
21
|
}
|
|
21
22
|
continue;
|
|
22
23
|
} else if (stat.isDirectory()) {
|
|
23
|
-
const dirFiles = await glob("**/*.
|
|
24
|
+
const dirFiles = await glob("**/*.tcase", { cwd: absolutePath, absolute: true });
|
|
24
25
|
if (dirFiles.length === 0) {
|
|
25
|
-
errors2.push(`No .
|
|
26
|
+
errors2.push(`No .tcase files found in directory: ${pattern2}`);
|
|
26
27
|
} else {
|
|
27
28
|
filePaths.push(...dirFiles);
|
|
28
29
|
}
|
|
@@ -30,9 +31,9 @@ async function discoverTSpecFiles(patterns, cwd) {
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
const matches = await glob(pattern2, { cwd: workingDir, absolute: true });
|
|
33
|
-
const tspecMatches = matches.filter((f) => f.endsWith(".
|
|
34
|
+
const tspecMatches = matches.filter((f) => f.endsWith(".tcase"));
|
|
34
35
|
if (tspecMatches.length === 0) {
|
|
35
|
-
errors2.push(`No .
|
|
36
|
+
errors2.push(`No .tcase files matched pattern: ${pattern2}`);
|
|
36
37
|
} else {
|
|
37
38
|
filePaths.push(...tspecMatches);
|
|
38
39
|
}
|
|
@@ -46,6 +47,61 @@ async function discoverTSpecFiles(patterns, cwd) {
|
|
|
46
47
|
}));
|
|
47
48
|
return { files, errors: errors2 };
|
|
48
49
|
}
|
|
50
|
+
async function discoverAllTestFiles(patterns, cwd) {
|
|
51
|
+
const workingDir = process.cwd();
|
|
52
|
+
const tspecPaths = [];
|
|
53
|
+
const suitePaths = [];
|
|
54
|
+
const errors2 = [];
|
|
55
|
+
for (const pattern2 of patterns) {
|
|
56
|
+
const absolutePath = isAbsolute(pattern2) ? pattern2 : resolve$1(workingDir, pattern2);
|
|
57
|
+
if (existsSync(absolutePath)) {
|
|
58
|
+
const stat = statSync(absolutePath);
|
|
59
|
+
if (stat.isFile()) {
|
|
60
|
+
if (absolutePath.endsWith(".tcase")) {
|
|
61
|
+
tspecPaths.push(absolutePath);
|
|
62
|
+
} else if (isSuiteFile(absolutePath)) {
|
|
63
|
+
suitePaths.push(absolutePath);
|
|
64
|
+
}
|
|
65
|
+
continue;
|
|
66
|
+
} else if (stat.isDirectory()) {
|
|
67
|
+
const tspecFiles2 = await glob("**/*.tcase", { cwd: absolutePath, absolute: true });
|
|
68
|
+
const suiteFiles2 = await glob("**/*.tsuite", { cwd: absolutePath, absolute: true });
|
|
69
|
+
if (tspecFiles2.length === 0 && suiteFiles2.length === 0) {
|
|
70
|
+
errors2.push(`No .tcase or .tsuite files found in directory: ${pattern2}`);
|
|
71
|
+
} else {
|
|
72
|
+
tspecPaths.push(...tspecFiles2);
|
|
73
|
+
suitePaths.push(...suiteFiles2);
|
|
74
|
+
}
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const matches = await glob(pattern2, { cwd: workingDir, absolute: true });
|
|
79
|
+
const tspecMatches = matches.filter((f) => f.endsWith(".tcase"));
|
|
80
|
+
const suiteMatches = matches.filter((f) => isSuiteFile(f));
|
|
81
|
+
if (tspecMatches.length === 0 && suiteMatches.length === 0) {
|
|
82
|
+
errors2.push(`No .tcase or .tsuite files matched pattern: ${pattern2}`);
|
|
83
|
+
} else {
|
|
84
|
+
tspecPaths.push(...tspecMatches);
|
|
85
|
+
suitePaths.push(...suiteMatches);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const uniqueTspecPaths = [...new Set(tspecPaths)];
|
|
89
|
+
const uniqueSuitePaths = [...new Set(suitePaths)];
|
|
90
|
+
const tspecFiles = uniqueTspecPaths.map((filePath) => ({
|
|
91
|
+
path: filePath,
|
|
92
|
+
relativePath: relative(workingDir, filePath),
|
|
93
|
+
fileName: basename(filePath),
|
|
94
|
+
protocol: getTypeFromFilePath(filePath)
|
|
95
|
+
}));
|
|
96
|
+
const suiteFiles = uniqueSuitePaths.map((filePath) => ({
|
|
97
|
+
path: filePath,
|
|
98
|
+
relativePath: relative(workingDir, filePath),
|
|
99
|
+
fileName: basename(filePath),
|
|
100
|
+
protocol: getSuiteProtocolType(filePath),
|
|
101
|
+
isTemplate: filePath.endsWith(".tsuite.yaml")
|
|
102
|
+
}));
|
|
103
|
+
return { tspecFiles, suiteFiles, errors: errors2 };
|
|
104
|
+
}
|
|
49
105
|
function formatJson(data) {
|
|
50
106
|
return JSON.stringify(data, null, 2);
|
|
51
107
|
}
|
|
@@ -199,7 +255,7 @@ async function executeValidate(params) {
|
|
|
199
255
|
if (fileDescriptors.length === 0) {
|
|
200
256
|
return {
|
|
201
257
|
success: false,
|
|
202
|
-
output: "No .
|
|
258
|
+
output: "No .tcase files found",
|
|
203
259
|
data: { results: [] }
|
|
204
260
|
};
|
|
205
261
|
}
|
|
@@ -222,7 +278,7 @@ async function executeValidate(params) {
|
|
|
222
278
|
data: { results }
|
|
223
279
|
};
|
|
224
280
|
}
|
|
225
|
-
const validateCommand = new Command("validate").description("Validate .
|
|
281
|
+
const validateCommand = new Command("validate").description("Validate .tcase files for schema correctness").argument("<files...>", "Files or glob patterns to validate").option("-o, --output <format>", "Output format: json, text", "text").option("-q, --quiet", "Only output errors").action(async (files, options) => {
|
|
226
282
|
setLoggerOptions({ quiet: options.quiet });
|
|
227
283
|
const spinner = options.quiet ? null : ora("Validating...").start();
|
|
228
284
|
try {
|
|
@@ -304,11 +360,11 @@ async function executeRun(params) {
|
|
|
304
360
|
const output = params.output ?? "text";
|
|
305
361
|
const verbose = params.verbose ?? false;
|
|
306
362
|
const quiet = params.quiet ?? false;
|
|
307
|
-
const {
|
|
308
|
-
if (
|
|
363
|
+
const { tspecFiles, suiteFiles, errors: resolveErrors } = await discoverAllTestFiles(params.files);
|
|
364
|
+
if (tspecFiles.length === 0 && suiteFiles.length === 0) {
|
|
309
365
|
return {
|
|
310
366
|
success: false,
|
|
311
|
-
output: "No .
|
|
367
|
+
output: "No .tcase or .tsuite files found",
|
|
312
368
|
data: {
|
|
313
369
|
results: [],
|
|
314
370
|
summary: { total: 0, passed: 0, failed: 0, passRate: 0, duration: 0 },
|
|
@@ -316,6 +372,29 @@ async function executeRun(params) {
|
|
|
316
372
|
}
|
|
317
373
|
};
|
|
318
374
|
}
|
|
375
|
+
if (suiteFiles.length > 0) {
|
|
376
|
+
return executeSuiteRun(suiteFiles, tspecFiles, {
|
|
377
|
+
env,
|
|
378
|
+
params: paramValues,
|
|
379
|
+
concurrency,
|
|
380
|
+
failFast,
|
|
381
|
+
output,
|
|
382
|
+
verbose,
|
|
383
|
+
quiet
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
return executeTspecRun(tspecFiles, {
|
|
387
|
+
env,
|
|
388
|
+
params: paramValues,
|
|
389
|
+
concurrency,
|
|
390
|
+
failFast,
|
|
391
|
+
output,
|
|
392
|
+
verbose,
|
|
393
|
+
quiet
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
async function executeTspecRun(fileDescriptors, options) {
|
|
397
|
+
const { env, params: paramValues, concurrency, failFast, output, verbose, quiet } = options;
|
|
319
398
|
const allResults = [];
|
|
320
399
|
const parseErrors = [];
|
|
321
400
|
let totalTestCases = 0;
|
|
@@ -384,6 +463,116 @@ ${parseErrors.length} file(s) failed to parse:`);
|
|
|
384
463
|
data: { results: formattedResults, summary, parseErrors }
|
|
385
464
|
};
|
|
386
465
|
}
|
|
466
|
+
async function executeSuiteRun(suiteFiles, additionalTspecFiles, options) {
|
|
467
|
+
const { env, params: paramValues, failFast, output, verbose, quiet } = options;
|
|
468
|
+
const allResults = [];
|
|
469
|
+
const parseErrors = [];
|
|
470
|
+
let totalTests = 0;
|
|
471
|
+
let totalPassed = 0;
|
|
472
|
+
let totalFailed = 0;
|
|
473
|
+
let stopped = false;
|
|
474
|
+
for (const suiteDescriptor of suiteFiles) {
|
|
475
|
+
if (stopped) break;
|
|
476
|
+
if (suiteDescriptor.isTemplate) continue;
|
|
477
|
+
try {
|
|
478
|
+
const suiteResult = await executeSuite(suiteDescriptor.path, {
|
|
479
|
+
env,
|
|
480
|
+
params: paramValues,
|
|
481
|
+
onSuiteStart: (name) => {
|
|
482
|
+
if (!quiet) logger.log(chalk.blue(`
|
|
483
|
+
Suite: ${name}`));
|
|
484
|
+
},
|
|
485
|
+
onTestStart: (file) => {
|
|
486
|
+
if (verbose) logger.log(chalk.gray(` Running: ${file}`));
|
|
487
|
+
},
|
|
488
|
+
onTestComplete: (file, result) => {
|
|
489
|
+
const statusIcon = result.status === "passed" ? chalk.green("✓") : chalk.red("✗");
|
|
490
|
+
if (!quiet) logger.log(` ${statusIcon} ${result.name} (${result.duration}ms)`);
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
totalTests += suiteResult.stats.total;
|
|
494
|
+
totalPassed += suiteResult.stats.passed;
|
|
495
|
+
totalFailed += suiteResult.stats.failed + suiteResult.stats.error;
|
|
496
|
+
for (const testResult of suiteResult.tests) {
|
|
497
|
+
allResults.push({
|
|
498
|
+
testCaseId: testResult.name,
|
|
499
|
+
passed: testResult.status === "passed",
|
|
500
|
+
duration: testResult.duration,
|
|
501
|
+
assertions: (testResult.assertions || []).map((a) => ({
|
|
502
|
+
passed: a.passed,
|
|
503
|
+
type: a.type,
|
|
504
|
+
message: a.message || ""
|
|
505
|
+
}))
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
if (suiteResult.suites) {
|
|
509
|
+
for (const nestedSuite of suiteResult.suites) {
|
|
510
|
+
totalTests += nestedSuite.stats.total;
|
|
511
|
+
totalPassed += nestedSuite.stats.passed;
|
|
512
|
+
totalFailed += nestedSuite.stats.failed + nestedSuite.stats.error;
|
|
513
|
+
for (const testResult of nestedSuite.tests) {
|
|
514
|
+
allResults.push({
|
|
515
|
+
testCaseId: `${nestedSuite.name}/${testResult.name}`,
|
|
516
|
+
passed: testResult.status === "passed",
|
|
517
|
+
duration: testResult.duration,
|
|
518
|
+
assertions: (testResult.assertions || []).map((a) => ({
|
|
519
|
+
passed: a.passed,
|
|
520
|
+
type: a.type,
|
|
521
|
+
message: a.message || ""
|
|
522
|
+
}))
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (failFast && (suiteResult.status === "failed" || suiteResult.status === "error")) {
|
|
528
|
+
stopped = true;
|
|
529
|
+
}
|
|
530
|
+
} catch (err) {
|
|
531
|
+
parseErrors.push({
|
|
532
|
+
file: suiteDescriptor.path,
|
|
533
|
+
error: err instanceof Error ? err.message : String(err)
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (additionalTspecFiles.length > 0 && !stopped) {
|
|
538
|
+
const tspecResult = await executeTspecRun(additionalTspecFiles, options);
|
|
539
|
+
allResults.push(...tspecResult.data.results);
|
|
540
|
+
parseErrors.push(...tspecResult.data.parseErrors);
|
|
541
|
+
totalTests += tspecResult.data.summary.total;
|
|
542
|
+
totalPassed += tspecResult.data.summary.passed;
|
|
543
|
+
totalFailed += tspecResult.data.summary.failed;
|
|
544
|
+
}
|
|
545
|
+
const summary = {
|
|
546
|
+
total: totalTests,
|
|
547
|
+
passed: totalPassed,
|
|
548
|
+
failed: totalFailed,
|
|
549
|
+
passRate: totalTests > 0 ? totalPassed / totalTests * 100 : 0,
|
|
550
|
+
duration: 0
|
|
551
|
+
};
|
|
552
|
+
let outputStr;
|
|
553
|
+
if (output === "json") {
|
|
554
|
+
outputStr = formatJson({ results: allResults, summary, parseErrors });
|
|
555
|
+
} else {
|
|
556
|
+
const parts = [];
|
|
557
|
+
if (!quiet) {
|
|
558
|
+
parts.push("\n" + chalk.bold("Results:"));
|
|
559
|
+
parts.push(formatTestResults(allResults, summary, { format: output, verbose }));
|
|
560
|
+
} else {
|
|
561
|
+
parts.push(`${summary.passed}/${summary.total} tests passed (${summary.passRate.toFixed(1)}%)`);
|
|
562
|
+
}
|
|
563
|
+
if (parseErrors.length > 0) {
|
|
564
|
+
parts.push(`
|
|
565
|
+
${parseErrors.length} file(s) failed to parse:`);
|
|
566
|
+
parseErrors.forEach(({ file, error: error2 }) => parts.push(` ${file}: ${error2}`));
|
|
567
|
+
}
|
|
568
|
+
outputStr = parts.join("\n");
|
|
569
|
+
}
|
|
570
|
+
return {
|
|
571
|
+
success: totalFailed === 0 && parseErrors.length === 0,
|
|
572
|
+
output: outputStr,
|
|
573
|
+
data: { results: allResults, summary, parseErrors }
|
|
574
|
+
};
|
|
575
|
+
}
|
|
387
576
|
const runCommand = new Command("run").description("Execute test cases and report results").argument("<files...>", "Files or glob patterns to run").option("-o, --output <format>", "Output format: json, text", "text").option("-c, --concurrency <number>", "Max concurrent tests", "5").option("-e, --env <key=value>", "Environment variables", parseKeyValue$1, {}).option("-p, --params <key=value>", "Parameters", parseKeyValue$1, {}).option("-v, --verbose", "Verbose output").option("-q, --quiet", "Only output summary").option("--fail-fast", "Stop on first failure").action(async (files, options) => {
|
|
388
577
|
setLoggerOptions({ verbose: options.verbose, quiet: options.quiet });
|
|
389
578
|
const spinner = options.quiet ? null : ora("Running tests...").start();
|
|
@@ -438,7 +627,7 @@ async function executeParse(params) {
|
|
|
438
627
|
if (fileDescriptors.length === 0) {
|
|
439
628
|
return {
|
|
440
629
|
success: false,
|
|
441
|
-
output: "No .
|
|
630
|
+
output: "No .tcase files found",
|
|
442
631
|
data: {
|
|
443
632
|
testCases: [],
|
|
444
633
|
parseErrors: [],
|
|
@@ -14756,7 +14945,7 @@ const TOOL_DEFINITIONS = [
|
|
|
14756
14945
|
files: {
|
|
14757
14946
|
type: "array",
|
|
14758
14947
|
items: { type: "string" },
|
|
14759
|
-
description: 'Files or glob patterns to run (e.g., ["tests/*.
|
|
14948
|
+
description: 'Files or glob patterns to run (e.g., ["tests/*.tcase"])'
|
|
14760
14949
|
},
|
|
14761
14950
|
concurrency: {
|
|
14762
14951
|
type: "number",
|
|
@@ -14787,7 +14976,7 @@ const TOOL_DEFINITIONS = [
|
|
|
14787
14976
|
},
|
|
14788
14977
|
{
|
|
14789
14978
|
name: "tspec_validate",
|
|
14790
|
-
description: "Validate .
|
|
14979
|
+
description: "Validate .tcase files for schema correctness",
|
|
14791
14980
|
inputSchema: {
|
|
14792
14981
|
type: "object",
|
|
14793
14982
|
properties: {
|
|
@@ -14949,8 +15138,11 @@ const mcpCommand = new Command("mcp").description("Start MCP server for tool int
|
|
|
14949
15138
|
setLoggerOptions({ quiet: true });
|
|
14950
15139
|
await startMcpServer();
|
|
14951
15140
|
});
|
|
15141
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
15142
|
+
const __dirname$1 = dirname(__filename$1);
|
|
15143
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname$1, "../package.json"), "utf-8"));
|
|
14952
15144
|
const program = new Command();
|
|
14953
|
-
program.name("tspec").description("CLI for @boolesai/tspec testing framework").version(
|
|
15145
|
+
program.name("tspec").description("CLI for @boolesai/tspec testing framework").version(packageJson.version);
|
|
14954
15146
|
program.addCommand(validateCommand);
|
|
14955
15147
|
program.addCommand(runCommand);
|
|
14956
15148
|
program.addCommand(parseCommand);
|