tryscript 0.0.1 → 0.1.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/LICENSE +21 -0
- package/README.md +38 -188
- package/dist/bin.cjs +121 -32
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.mjs +120 -31
- package/dist/bin.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +72 -8
- package/dist/index.d.mts +72 -8
- package/dist/index.mjs +1 -1
- package/dist/{src-CeUA446P.cjs → src-CP4-Q-U5.cjs} +117 -15
- package/dist/src-CP4-Q-U5.cjs.map +1 -0
- package/dist/{src-UjaSQrqA.mjs → src-Ca6X7ul-.mjs} +114 -18
- package/dist/src-Ca6X7ul-.mjs.map +1 -0
- package/docs/tryscript-reference.md +362 -84
- package/package.json +17 -16
- package/dist/src-CeUA446P.cjs.map +0 -1
- package/dist/src-UjaSQrqA.mjs.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Joshua Levy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,222 +2,72 @@
|
|
|
2
2
|
|
|
3
3
|
Golden testing for CLI applications - a TypeScript port of [trycmd](https://github.com/assert-rs/trycmd).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Overview
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
tryscript enables golden testing for any CLI application. Write test cases in Markdown with console code blocks, and tryscript runs the commands, compares output, and reports differences.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
````markdown
|
|
10
|
+
# Test: Hello World
|
|
10
11
|
|
|
11
|
-
```
|
|
12
|
-
npm install tryscript
|
|
13
|
-
# or
|
|
14
|
-
pnpm add tryscript
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Quick Start
|
|
18
|
-
|
|
19
|
-
Create a test file with the `.tryscript.md` extension:
|
|
20
|
-
|
|
21
|
-
```markdown
|
|
22
|
-
# Test: Help command
|
|
23
|
-
|
|
24
|
-
\`\`\`console
|
|
25
|
-
$ my-cli --help
|
|
26
|
-
Usage: my-cli [options]
|
|
27
|
-
|
|
28
|
-
Options:
|
|
29
|
-
--version Show version
|
|
30
|
-
--help Show help
|
|
31
|
-
? 0
|
|
32
|
-
\`\`\`
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Run the tests:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npx tryscript tests/
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Test File Format
|
|
42
|
-
|
|
43
|
-
Test files are Markdown documents with console code blocks. Each code block represents a test case:
|
|
44
|
-
|
|
45
|
-
```markdown
|
|
46
|
-
\`\`\`console
|
|
47
|
-
$ <command>
|
|
48
|
-
<expected output>
|
|
49
|
-
? <exit code>
|
|
50
|
-
\`\`\`
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Example
|
|
54
|
-
|
|
55
|
-
```markdown
|
|
56
|
-
# Test: Echo command
|
|
57
|
-
|
|
58
|
-
\`\`\`console
|
|
12
|
+
```console
|
|
59
13
|
$ echo "hello world"
|
|
60
14
|
hello world
|
|
61
15
|
? 0
|
|
62
|
-
\`\`\`
|
|
63
|
-
|
|
64
|
-
# Test: Exit with error
|
|
65
|
-
|
|
66
|
-
\`\`\`console
|
|
67
|
-
$ exit 1
|
|
68
|
-
? 1
|
|
69
|
-
\`\`\`
|
|
70
16
|
```
|
|
17
|
+
````
|
|
71
18
|
|
|
72
|
-
##
|
|
73
|
-
|
|
74
|
-
Use elision patterns to match dynamic or platform-specific output:
|
|
75
|
-
|
|
76
|
-
| Pattern | Description | Example |
|
|
77
|
-
| -------- | ---------------------------------------- | -------------------------- |
|
|
78
|
-
| `[..]` | Match any characters on the current line | `Built in [..]ms` |
|
|
79
|
-
| `...` | Match zero or more complete lines | `...\nDone` |
|
|
80
|
-
| `[EXE]` | Match `.exe` on Windows, empty otherwise | `my-cli[EXE] --help` |
|
|
81
|
-
| `[ROOT]` | Match the test's root directory | `[ROOT]/output.txt` |
|
|
82
|
-
| `[CWD]` | Match the current working directory | `[CWD]/file.txt` |
|
|
19
|
+
## Features
|
|
83
20
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Elapsed: [..]ms
|
|
90
|
-
? 0
|
|
91
|
-
\`\`\`
|
|
92
|
-
```
|
|
21
|
+
- **Markdown test format** - Tests are readable documentation
|
|
22
|
+
- **Elision patterns** - Match dynamic output with `[..]`, `...`, `[EXE]`, `[ROOT]`, `[CWD]`
|
|
23
|
+
- **Custom patterns** - Define regex patterns for timestamps, versions, UUIDs
|
|
24
|
+
- **Update mode** - Regenerate golden files with `--update`
|
|
25
|
+
- **Self-bootstrapping** - tryscript tests itself
|
|
93
26
|
|
|
94
|
-
##
|
|
95
|
-
|
|
96
|
-
### YAML Frontmatter
|
|
97
|
-
|
|
98
|
-
Add configuration at the top of your test file:
|
|
27
|
+
## Quick Start
|
|
99
28
|
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
env:
|
|
104
|
-
NO_COLOR: "1"
|
|
105
|
-
timeout: 5000
|
|
106
|
-
---
|
|
29
|
+
```bash
|
|
30
|
+
# Install
|
|
31
|
+
pnpm add tryscript
|
|
107
32
|
|
|
108
|
-
#
|
|
33
|
+
# Run tests
|
|
34
|
+
npx tryscript tests/
|
|
109
35
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
1.0.0
|
|
113
|
-
? 0
|
|
114
|
-
\`\`\`
|
|
36
|
+
# Update golden files
|
|
37
|
+
npx tryscript --update
|
|
115
38
|
```
|
|
116
39
|
|
|
117
|
-
|
|
40
|
+
## Documentation
|
|
118
41
|
|
|
119
|
-
|
|
42
|
+
See [packages/tryscript/README.md](packages/tryscript/README.md) for full documentation.
|
|
120
43
|
|
|
121
|
-
|
|
122
|
-
import { defineConfig } from 'tryscript';
|
|
44
|
+
## Project Structure
|
|
123
45
|
|
|
124
|
-
export default defineConfig({
|
|
125
|
-
bin: './dist/cli.js',
|
|
126
|
-
env: {
|
|
127
|
-
NO_COLOR: '1',
|
|
128
|
-
},
|
|
129
|
-
timeout: 30000,
|
|
130
|
-
patterns: {
|
|
131
|
-
VERSION: '\\d+\\.\\d+\\.\\d+',
|
|
132
|
-
UUID: '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}',
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
46
|
```
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
47
|
+
tryscript/
|
|
48
|
+
├── packages/
|
|
49
|
+
│ └── tryscript/ # Main package
|
|
50
|
+
│ ├── src/ # TypeScript source
|
|
51
|
+
│ └── tests/ # Self-tests
|
|
52
|
+
└── docs/ # Documentation
|
|
139
53
|
```
|
|
140
|
-
tryscript [options] [files...]
|
|
141
|
-
|
|
142
|
-
Arguments:
|
|
143
|
-
files Test files to run (default: **/*.tryscript.md)
|
|
144
|
-
|
|
145
|
-
Options:
|
|
146
|
-
--version Show version number
|
|
147
|
-
--update Update golden files with actual output
|
|
148
|
-
--diff Show diff on failure (default: true)
|
|
149
|
-
--no-diff Hide diff on failure
|
|
150
|
-
--fail-fast Stop on first failure
|
|
151
|
-
--filter <pattern> Filter tests by name pattern
|
|
152
|
-
--verbose Show detailed output
|
|
153
|
-
--quiet Suppress non-essential output
|
|
154
|
-
--help Show help
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## Update Mode
|
|
158
54
|
|
|
159
|
-
|
|
55
|
+
## Development
|
|
160
56
|
|
|
161
57
|
```bash
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
This rewrites test files with the actual output from running the commands.
|
|
58
|
+
# Install dependencies
|
|
59
|
+
pnpm install
|
|
166
60
|
|
|
167
|
-
|
|
61
|
+
# Build
|
|
62
|
+
pnpm build
|
|
168
63
|
|
|
169
|
-
|
|
170
|
-
|
|
64
|
+
# Run tests
|
|
65
|
+
pnpm test
|
|
171
66
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const ctx = await createExecutionContext({}, 'test.tryscript.md');
|
|
176
|
-
for (const block of testFile.blocks) {
|
|
177
|
-
const result = await runBlock(block, ctx);
|
|
178
|
-
const matches = matchOutput(
|
|
179
|
-
result.actualOutput,
|
|
180
|
-
block.expectedOutput,
|
|
181
|
-
{ root: ctx.tempDir, cwd: ctx.tempDir },
|
|
182
|
-
);
|
|
183
|
-
console.log(`${block.name}: ${matches ? 'PASS' : 'FAIL'}`);
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
## Measuring Coverage
|
|
188
|
-
|
|
189
|
-
When testing CLI tools as subprocesses, standard coverage tools don't track execution. Use [c8](https://github.com/bcoe/c8) which leverages Node's V8 coverage collection:
|
|
190
|
-
|
|
191
|
-
```bash
|
|
192
|
-
npm install -D c8
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
Add scripts to your `package.json`:
|
|
196
|
-
|
|
197
|
-
```json
|
|
198
|
-
{
|
|
199
|
-
"scripts": {
|
|
200
|
-
"test:golden": "tryscript 'tests/**/*.tryscript.md'",
|
|
201
|
-
"test:golden:coverage": "c8 --src src --all --include 'dist/**' tryscript 'tests/**/*.tryscript.md'"
|
|
202
|
-
}
|
|
203
|
-
}
|
|
67
|
+
# Run self-tests
|
|
68
|
+
pnpm -r tryscript tests/
|
|
204
69
|
```
|
|
205
70
|
|
|
206
|
-
Key c8 flags:
|
|
207
|
-
- `--src src` — Map coverage back to source files
|
|
208
|
-
- `--all` — Include files with 0% coverage
|
|
209
|
-
- `--include 'dist/**'` — Track your built CLI output
|
|
210
|
-
|
|
211
|
-
This captures coverage from actual CLI usage—the most realistic testing possible.
|
|
212
|
-
|
|
213
|
-
## Comparison with trycmd
|
|
214
|
-
|
|
215
|
-
tryscript is a TypeScript port of the Rust [trycmd](https://github.com/assert-rs/trycmd) crate. Key differences:
|
|
216
|
-
|
|
217
|
-
- **Language**: TypeScript/Node.js instead of Rust
|
|
218
|
-
- **Format**: Uses console code blocks (trycmd uses `.toml` or `.trycmd` files)
|
|
219
|
-
- **Integration**: Works with Node.js test frameworks (Vitest, Jest)
|
|
220
|
-
|
|
221
71
|
## License
|
|
222
72
|
|
|
223
73
|
MIT
|
package/dist/bin.cjs
CHANGED
|
@@ -1,21 +1,85 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
const require_src = require('./src-
|
|
4
|
+
const require_src = require('./src-CP4-Q-U5.cjs');
|
|
5
5
|
let node_url = require("node:url");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
let node_fs_promises = require("node:fs/promises");
|
|
9
9
|
let commander = require("commander");
|
|
10
|
-
let picocolors = require("picocolors");
|
|
11
|
-
picocolors = require_src.__toESM(picocolors);
|
|
12
10
|
let fast_glob = require("fast-glob");
|
|
13
11
|
fast_glob = require_src.__toESM(fast_glob);
|
|
12
|
+
let picocolors = require("picocolors");
|
|
13
|
+
picocolors = require_src.__toESM(picocolors);
|
|
14
14
|
let diff = require("diff");
|
|
15
15
|
let atomically = require("atomically");
|
|
16
16
|
|
|
17
|
+
//#region src/cli/lib/shared.ts
|
|
18
|
+
/**
|
|
19
|
+
* Shared color utilities for consistent terminal output.
|
|
20
|
+
*/
|
|
21
|
+
const colors = {
|
|
22
|
+
success: (s) => picocolors.default.green(s),
|
|
23
|
+
error: (s) => picocolors.default.red(s),
|
|
24
|
+
info: (s) => picocolors.default.cyan(s),
|
|
25
|
+
warn: (s) => picocolors.default.yellow(s),
|
|
26
|
+
muted: (s) => picocolors.default.gray(s),
|
|
27
|
+
bold: (s) => picocolors.default.bold(s)
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Status indicators with emoji.
|
|
31
|
+
*/
|
|
32
|
+
const status = {
|
|
33
|
+
pass: picocolors.default.green("✓"),
|
|
34
|
+
fail: picocolors.default.red("✗"),
|
|
35
|
+
skip: picocolors.default.yellow("○"),
|
|
36
|
+
update: picocolors.default.yellow("↻")
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Configure Commander.js with colored help text.
|
|
40
|
+
* Applies consistent styling: cyan titles, green commands, yellow options.
|
|
41
|
+
*/
|
|
42
|
+
function withColoredHelp(cmd) {
|
|
43
|
+
cmd.configureHelp({
|
|
44
|
+
styleTitle: (str) => picocolors.default.bold(picocolors.default.cyan(str)),
|
|
45
|
+
styleCommandText: (str) => picocolors.default.green(str),
|
|
46
|
+
styleOptionText: (str) => picocolors.default.yellow(str),
|
|
47
|
+
showGlobalOptions: true
|
|
48
|
+
});
|
|
49
|
+
return cmd;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Log a warning message to stderr.
|
|
53
|
+
*/
|
|
54
|
+
function logWarn(message) {
|
|
55
|
+
console.error(colors.warn(message));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Log an error message to stderr.
|
|
59
|
+
*/
|
|
60
|
+
function logError(message) {
|
|
61
|
+
console.error(colors.error(message));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
17
65
|
//#region src/lib/reporter.ts
|
|
18
66
|
/**
|
|
67
|
+
* Test result reporting utilities.
|
|
68
|
+
*
|
|
69
|
+
* Handles output formatting for test results, diffs, and summaries.
|
|
70
|
+
*/
|
|
71
|
+
const statusIcon = {
|
|
72
|
+
pass: picocolors.default.green("✓"),
|
|
73
|
+
fail: picocolors.default.red("✗")
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Format a duration in milliseconds for display.
|
|
77
|
+
*/
|
|
78
|
+
function formatDuration(ms) {
|
|
79
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
80
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
19
83
|
* Create a unified diff between expected and actual output.
|
|
20
84
|
*/
|
|
21
85
|
function createDiff(expected, actual, filename) {
|
|
@@ -27,26 +91,19 @@ function createDiff(expected, actual, filename) {
|
|
|
27
91
|
}).join("\n");
|
|
28
92
|
}
|
|
29
93
|
/**
|
|
30
|
-
* Format a duration in milliseconds for display.
|
|
31
|
-
*/
|
|
32
|
-
function formatDuration(ms) {
|
|
33
|
-
if (ms < 1e3) return `${ms}ms`;
|
|
34
|
-
return `${(ms / 1e3).toFixed(2)}s`;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
94
|
* Report results for a single file.
|
|
38
95
|
*/
|
|
39
96
|
function reportFile(result, options) {
|
|
40
97
|
const filename = result.file.path;
|
|
41
|
-
const status = result.passed ? picocolors.default.green(picocolors.default.bold("PASS")) : picocolors.default.red(picocolors.default.bold("FAIL"));
|
|
98
|
+
const status$1 = result.passed ? picocolors.default.green(picocolors.default.bold("PASS")) : picocolors.default.red(picocolors.default.bold("FAIL"));
|
|
42
99
|
if (options.quiet && result.passed) return;
|
|
43
|
-
console.error(`${status} ${filename}`);
|
|
100
|
+
console.error(`${status$1} ${filename}`);
|
|
44
101
|
for (const blockResult of result.results) {
|
|
45
102
|
const name = blockResult.block.name ?? `Line ${blockResult.block.lineNumber}`;
|
|
46
103
|
if (blockResult.passed) {
|
|
47
|
-
if (!options.quiet) console.error(` ${
|
|
104
|
+
if (!options.quiet) console.error(` ${statusIcon.pass} ${name}`);
|
|
48
105
|
} else {
|
|
49
|
-
console.error(` ${
|
|
106
|
+
console.error(` ${statusIcon.fail} ${name}`);
|
|
50
107
|
if (blockResult.error) console.error(` ${picocolors.default.red(blockResult.error)}`);
|
|
51
108
|
else {
|
|
52
109
|
if (blockResult.actualExitCode !== blockResult.block.expectedExitCode) console.error(` Expected exit code ${blockResult.block.expectedExitCode}, got ${blockResult.actualExitCode}`);
|
|
@@ -115,6 +172,12 @@ function buildUpdatedBlock(block, result) {
|
|
|
115
172
|
|
|
116
173
|
//#endregion
|
|
117
174
|
//#region src/cli/commands/run.ts
|
|
175
|
+
/**
|
|
176
|
+
* Register the run command.
|
|
177
|
+
*/
|
|
178
|
+
function registerRunCommand(program) {
|
|
179
|
+
program.command("run").description("Run golden tests").argument("[files...]", "Test files to run (default: **/*.tryscript.md)").option("--update", "Update golden files with actual output").option("--diff", "Show diff on failure (default: true)").option("--no-diff", "Hide diff on failure").option("--fail-fast", "Stop on first failure").option("--filter <pattern>", "Filter tests by name pattern").option("--verbose", "Show detailed output including passing test output").option("--quiet", "Suppress non-essential output (only show failures)").action(runCommand);
|
|
180
|
+
}
|
|
118
181
|
async function runCommand(files, options) {
|
|
119
182
|
const startTime = Date.now();
|
|
120
183
|
const opts = {
|
|
@@ -131,7 +194,7 @@ async function runCommand(files, options) {
|
|
|
131
194
|
dot: false
|
|
132
195
|
});
|
|
133
196
|
if (testFiles.length === 0) {
|
|
134
|
-
|
|
197
|
+
logWarn("No test files found");
|
|
135
198
|
process.exit(1);
|
|
136
199
|
}
|
|
137
200
|
const globalConfig = await require_src.loadConfig(process.cwd());
|
|
@@ -146,18 +209,29 @@ async function runCommand(files, options) {
|
|
|
146
209
|
const filterPattern = new RegExp(opts.filter, "i");
|
|
147
210
|
blocksToRun = blocksToRun.filter((b) => b.name ? filterPattern.test(b.name) : true);
|
|
148
211
|
}
|
|
212
|
+
const onlyBlocks = blocksToRun.filter((b) => b.only);
|
|
213
|
+
if (onlyBlocks.length > 0) blocksToRun = onlyBlocks;
|
|
149
214
|
if (blocksToRun.length === 0) continue;
|
|
150
215
|
const ctx = await require_src.createExecutionContext(config, filePath);
|
|
151
216
|
const results = [];
|
|
152
217
|
try {
|
|
153
218
|
for (const block of blocksToRun) {
|
|
154
219
|
const result = await require_src.runBlock(block, ctx);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
220
|
+
if (result.skipped) {
|
|
221
|
+
results.push(result);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
const outputMatches = require_src.matchOutput(block.expectedStderr ? result.actualStdout ?? "" : result.actualOutput, block.expectedOutput, {
|
|
225
|
+
root: ctx.testDir,
|
|
226
|
+
cwd: ctx.cwd
|
|
227
|
+
}, config.patterns ?? {});
|
|
228
|
+
let stderrMatches = true;
|
|
229
|
+
if (block.expectedStderr) stderrMatches = require_src.matchOutput(result.actualStderr ?? "", block.expectedStderr, {
|
|
230
|
+
root: ctx.testDir,
|
|
231
|
+
cwd: ctx.cwd
|
|
158
232
|
}, config.patterns ?? {});
|
|
159
233
|
const exitCodeMatches = result.actualExitCode === block.expectedExitCode;
|
|
160
|
-
result.passed =
|
|
234
|
+
result.passed = outputMatches && stderrMatches && exitCodeMatches && !result.error;
|
|
161
235
|
if (!result.passed && opts.diff) result.diff = createDiff(block.expectedOutput, result.actualOutput, `${filePath}:${block.lineNumber}`);
|
|
162
236
|
results.push(result);
|
|
163
237
|
if (!result.passed && opts.failFast) {
|
|
@@ -165,6 +239,7 @@ async function runCommand(files, options) {
|
|
|
165
239
|
break;
|
|
166
240
|
}
|
|
167
241
|
}
|
|
242
|
+
await require_src.runAfterHook(ctx);
|
|
168
243
|
} finally {
|
|
169
244
|
await require_src.cleanupExecutionContext(ctx);
|
|
170
245
|
}
|
|
@@ -178,7 +253,7 @@ async function runCommand(files, options) {
|
|
|
178
253
|
reportFile(fileResult, opts);
|
|
179
254
|
if (opts.update && !fileResult.passed) {
|
|
180
255
|
const { updated, changes } = await updateTestFile(testFile, results);
|
|
181
|
-
if (updated) console.error(
|
|
256
|
+
if (updated) console.error(colors.warn(` ${status.update} Updated: ${changes.join(", ")}`));
|
|
182
257
|
}
|
|
183
258
|
}
|
|
184
259
|
const summary = {
|
|
@@ -266,19 +341,24 @@ function isInteractive$1() {
|
|
|
266
341
|
return process.stdout.isTTY === true;
|
|
267
342
|
}
|
|
268
343
|
/**
|
|
344
|
+
* Display the README content.
|
|
345
|
+
* Exported for use as the default command.
|
|
346
|
+
*/
|
|
347
|
+
function showReadme(options) {
|
|
348
|
+
try {
|
|
349
|
+
const formatted = formatMarkdown$1(loadReadme(), !options?.raw && isInteractive$1());
|
|
350
|
+
console.log(formatted);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
353
|
+
console.error(picocolors.default.red(`Error: ${message}`));
|
|
354
|
+
process.exit(1);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
269
358
|
* Register the readme command.
|
|
270
359
|
*/
|
|
271
360
|
function registerReadmeCommand(program) {
|
|
272
|
-
program.command("readme").description("Display README documentation").option("--raw", "Output raw markdown without formatting").action(
|
|
273
|
-
try {
|
|
274
|
-
const formatted = formatMarkdown$1(loadReadme(), !options.raw && isInteractive$1());
|
|
275
|
-
console.log(formatted);
|
|
276
|
-
} catch (error) {
|
|
277
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
278
|
-
console.error(picocolors.default.red(`Error: ${message}`));
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
361
|
+
program.command("readme").description("Display README documentation").option("--raw", "Output raw markdown without formatting").action(showReadme);
|
|
282
362
|
}
|
|
283
363
|
|
|
284
364
|
//#endregion
|
|
@@ -372,12 +452,21 @@ function registerDocsCommand(program) {
|
|
|
372
452
|
|
|
373
453
|
//#endregion
|
|
374
454
|
//#region src/cli/cli.ts
|
|
455
|
+
/**
|
|
456
|
+
* CLI entry point for tryscript.
|
|
457
|
+
*
|
|
458
|
+
* Configures Commander.js with colored help and registers all subcommands.
|
|
459
|
+
*/
|
|
375
460
|
function run(argv) {
|
|
376
|
-
const program = new commander.Command().name("tryscript").version(require_src.VERSION, "--version", "Show version number").description("Golden testing for CLI applications").showHelpAfterError("(use --help for usage)")
|
|
461
|
+
const program = withColoredHelp(new commander.Command().name("tryscript").version(require_src.VERSION, "--version", "Show version number").description("Golden testing for CLI applications").showHelpAfterError("(use --help for usage)"));
|
|
462
|
+
registerRunCommand(program);
|
|
377
463
|
registerReadmeCommand(program);
|
|
378
464
|
registerDocsCommand(program);
|
|
465
|
+
program.action(() => {
|
|
466
|
+
program.help();
|
|
467
|
+
});
|
|
379
468
|
program.parseAsync(argv).catch((err) => {
|
|
380
|
-
|
|
469
|
+
logError(`Error: ${err.message}`);
|
|
381
470
|
process.exit(2);
|
|
382
471
|
});
|
|
383
472
|
}
|