@git.zone/tstest 3.1.8 → 3.3.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/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/tstest.classes.migration.js +4 -4
- package/dist_ts/tstest.classes.runtime.bun.js +5 -5
- package/dist_ts/tstest.classes.runtime.chromium.js +12 -10
- package/dist_ts/tstest.classes.runtime.deno.d.ts +4 -0
- package/dist_ts/tstest.classes.runtime.deno.js +22 -27
- package/dist_ts/tstest.classes.runtime.docker.js +2 -2
- package/dist_ts/tstest.classes.runtime.node.js +5 -5
- package/dist_ts/tstest.classes.tap.parser.js +6 -7
- package/dist_ts/tstest.classes.testdirectory.d.ts +1 -1
- package/dist_ts/tstest.classes.testdirectory.js +11 -12
- package/dist_ts/tstest.classes.testfile.directives.d.ts +38 -0
- package/dist_ts/tstest.classes.testfile.directives.js +191 -0
- package/dist_ts/tstest.classes.tstest.js +48 -33
- package/dist_ts/tstest.plugins.d.ts +6 -3
- package/dist_ts/tstest.plugins.js +7 -4
- package/dist_ts_tapbundle_serverside/classes.tapnodetools.d.ts +30 -0
- package/dist_ts_tapbundle_serverside/classes.tapnodetools.js +100 -3
- package/dist_ts_tapbundle_serverside/classes.testfileprovider.js +3 -3
- package/dist_ts_tapbundle_serverside/plugins.d.ts +4 -1
- package/dist_ts_tapbundle_serverside/plugins.js +5 -2
- package/npmextra.json +1 -1
- package/package.json +17 -16
- package/readme.hints.md +1 -1
- package/readme.md +329 -860
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/tstest.classes.migration.ts +3 -6
- package/ts/tstest.classes.runtime.bun.ts +4 -4
- package/ts/tstest.classes.runtime.chromium.ts +8 -12
- package/ts/tstest.classes.runtime.deno.ts +22 -26
- package/ts/tstest.classes.runtime.docker.ts +1 -1
- package/ts/tstest.classes.runtime.node.ts +4 -4
- package/ts/tstest.classes.tap.parser.ts +5 -7
- package/ts/tstest.classes.testdirectory.ts +19 -20
- package/ts/tstest.classes.testfile.directives.ts +226 -0
- package/ts/tstest.classes.tstest.ts +60 -43
- package/ts/tstest.plugins.ts +8 -3
package/readme.md
CHANGED
|
@@ -1,262 +1,97 @@
|
|
|
1
1
|
# @git.zone/tstest
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
🧪 **A powerful, modern test runner for TypeScript** — beautiful output, multi-runtime support, and a batteries-included test framework that makes testing actually enjoyable.
|
|
3
4
|
|
|
4
5
|
## Availability and Links
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
- [npmjs.org (npm package)](https://www.npmjs.com/package/@git.zone/tstest)
|
|
8
|
+
- [code.foss.global (source)](https://code.foss.global/git.zone/tstest)
|
|
7
9
|
|
|
8
10
|
## Issue Reporting and Security
|
|
9
11
|
|
|
10
|
-
For reporting bugs, issues, or security vulnerabilities, please visit https://community.foss.global
|
|
12
|
+
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
|
11
13
|
|
|
12
14
|
## Why tstest?
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
- 📊 **Multiple Output Modes** - Choose from normal, quiet, verbose, or JSON output
|
|
22
|
-
- 🔍 **Automatic Discovery** - Finds all your test files automatically
|
|
23
|
-
- 📝 **Detailed Logging** - Optional file logging for debugging
|
|
24
|
-
- ⚡ **Performance Metrics** - See which tests are slow
|
|
25
|
-
- 🤖 **CI/CD Ready** - JSON output mode for automation
|
|
26
|
-
- 🏷️ **Tag-based Filtering** - Run only tests with specific tags
|
|
27
|
-
- 🎯 **Parallel Test Execution** - Run tests in parallel groups
|
|
28
|
-
- 🔧 **Test Lifecycle Hooks** - beforeEach/afterEach support
|
|
29
|
-
- 📸 **Snapshot Testing** - Compare test outputs with saved snapshots
|
|
30
|
-
- ⏳ **Timeout Control** - Set custom timeouts for tests
|
|
31
|
-
- 🔁 **Retry Logic** - Automatically retry failing tests
|
|
32
|
-
- 🛠️ **Test Fixtures** - Create reusable test data
|
|
33
|
-
- 👀 **Watch Mode** - Automatically re-run tests on file changes
|
|
34
|
-
- 📊 **Real-time Progress** - Live test execution progress updates
|
|
35
|
-
- 🎨 **Visual Diffs** - Beautiful side-by-side diffs for failed assertions
|
|
36
|
-
- 🔄 **Event-based Reporting** - Real-time test lifecycle events
|
|
16
|
+
Most TypeScript test runners feel like an afterthought — clunky configuration, ugly output, and poor TypeScript support. **tstest** was built from the ground up for TypeScript developers who want:
|
|
17
|
+
|
|
18
|
+
- 🎯 **Zero config** — Point it at your test directory and go
|
|
19
|
+
- 🚀 **Multi-runtime** — Run the same tests on Node.js, Deno, Bun, and Chromium
|
|
20
|
+
- 🎨 **Beautiful output** — Color-coded results with emojis, progress bars, and visual diffs
|
|
21
|
+
- ⚡ **Built-in everything** — Assertions, snapshots, fixtures, retries, timeouts, parallel execution
|
|
22
|
+
- 🔧 **Server-side tooling** — Free ports, HTTPS certs, ephemeral databases, S3 storage — all out of the box
|
|
37
23
|
|
|
38
24
|
## Installation
|
|
39
25
|
|
|
40
26
|
```bash
|
|
41
|
-
|
|
42
|
-
# or with pnpm
|
|
43
|
-
pnpm add -D @git.zone/tstest
|
|
27
|
+
pnpm install --save-dev @git.zone/tstest
|
|
44
28
|
```
|
|
45
29
|
|
|
46
|
-
##
|
|
47
|
-
|
|
48
|
-
tstest supports running your tests across multiple JavaScript runtimes, allowing you to verify cross-platform compatibility easily.
|
|
30
|
+
## Module Exports
|
|
49
31
|
|
|
50
|
-
|
|
32
|
+
tstest ships as four modules, each optimized for a different use case:
|
|
51
33
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
Name your test files with runtime specifiers to control where they run:
|
|
34
|
+
| Export Path | Environment | Purpose |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `@git.zone/tstest` | CLI | Test runner — discovers and executes test files |
|
|
37
|
+
| `@git.zone/tstest/tapbundle` | Browser + Node | Core test framework — `tap`, `expect`, lifecycle hooks |
|
|
38
|
+
| `@git.zone/tstest/tapbundle_serverside` | Node.js only | Server-side utilities — ports, certs, databases, shell |
|
|
39
|
+
| `@git.zone/tstest/tapbundle_protocol` | Isomorphic | TAP Protocol V2 — structured metadata, events, diffs |
|
|
60
40
|
|
|
61
|
-
|
|
62
|
-
|---------|----------|---------|
|
|
63
|
-
| `*.ts` | Node.js only (default) | `test.api.ts` |
|
|
64
|
-
| `*.node.ts` | Node.js only | `test.server.node.ts` |
|
|
65
|
-
| `*.chromium.ts` | Chromium browser | `test.dom.chromium.ts` |
|
|
66
|
-
| `*.deno.ts` | Deno runtime | `test.http.deno.ts` |
|
|
67
|
-
| `*.bun.ts` | Bun runtime | `test.fast.bun.ts` |
|
|
68
|
-
| `*.all.ts` | All runtimes (Node, Chromium, Deno, Bun) | `test.universal.all.ts` |
|
|
69
|
-
| `*.node+chromium.ts` | Both Node.js and Chromium | `test.isomorphic.node+chromium.ts` |
|
|
70
|
-
| `*.node+deno.ts` | Both Node.js and Deno | `test.cross.node+deno.ts` |
|
|
71
|
-
| `*.deno+bun.ts` | Both Deno and Bun | `test.modern.deno+bun.ts` |
|
|
72
|
-
| `*.chromium.nonci.ts` | Chromium, skip in CI | `test.visual.chromium.nonci.ts` |
|
|
73
|
-
| `*.all.nonci.ts` | All runtimes, skip in CI | `test.comprehensive.all.nonci.ts` |
|
|
41
|
+
## Quick Start
|
|
74
42
|
|
|
75
|
-
|
|
43
|
+
### 1. Write a test
|
|
76
44
|
|
|
77
45
|
```typescript
|
|
78
|
-
// test.
|
|
79
|
-
import {
|
|
46
|
+
// test/test.math.ts
|
|
47
|
+
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
|
80
48
|
|
|
81
|
-
tap.test('
|
|
82
|
-
|
|
83
|
-
expect(response.status).toEqual(200);
|
|
49
|
+
tap.test('should add numbers', async () => {
|
|
50
|
+
expect(2 + 2).toEqual(4);
|
|
84
51
|
});
|
|
85
52
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// test.api.node+deno+bun.ts - runs in specific runtimes
|
|
91
|
-
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
92
|
-
|
|
93
|
-
tap.test('cross-runtime HTTP test', async () => {
|
|
94
|
-
const response = await fetch('https://api.example.com/test');
|
|
95
|
-
expect(response.status).toEqual(200);
|
|
53
|
+
tap.test('should handle async operations', async (tools) => {
|
|
54
|
+
await tools.delayFor(100);
|
|
55
|
+
const result = await fetchData();
|
|
56
|
+
expect(result).toBeTruthy();
|
|
96
57
|
});
|
|
97
58
|
|
|
98
59
|
export default tap.start();
|
|
99
60
|
```
|
|
100
61
|
|
|
101
|
-
###
|
|
102
|
-
|
|
103
|
-
When multiple runtimes are specified, tests execute in this order:
|
|
104
|
-
1. Node.js
|
|
105
|
-
2. Bun
|
|
106
|
-
3. Deno
|
|
107
|
-
4. Chromium
|
|
108
|
-
|
|
109
|
-
### Legacy Naming (Deprecated)
|
|
110
|
-
|
|
111
|
-
The following patterns are still supported but deprecated. Use the migration tool to update:
|
|
112
|
-
|
|
113
|
-
| Legacy Pattern | Modern Equivalent | Migration Command |
|
|
114
|
-
|----------------|-------------------|-------------------|
|
|
115
|
-
| `*.browser.ts` | `*.chromium.ts` | `tstest migrate` |
|
|
116
|
-
| `*.both.ts` | `*.node+chromium.ts` | `tstest migrate` |
|
|
117
|
-
|
|
118
|
-
When running legacy files, tstest shows a deprecation warning with the suggested new name.
|
|
119
|
-
|
|
120
|
-
### Migration Tool
|
|
121
|
-
|
|
122
|
-
Migrate your test files from legacy naming to the new convention:
|
|
62
|
+
### 2. Run it
|
|
123
63
|
|
|
124
64
|
```bash
|
|
125
|
-
#
|
|
126
|
-
tstest migrate --dry-run
|
|
127
|
-
|
|
128
|
-
# Apply migrations (uses git mv to preserve history)
|
|
129
|
-
tstest migrate --write
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
**Migration Features:**
|
|
133
|
-
- ✅ Uses `git mv` to preserve file history
|
|
134
|
-
- ✅ Idempotent - safe to run multiple times
|
|
135
|
-
- ✅ Dry-run by default for safety
|
|
136
|
-
- ✅ Colored output showing all changes
|
|
137
|
-
- ✅ Handles modifiers like `.nonci` correctly
|
|
138
|
-
|
|
139
|
-
Example output:
|
|
140
|
-
```
|
|
141
|
-
============================================================
|
|
142
|
-
Test File Migration Tool
|
|
143
|
-
============================================================
|
|
144
|
-
|
|
145
|
-
🔍 DRY RUN MODE - No files will be modified
|
|
146
|
-
|
|
147
|
-
Found 3 legacy test file(s)
|
|
148
|
-
|
|
149
|
-
Would migrate:
|
|
150
|
-
test.browser.ts
|
|
151
|
-
→ test.chromium.ts
|
|
152
|
-
|
|
153
|
-
Would migrate:
|
|
154
|
-
test.both.ts
|
|
155
|
-
→ test.node+chromium.ts
|
|
156
|
-
|
|
157
|
-
Would migrate:
|
|
158
|
-
test.auth.browser.nonci.ts
|
|
159
|
-
→ test.auth.chromium.nonci.ts
|
|
160
|
-
|
|
161
|
-
============================================================
|
|
162
|
-
Summary:
|
|
163
|
-
Total legacy files: 3
|
|
164
|
-
Successfully migrated: 3
|
|
165
|
-
Errors: 0
|
|
166
|
-
============================================================
|
|
167
|
-
|
|
168
|
-
To apply these changes, run:
|
|
169
|
-
tstest migrate --write
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Runtime-Specific Permissions
|
|
173
|
-
|
|
174
|
-
#### Deno Runtime
|
|
175
|
-
|
|
176
|
-
Tests run with these permissions by default:
|
|
177
|
-
```bash
|
|
178
|
-
--allow-read
|
|
179
|
-
--allow-env
|
|
180
|
-
--allow-net
|
|
181
|
-
--allow-write
|
|
182
|
-
--allow-sys
|
|
183
|
-
--allow-import # Enables npm packages and Node.js built-ins
|
|
184
|
-
--node-modules-dir # Node.js compatibility mode
|
|
185
|
-
--sloppy-imports # Allows .js imports to resolve to .ts files
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
Configure custom permissions in your test file or via environment variables.
|
|
189
|
-
|
|
190
|
-
#### Bun Runtime
|
|
191
|
-
|
|
192
|
-
Bun runs with its native TypeScript support and full access to Node.js APIs.
|
|
193
|
-
|
|
194
|
-
## Usage
|
|
195
|
-
|
|
196
|
-
### Basic Test Execution
|
|
197
|
-
|
|
198
|
-
```bash
|
|
199
|
-
# Run all tests in a directory
|
|
65
|
+
# Run all tests
|
|
200
66
|
tstest test/
|
|
201
67
|
|
|
202
|
-
# Run a specific
|
|
203
|
-
tstest test/test.
|
|
68
|
+
# Run a specific file
|
|
69
|
+
tstest test/test.math.ts
|
|
204
70
|
|
|
205
71
|
# Use glob patterns
|
|
206
|
-
tstest "test/**/*.
|
|
207
|
-
tstest "test/unit/*.ts"
|
|
208
|
-
```
|
|
72
|
+
tstest "test/**/*.ts"
|
|
209
73
|
|
|
210
|
-
|
|
74
|
+
# Verbose mode (shows console output)
|
|
75
|
+
tstest test/ --verbose
|
|
211
76
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
2. **File mode** - Runs a single test file
|
|
216
|
-
3. **Glob mode** - Uses pattern matching for flexible test selection
|
|
77
|
+
# Watch mode
|
|
78
|
+
tstest test/ --watch
|
|
79
|
+
```
|
|
217
80
|
|
|
218
|
-
###
|
|
81
|
+
### 3. See beautiful output
|
|
219
82
|
|
|
220
|
-
| Option | Description |
|
|
221
|
-
|--------|-------------|
|
|
222
|
-
| `--quiet`, `-q` | Minimal output - perfect for CI environments |
|
|
223
|
-
| `--verbose`, `-v` | Show all console output from tests |
|
|
224
|
-
| `--no-color` | Disable colored output |
|
|
225
|
-
| `--json` | Output results as JSON |
|
|
226
|
-
| `--logfile` | Save detailed logs with automatic error and diff tracking |
|
|
227
|
-
| `--tags <tags>` | Run only tests with specific tags (comma-separated) |
|
|
228
|
-
| `--timeout <seconds>` | Timeout test files after specified seconds |
|
|
229
|
-
| `--startFrom <n>` | Start running from test file number n |
|
|
230
|
-
| `--stopAt <n>` | Stop running at test file number n |
|
|
231
|
-
| `--watch`, `-w` | Watch for file changes and re-run tests |
|
|
232
|
-
| `--watch-ignore <patterns>` | Ignore patterns in watch mode (comma-separated) |
|
|
233
|
-
| `--only` | Run only tests marked with .only |
|
|
234
|
-
|
|
235
|
-
### Example Outputs
|
|
236
|
-
|
|
237
|
-
#### Normal Output (Default)
|
|
238
83
|
```
|
|
239
84
|
🔍 Test Discovery
|
|
240
85
|
Mode: directory
|
|
241
86
|
Pattern: test
|
|
242
87
|
Found: 4 test file(s)
|
|
243
88
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
▶️ test/test.node+deno.ts (1/4)
|
|
89
|
+
▶️ test/test.math.ts (1/4)
|
|
247
90
|
Runtime: Node.js
|
|
248
|
-
✅
|
|
249
|
-
✅
|
|
91
|
+
✅ should add numbers (2ms)
|
|
92
|
+
✅ should handle async operations (105ms)
|
|
250
93
|
Summary: 2/2 PASSED in 1.2s
|
|
251
94
|
|
|
252
|
-
━━━ Part 2: Deno ━━━
|
|
253
|
-
|
|
254
|
-
▶️ test/test.node+deno.ts (1/4)
|
|
255
|
-
Runtime: Deno
|
|
256
|
-
✅ HTTP request works (15ms)
|
|
257
|
-
✅ JSON parsing works (2ms)
|
|
258
|
-
Summary: 2/2 PASSED in 1.1s
|
|
259
|
-
|
|
260
95
|
📊 Test Summary
|
|
261
96
|
┌────────────────────────────────┐
|
|
262
97
|
│ Total Files: 4 │
|
|
@@ -269,331 +104,171 @@ tstest "test/unit/*.ts"
|
|
|
269
104
|
ALL TESTS PASSED! 🎉
|
|
270
105
|
```
|
|
271
106
|
|
|
272
|
-
|
|
273
|
-
```
|
|
274
|
-
Found 4 tests
|
|
275
|
-
✅ test functionality works
|
|
276
|
-
✅ api calls return expected data
|
|
277
|
-
✅ error handling works correctly
|
|
278
|
-
✅ performance is within limits
|
|
279
|
-
|
|
280
|
-
Summary: 4/4 | 542ms | PASSED
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
#### Verbose Mode
|
|
284
|
-
Shows all console output from your tests, making debugging easier:
|
|
285
|
-
```
|
|
286
|
-
▶️ test/api.test.ts (1/1)
|
|
287
|
-
Runtime: node.js
|
|
288
|
-
Making API call to /users...
|
|
289
|
-
Response received: 200 OK
|
|
290
|
-
Processing user data...
|
|
291
|
-
✅ api calls return expected data (145ms)
|
|
292
|
-
Summary: 1/1 PASSED
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
#### JSON Mode
|
|
296
|
-
Perfect for CI/CD pipelines:
|
|
297
|
-
```json
|
|
298
|
-
{"event":"discovery","count":4,"pattern":"test","executionMode":"directory"}
|
|
299
|
-
{"event":"fileStart","filename":"test/test.ts","runtime":"node.js","index":1,"total":4}
|
|
300
|
-
{"event":"testResult","testName":"prepare test","passed":true,"duration":1}
|
|
301
|
-
{"event":"summary","summary":{"totalFiles":4,"totalTests":4,"totalPassed":4,"totalFailed":0,"totalDuration":542}}
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
## Writing Tests with tapbundle
|
|
305
|
-
|
|
306
|
-
tstest includes tapbundle, a powerful TAP-based test framework. Import it from the embedded tapbundle:
|
|
307
|
-
|
|
308
|
-
```typescript
|
|
309
|
-
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
310
|
-
|
|
311
|
-
tap.test('my awesome test', async () => {
|
|
312
|
-
const result = await myFunction();
|
|
313
|
-
expect(result).toEqual('expected value');
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
export default tap.start();
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
**Module Exports**
|
|
320
|
-
|
|
321
|
-
tstest provides multiple exports for different use cases:
|
|
322
|
-
|
|
323
|
-
- `@git.zone/tstest` - Main CLI and test runner functionality
|
|
324
|
-
- `@git.zone/tstest/tapbundle` - Browser-compatible test framework
|
|
325
|
-
- `@git.zone/tstest/tapbundle_serverside` - Server-side testing utilities for Node.js-only tests (*.node.ts files)
|
|
326
|
-
- Execute shell commands during tests
|
|
327
|
-
- Manage environment variables on-demand with secure storage
|
|
328
|
-
- Generate self-signed HTTPS certificates for testing secure connections
|
|
329
|
-
- Create ephemeral MongoDB instances for database testing
|
|
330
|
-
- Create local S3-compatible storage for object storage testing
|
|
331
|
-
- Download and manage test assets (e.g., Docker images)
|
|
332
|
-
- `@git.zone/tstest/tapbundle_protocol` - Protocol V2 emitter and parser for TAP extensions
|
|
333
|
-
|
|
334
|
-
### When to Use tapbundle_serverside
|
|
335
|
-
|
|
336
|
-
Use `@git.zone/tstest/tapbundle_serverside` when your tests:
|
|
337
|
-
|
|
338
|
-
- Run exclusively on Node.js server-side (*.node.ts test files)
|
|
339
|
-
- Need to execute shell commands or interact with the file system
|
|
340
|
-
- Require environment variable management with secure on-demand prompts
|
|
341
|
-
- Test HTTPS servers and need self-signed certificates
|
|
342
|
-
- Interact with databases (MongoDB) and need ephemeral test instances
|
|
343
|
-
- Work with object storage (S3-compatible) and need local testing
|
|
344
|
-
- Require test assets like Docker images or other downloadable files
|
|
345
|
-
|
|
346
|
-
**Important:** tapbundle_serverside utilities are NOT available in:
|
|
347
|
-
- Browser environments
|
|
348
|
-
- Deno runtime
|
|
349
|
-
- Bun runtime
|
|
350
|
-
|
|
351
|
-
For cross-runtime tests, only import tapbundle_serverside in `.node.ts` files where you need server-side specific functionality.
|
|
352
|
-
|
|
353
|
-
## tapbundle Protocol V2
|
|
354
|
-
|
|
355
|
-
tstest includes an enhanced TAP protocol (Protocol V2) that extends standard TAP 13 with additional metadata while maintaining backwards compatibility.
|
|
356
|
-
|
|
357
|
-
### Overview
|
|
358
|
-
|
|
359
|
-
Protocol V2 adds structured metadata to TAP output using Unicode markers (`⟦TSTEST:...⟧`) that standard TAP parsers safely ignore. This allows for:
|
|
360
|
-
|
|
361
|
-
- **Timing information** - Test execution duration in milliseconds
|
|
362
|
-
- **Structured errors** - Stack traces, diffs, and detailed error data
|
|
363
|
-
- **Test events** - Real-time progress and lifecycle events
|
|
364
|
-
- **Snapshots** - Snapshot testing data exchange
|
|
365
|
-
- **Custom metadata** - Tags, retry counts, file locations
|
|
366
|
-
|
|
367
|
-
### Using the Protocol
|
|
368
|
-
|
|
369
|
-
```typescript
|
|
370
|
-
import {
|
|
371
|
-
ProtocolEmitter,
|
|
372
|
-
ProtocolParser,
|
|
373
|
-
PROTOCOL_MARKERS,
|
|
374
|
-
PROTOCOL_VERSION
|
|
375
|
-
} from '@git.zone/tstest/tapbundle_protocol';
|
|
376
|
-
|
|
377
|
-
// Create an emitter
|
|
378
|
-
const emitter = new ProtocolEmitter();
|
|
379
|
-
|
|
380
|
-
// Emit protocol header
|
|
381
|
-
console.log(emitter.emitProtocolHeader());
|
|
382
|
-
// Output: ⟦TSTEST:PROTOCOL:2.0.0⟧
|
|
383
|
-
|
|
384
|
-
// Emit TAP version
|
|
385
|
-
console.log(emitter.emitTapVersion(13));
|
|
386
|
-
// Output: TAP version 13
|
|
387
|
-
|
|
388
|
-
// Emit a test result with metadata
|
|
389
|
-
const testResult = {
|
|
390
|
-
ok: true,
|
|
391
|
-
testNumber: 1,
|
|
392
|
-
description: 'user authentication works',
|
|
393
|
-
metadata: {
|
|
394
|
-
time: 123,
|
|
395
|
-
tags: ['auth', 'unit']
|
|
396
|
-
}
|
|
397
|
-
};
|
|
398
|
-
console.log(emitter.emitTest(testResult).join('\n'));
|
|
399
|
-
// Output: ok 1 - user authentication works ⟦TSTEST:time:123⟧
|
|
400
|
-
// ⟦TSTEST:META:{"tags":["auth","unit"]}⟧
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
### Protocol Markers
|
|
404
|
-
|
|
405
|
-
```typescript
|
|
406
|
-
PROTOCOL_MARKERS = {
|
|
407
|
-
START: '⟦TSTEST:',
|
|
408
|
-
END: '⟧',
|
|
409
|
-
META_PREFIX: 'META:',
|
|
410
|
-
ERROR_PREFIX: 'ERROR',
|
|
411
|
-
SNAPSHOT_PREFIX: 'SNAPSHOT:',
|
|
412
|
-
SKIP_PREFIX: 'SKIP:',
|
|
413
|
-
TODO_PREFIX: 'TODO:',
|
|
414
|
-
EVENT_PREFIX: 'EVENT:'
|
|
415
|
-
}
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
### Use Cases
|
|
419
|
-
|
|
420
|
-
#### Creating Custom Test Runners
|
|
107
|
+
## Multi-Runtime Architecture
|
|
421
108
|
|
|
422
|
-
|
|
423
|
-
import { ProtocolEmitter } from '@git.zone/tstest/tapbundle_protocol';
|
|
109
|
+
tstest supports running your tests across **four JavaScript runtimes**, letting you verify cross-platform compatibility with zero extra effort.
|
|
424
110
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
// Emit header and version
|
|
428
|
-
console.log(emitter.emitProtocolHeader());
|
|
429
|
-
console.log(emitter.emitTapVersion(13));
|
|
430
|
-
console.log(emitter.emitPlan({ start: 1, end: 2 }));
|
|
111
|
+
### Test File Naming Convention
|
|
431
112
|
|
|
432
|
-
|
|
433
|
-
const startTime = Date.now();
|
|
434
|
-
// ... run test ...
|
|
435
|
-
const duration = Date.now() - startTime;
|
|
113
|
+
Name your test files with runtime specifiers to control where they run:
|
|
436
114
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
115
|
+
| Pattern | Runtimes | Example |
|
|
116
|
+
|---------|----------|---------|
|
|
117
|
+
| `*.ts` | Node.js (default) | `test.api.ts` |
|
|
118
|
+
| `*.node.ts` | Node.js only | `test.server.node.ts` |
|
|
119
|
+
| `*.chromium.ts` | Chromium browser | `test.dom.chromium.ts` |
|
|
120
|
+
| `*.deno.ts` | Deno | `test.http.deno.ts` |
|
|
121
|
+
| `*.bun.ts` | Bun | `test.fast.bun.ts` |
|
|
122
|
+
| `*.all.ts` | All runtimes | `test.universal.all.ts` |
|
|
123
|
+
| `*.node+chromium.ts` | Node.js + Chromium | `test.isomorphic.node+chromium.ts` |
|
|
124
|
+
| `*.node+deno.ts` | Node.js + Deno | `test.cross.node+deno.ts` |
|
|
125
|
+
| `*.chromium.nonci.ts` | Chromium, skip in CI | `test.visual.chromium.nonci.ts` |
|
|
444
126
|
|
|
445
|
-
|
|
127
|
+
### Runtime Execution Order
|
|
446
128
|
|
|
447
|
-
|
|
448
|
-
import { ProtocolParser } from '@git.zone/tstest/tapbundle_protocol';
|
|
129
|
+
When multiple runtimes are specified, tests execute in this order: **Node.js → Bun → Deno → Chromium**
|
|
449
130
|
|
|
450
|
-
|
|
131
|
+
### Migration from Legacy Naming
|
|
451
132
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
parser.parseLine('1..1');
|
|
456
|
-
parser.parseLine('ok 1 - test name ⟦TSTEST:time:123⟧');
|
|
133
|
+
```bash
|
|
134
|
+
# Dry run — see what would change
|
|
135
|
+
tstest migrate --dry-run
|
|
457
136
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
console.log(results);
|
|
137
|
+
# Apply migrations (uses git mv to preserve history)
|
|
138
|
+
tstest migrate --write
|
|
461
139
|
```
|
|
462
140
|
|
|
463
|
-
|
|
141
|
+
| Legacy Pattern | Modern Equivalent |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `*.browser.ts` | `*.chromium.ts` |
|
|
144
|
+
| `*.both.ts` | `*.node+chromium.ts` |
|
|
464
145
|
|
|
465
|
-
|
|
146
|
+
## CLI Options
|
|
466
147
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
148
|
+
| Option | Description |
|
|
149
|
+
|---|---|
|
|
150
|
+
| `--quiet`, `-q` | Minimal output — perfect for CI |
|
|
151
|
+
| `--verbose`, `-v` | Show all console output from tests |
|
|
152
|
+
| `--no-color` | Disable colored output |
|
|
153
|
+
| `--json` | Output results as JSON (CI/CD pipelines) |
|
|
154
|
+
| `--logfile` | Save detailed logs with error/diff tracking |
|
|
155
|
+
| `--tags <tags>` | Run only tests with specific tags |
|
|
156
|
+
| `--timeout <seconds>` | Timeout test files after N seconds |
|
|
157
|
+
| `--startFrom <n>` | Start from test file number N |
|
|
158
|
+
| `--stopAt <n>` | Stop at test file number N |
|
|
159
|
+
| `--watch`, `-w` | Re-run tests on file changes |
|
|
160
|
+
| `--watch-ignore <patterns>` | Ignore patterns in watch mode |
|
|
161
|
+
| `--only` | Run only tests marked with `.only` |
|
|
474
162
|
|
|
475
|
-
##
|
|
163
|
+
## Writing Tests with tapbundle
|
|
476
164
|
|
|
477
|
-
### Basic
|
|
165
|
+
### Basic Syntax
|
|
478
166
|
|
|
479
167
|
```typescript
|
|
480
168
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
|
481
169
|
|
|
482
|
-
|
|
483
|
-
tap.test('should perform basic arithmetic', async () => {
|
|
170
|
+
tap.test('basic test', async () => {
|
|
484
171
|
expect(2 + 2).toEqual(4);
|
|
485
172
|
});
|
|
486
173
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
expect(result).toBeDefined();
|
|
174
|
+
tap.test('with tools', async (tools) => {
|
|
175
|
+
await tools.delayFor(100);
|
|
176
|
+
tools.timeout(5000);
|
|
177
|
+
expect(true).toBeTrue();
|
|
492
178
|
});
|
|
493
179
|
|
|
494
|
-
// Start test execution
|
|
495
180
|
export default tap.start();
|
|
496
181
|
```
|
|
497
182
|
|
|
498
|
-
### Test Modifiers
|
|
183
|
+
### Test Modifiers
|
|
499
184
|
|
|
500
185
|
```typescript
|
|
501
|
-
// Skip
|
|
502
|
-
tap.skip.test('not ready yet', async () => {
|
|
503
|
-
// This test will be skipped
|
|
504
|
-
});
|
|
186
|
+
// Skip
|
|
187
|
+
tap.skip.test('not ready yet', async () => { /* skipped */ });
|
|
505
188
|
|
|
506
|
-
//
|
|
507
|
-
tap.only.test('focus on this', async () => {
|
|
508
|
-
// Only this test will run
|
|
509
|
-
});
|
|
189
|
+
// Only (exclusive)
|
|
190
|
+
tap.only.test('focus on this', async () => { /* only this runs */ });
|
|
510
191
|
|
|
511
|
-
// Todo
|
|
512
|
-
tap.todo.test('implement later', async () => {
|
|
513
|
-
// This test will be counted but marked as todo
|
|
514
|
-
});
|
|
192
|
+
// Todo
|
|
193
|
+
tap.todo.test('implement later', async () => { /* marked as todo */ });
|
|
515
194
|
|
|
516
|
-
//
|
|
195
|
+
// Fluent chaining
|
|
517
196
|
tap.timeout(5000)
|
|
518
197
|
.retry(3)
|
|
519
198
|
.tags('api', 'integration')
|
|
520
|
-
.test('complex test', async (tools) => {
|
|
521
|
-
// Test with 5s timeout, 3 retries, and tags
|
|
522
|
-
});
|
|
199
|
+
.test('complex test', async (tools) => { /* configured */ });
|
|
523
200
|
```
|
|
524
201
|
|
|
525
202
|
### Test Organization with describe()
|
|
526
203
|
|
|
527
204
|
```typescript
|
|
528
205
|
tap.describe('User Management', () => {
|
|
529
|
-
let testDatabase;
|
|
530
|
-
|
|
531
206
|
tap.beforeEach(async () => {
|
|
532
|
-
|
|
207
|
+
// setup before each test
|
|
533
208
|
});
|
|
534
209
|
|
|
535
210
|
tap.afterEach(async () => {
|
|
536
|
-
|
|
211
|
+
// cleanup after each test
|
|
537
212
|
});
|
|
538
213
|
|
|
539
|
-
tap.test('should create user', async () => {
|
|
540
|
-
|
|
541
|
-
expect(user.id).toBeDefined();
|
|
542
|
-
});
|
|
214
|
+
tap.test('should create user', async () => { /* ... */ });
|
|
215
|
+
tap.test('should delete user', async () => { /* ... */ });
|
|
543
216
|
|
|
544
|
-
tap.describe('
|
|
545
|
-
tap.test('should set admin role', async () => {
|
|
546
|
-
// Nested describe blocks
|
|
547
|
-
});
|
|
217
|
+
tap.describe('Permissions', () => {
|
|
218
|
+
tap.test('should set admin role', async () => { /* ... */ });
|
|
548
219
|
});
|
|
549
220
|
});
|
|
550
221
|
```
|
|
551
222
|
|
|
552
|
-
###
|
|
553
|
-
|
|
554
|
-
Every test function receives a `tools` parameter with utilities:
|
|
223
|
+
### Pre-Tasks and Post-Tasks
|
|
555
224
|
|
|
556
225
|
```typescript
|
|
557
|
-
tap.
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
await tools.delayForRandom(100, 500); // random delay between 100-500ms
|
|
226
|
+
tap.preTask('setup database', async () => {
|
|
227
|
+
await initializeDatabase();
|
|
228
|
+
});
|
|
561
229
|
|
|
562
|
-
|
|
563
|
-
tools.skipIf(process.env.CI === 'true', 'Skipping in CI');
|
|
230
|
+
tap.test('uses the database', async () => { /* ... */ });
|
|
564
231
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
232
|
+
tap.postTask('cleanup database', async () => {
|
|
233
|
+
await cleanupDatabase();
|
|
234
|
+
});
|
|
235
|
+
```
|
|
569
236
|
|
|
570
|
-
|
|
571
|
-
tools.todo('Needs implementation');
|
|
237
|
+
### Test Tools
|
|
572
238
|
|
|
573
|
-
|
|
574
|
-
tools.retry(3); // Set retry count
|
|
239
|
+
Every test function receives a `tools` parameter packed with utilities:
|
|
575
240
|
|
|
576
|
-
|
|
577
|
-
|
|
241
|
+
```typescript
|
|
242
|
+
tap.test('tools demo', async (tools) => {
|
|
243
|
+
// ⏱️ Delays
|
|
244
|
+
await tools.delayFor(1000);
|
|
245
|
+
await tools.delayForRandom(100, 500);
|
|
578
246
|
|
|
579
|
-
//
|
|
247
|
+
// ⏭️ Skip
|
|
248
|
+
tools.skipIf(process.env.CI === 'true', 'Skipping in CI');
|
|
249
|
+
tools.skip('reason');
|
|
250
|
+
|
|
251
|
+
// 🔁 Retry & timeout
|
|
252
|
+
tools.retry(3);
|
|
253
|
+
tools.timeout(10000);
|
|
254
|
+
|
|
255
|
+
// 📦 Context sharing between tests
|
|
580
256
|
tools.context.set('userId', 12345);
|
|
581
257
|
const userId = tools.context.get('userId');
|
|
582
258
|
|
|
583
|
-
// Deferred promises
|
|
259
|
+
// 🔮 Deferred promises
|
|
584
260
|
const deferred = tools.defer();
|
|
585
261
|
setTimeout(() => deferred.resolve('done'), 100);
|
|
586
262
|
await deferred.promise;
|
|
587
263
|
|
|
588
|
-
//
|
|
589
|
-
const coloredString = await tools.coloredString('Success!', 'green');
|
|
590
|
-
console.log(coloredString);
|
|
591
|
-
|
|
592
|
-
// Error handling helper
|
|
264
|
+
// 🎯 Error capture
|
|
593
265
|
const error = await tools.returnError(async () => {
|
|
594
266
|
throw new Error('Expected error');
|
|
595
267
|
});
|
|
596
268
|
expect(error).toBeInstanceOf(Error);
|
|
269
|
+
|
|
270
|
+
// ✅ Allow failure (test won't fail the suite)
|
|
271
|
+
tools.allowFailure();
|
|
597
272
|
});
|
|
598
273
|
```
|
|
599
274
|
|
|
@@ -602,41 +277,25 @@ tap.test('using test tools', async (tools) => {
|
|
|
602
277
|
```typescript
|
|
603
278
|
tap.test('snapshot test', async (tools) => {
|
|
604
279
|
const output = generateComplexOutput();
|
|
605
|
-
|
|
606
|
-
// Compare with saved snapshot
|
|
607
280
|
await tools.matchSnapshot(output);
|
|
608
|
-
|
|
609
|
-
// Named snapshots for multiple checks in one test
|
|
610
281
|
await tools.matchSnapshot(output.header, 'header');
|
|
611
|
-
await tools.matchSnapshot(output.body, 'body');
|
|
612
282
|
});
|
|
613
283
|
|
|
614
|
-
// Update snapshots
|
|
284
|
+
// Update snapshots: UPDATE_SNAPSHOTS=true tstest test/
|
|
615
285
|
```
|
|
616
286
|
|
|
617
287
|
### Test Fixtures
|
|
618
288
|
|
|
619
289
|
```typescript
|
|
620
|
-
// Define reusable fixtures
|
|
621
290
|
tap.defineFixture('testUser', async (data) => ({
|
|
622
291
|
id: Date.now(),
|
|
623
292
|
name: data?.name || 'Test User',
|
|
624
293
|
email: data?.email || 'test@example.com',
|
|
625
|
-
created: new Date()
|
|
626
294
|
}));
|
|
627
295
|
|
|
628
|
-
tap.defineFixture('testPost', async (data) => ({
|
|
629
|
-
id: Date.now(),
|
|
630
|
-
title: data?.title || 'Test Post',
|
|
631
|
-
authorId: data?.authorId || 1
|
|
632
|
-
}));
|
|
633
|
-
|
|
634
|
-
// Use fixtures in tests
|
|
635
296
|
tap.test('fixture test', async (tools) => {
|
|
636
297
|
const user = await tools.fixture('testUser', { name: 'John' });
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
expect(post.authorId).toEqual(user.id);
|
|
298
|
+
expect(user.name).toEqual('John');
|
|
640
299
|
|
|
641
300
|
// Factory pattern for multiple instances
|
|
642
301
|
const users = await tools.factory('testUser').createMany(5);
|
|
@@ -644,274 +303,229 @@ tap.test('fixture test', async (tools) => {
|
|
|
644
303
|
});
|
|
645
304
|
```
|
|
646
305
|
|
|
647
|
-
### Parallel
|
|
306
|
+
### Parallel Execution
|
|
648
307
|
|
|
649
308
|
```typescript
|
|
650
|
-
//
|
|
651
|
-
tap.
|
|
652
|
-
|
|
653
|
-
});
|
|
309
|
+
// Within a file
|
|
310
|
+
tap.parallel().test('parallel test 1', async () => { /* ... */ });
|
|
311
|
+
tap.parallel().test('parallel test 2', async () => { /* ... */ });
|
|
654
312
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
// File naming for parallel groups
|
|
660
|
-
// test.api.para__1.ts - runs in parallel with other para__1 files
|
|
661
|
-
// test.db.para__1.ts - runs in parallel with other para__1 files
|
|
662
|
-
// test.auth.para__2.ts - runs after para__1 group completes
|
|
313
|
+
// Across files — same suffix = parallel group
|
|
314
|
+
// test.api.para__1.ts ←─ run together
|
|
315
|
+
// test.db.para__1.ts ←─ run together
|
|
316
|
+
// test.auth.para__2.ts ←─ runs after para__1 completes
|
|
663
317
|
```
|
|
664
318
|
|
|
665
|
-
### Assertions
|
|
319
|
+
### Assertions (expect)
|
|
666
320
|
|
|
667
|
-
tapbundle uses @push.rocks/smartexpect for assertions:
|
|
321
|
+
tapbundle uses [@push.rocks/smartexpect](https://code.foss.global/push.rocks/smartexpect) for assertions with automatic diff generation on failures:
|
|
668
322
|
|
|
669
323
|
```typescript
|
|
670
|
-
//
|
|
324
|
+
// Equality
|
|
671
325
|
expect(value).toEqual(5);
|
|
672
|
-
expect(value).not.toEqual(10);
|
|
673
326
|
expect(obj).toDeepEqual({ a: 1, b: 2 });
|
|
674
327
|
|
|
675
|
-
//
|
|
328
|
+
// Types
|
|
676
329
|
expect('hello').toBeTypeofString();
|
|
677
330
|
expect(42).toBeTypeofNumber();
|
|
678
|
-
expect(true).toBeTypeofBoolean();
|
|
679
331
|
expect([]).toBeArray();
|
|
680
|
-
expect({}).toBeTypeOf('object');
|
|
681
332
|
|
|
682
|
-
//
|
|
333
|
+
// Comparisons
|
|
683
334
|
expect(5).toBeGreaterThan(3);
|
|
684
|
-
expect(3).toBeLessThan(5);
|
|
685
|
-
expect(5).toBeGreaterThanOrEqual(5);
|
|
686
|
-
expect(5).toBeLessThanOrEqual(5);
|
|
687
335
|
expect(0.1 + 0.2).toBeCloseTo(0.3, 10);
|
|
688
336
|
|
|
689
337
|
// Truthiness
|
|
690
338
|
expect(true).toBeTrue();
|
|
691
|
-
expect(false).toBeFalse();
|
|
692
|
-
expect('text').toBeTruthy();
|
|
693
|
-
expect(0).toBeFalsy();
|
|
694
339
|
expect(null).toBeNull();
|
|
695
340
|
expect(undefined).toBeUndefined();
|
|
696
|
-
expect(null).toBeNullOrUndefined();
|
|
697
341
|
|
|
698
|
-
//
|
|
342
|
+
// Strings
|
|
699
343
|
expect('hello world').toStartWith('hello');
|
|
700
344
|
expect('hello world').toEndWith('world');
|
|
701
345
|
expect('hello world').toInclude('lo wo');
|
|
702
346
|
expect('hello world').toMatch(/^hello/);
|
|
703
|
-
expect('option').toBeOneOf(['choice', 'option', 'alternative']);
|
|
704
347
|
|
|
705
|
-
//
|
|
348
|
+
// Arrays
|
|
706
349
|
expect([1, 2, 3]).toContain(2);
|
|
707
350
|
expect([1, 2, 3]).toContainAll([1, 3]);
|
|
708
|
-
expect([1, 2, 3]).toExclude(4);
|
|
709
351
|
expect([1, 2, 3]).toHaveLength(3);
|
|
710
|
-
expect([]).toBeEmptyArray();
|
|
711
|
-
expect([{ id: 1 }]).toContainEqual({ id: 1 });
|
|
712
352
|
|
|
713
|
-
//
|
|
353
|
+
// Objects
|
|
714
354
|
expect(obj).toHaveProperty('name');
|
|
715
|
-
expect(obj).toHaveProperty('user.email', 'test@example.com');
|
|
716
|
-
expect(obj).toHaveDeepProperty(['level1', 'level2']);
|
|
717
355
|
expect(obj).toMatchObject({ name: 'John' });
|
|
718
356
|
|
|
719
|
-
//
|
|
720
|
-
expect(() => { throw new Error(
|
|
721
|
-
expect((
|
|
722
|
-
expect((
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
await expect(Promise.resolve('value')).resolves.toEqual('value');
|
|
727
|
-
await expect(Promise.reject(new Error('fail'))).rejects.toThrow();
|
|
728
|
-
|
|
729
|
-
// Custom assertions
|
|
730
|
-
expect(7).customAssertion(
|
|
731
|
-
value => value % 2 === 1,
|
|
732
|
-
'Value is not odd'
|
|
733
|
-
);
|
|
357
|
+
// Functions & Promises
|
|
358
|
+
expect(() => { throw new Error(); }).toThrow();
|
|
359
|
+
await expect(Promise.resolve('val')).resolves.toEqual('val');
|
|
360
|
+
await expect(Promise.reject(new Error())).rejects.toThrow();
|
|
361
|
+
|
|
362
|
+
// Custom
|
|
363
|
+
expect(7).customAssertion(v => v % 2 === 1, 'Value is not odd');
|
|
734
364
|
```
|
|
735
365
|
|
|
736
|
-
|
|
366
|
+
## Server-Side Tools (tapbundle_serverside)
|
|
737
367
|
|
|
738
|
-
|
|
368
|
+
For Node.js-only tests, import server-side utilities:
|
|
739
369
|
|
|
740
370
|
```typescript
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
371
|
+
import { tapNodeTools } from '@git.zone/tstest/tapbundle_serverside';
|
|
372
|
+
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### 🌐 Network Utilities
|
|
376
|
+
|
|
377
|
+
Find free local ports for test servers — no more port conflicts:
|
|
745
378
|
|
|
746
|
-
|
|
747
|
-
|
|
379
|
+
```typescript
|
|
380
|
+
tap.test('should start server on free port', async () => {
|
|
381
|
+
// Single free port (random in range 3000–60000)
|
|
382
|
+
const port = await tapNodeTools.findFreePort();
|
|
383
|
+
|
|
384
|
+
// Custom range
|
|
385
|
+
const port2 = await tapNodeTools.findFreePort({ startPort: 8000, endPort: 9000 });
|
|
386
|
+
|
|
387
|
+
// With exclusions
|
|
388
|
+
const port3 = await tapNodeTools.findFreePort({ exclude: [8080, 8443] });
|
|
748
389
|
});
|
|
749
390
|
|
|
750
|
-
|
|
391
|
+
tap.test('should allocate multiple ports', async () => {
|
|
392
|
+
// Multiple distinct ports
|
|
393
|
+
const [httpPort, wsPort, adminPort] = await tapNodeTools.findFreePorts(3);
|
|
394
|
+
|
|
395
|
+
// Consecutive port range (e.g., 4000, 4001, 4002)
|
|
396
|
+
const portRange = await tapNodeTools.findFreePortRange(3, {
|
|
397
|
+
startPort: 20000,
|
|
398
|
+
endPort: 30000,
|
|
399
|
+
});
|
|
400
|
+
});
|
|
751
401
|
```
|
|
752
402
|
|
|
753
|
-
###
|
|
403
|
+
### 🔒 HTTPS Certificates
|
|
404
|
+
|
|
405
|
+
Generate self-signed certs for testing secure connections:
|
|
754
406
|
|
|
755
407
|
```typescript
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
tap.tags('integration', 'slow')
|
|
763
|
-
.test('database integration', async () => {
|
|
764
|
-
// Test code
|
|
765
|
-
});
|
|
766
|
-
|
|
767
|
-
// Run only tests with specific tags
|
|
768
|
-
// tstest test/ --tags unit,api
|
|
408
|
+
tap.test('should serve over HTTPS', async () => {
|
|
409
|
+
const { key, cert } = await tapNodeTools.createHttpsCert('localhost');
|
|
410
|
+
const server = https.createServer({ key, cert }, handler);
|
|
411
|
+
server.listen(port);
|
|
412
|
+
});
|
|
769
413
|
```
|
|
770
414
|
|
|
771
|
-
###
|
|
772
|
-
|
|
773
|
-
Share data between tests:
|
|
415
|
+
### 💻 Shell Commands
|
|
774
416
|
|
|
775
417
|
```typescript
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
});
|
|
418
|
+
const result = await tapNodeTools.runCommand('ls -la');
|
|
419
|
+
console.log(result.exitCode); // 0
|
|
420
|
+
```
|
|
780
421
|
|
|
781
|
-
|
|
782
|
-
const sessionId = tools.context.get('sessionId');
|
|
783
|
-
expect(sessionId).toBeDefined();
|
|
422
|
+
### 🔐 Environment Variables
|
|
784
423
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
424
|
+
```typescript
|
|
425
|
+
const apiKey = await tapNodeTools.getEnvVarOnDemand('GITHUB_API_KEY');
|
|
426
|
+
// Prompts if not set, stores in .nogit/.env for future use
|
|
788
427
|
```
|
|
789
428
|
|
|
790
|
-
###
|
|
429
|
+
### 🗄️ Ephemeral MongoDB
|
|
791
430
|
|
|
792
|
-
|
|
431
|
+
```typescript
|
|
432
|
+
const mongo = await tapNodeTools.createSmartmongo();
|
|
433
|
+
// ... run database tests ...
|
|
434
|
+
await mongo.stop();
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### 📦 Local S3 Storage
|
|
793
438
|
|
|
794
439
|
```typescript
|
|
795
|
-
|
|
440
|
+
const s3 = await tapNodeTools.createSmarts3();
|
|
441
|
+
// ... run object storage tests ...
|
|
442
|
+
await s3.stop();
|
|
443
|
+
```
|
|
796
444
|
|
|
797
|
-
|
|
798
|
-
// Create DOM elements from HTML strings
|
|
799
|
-
const element = await webhelpers.fixture(webhelpers.html`
|
|
800
|
-
<div class="test-container">
|
|
801
|
-
<h1>Test Title</h1>
|
|
802
|
-
<button id="test-btn">Click Me</button>
|
|
803
|
-
</div>
|
|
804
|
-
`);
|
|
445
|
+
## Test File Directives
|
|
805
446
|
|
|
806
|
-
|
|
447
|
+
Control runtime behavior directly from your test files using special comment directives at the top of the file. Directives must appear before any `import` statements.
|
|
807
448
|
|
|
808
|
-
|
|
809
|
-
const button = element.querySelector('#test-btn');
|
|
810
|
-
button.click();
|
|
811
|
-
});
|
|
449
|
+
### Deno Permissions
|
|
812
450
|
|
|
813
|
-
|
|
814
|
-
const styles = webhelpers.css`
|
|
815
|
-
.test-class {
|
|
816
|
-
color: red;
|
|
817
|
-
font-size: 16px;
|
|
818
|
-
}
|
|
819
|
-
`;
|
|
451
|
+
By default, Deno tests run with `--allow-read`, `--allow-env`, `--allow-net`, `--allow-write`, `--allow-sys`, and `--allow-import`. Add directives to request additional permissions:
|
|
820
452
|
|
|
821
|
-
|
|
822
|
-
|
|
453
|
+
```typescript
|
|
454
|
+
// tstest:deno:allowAll
|
|
455
|
+
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
|
456
|
+
|
|
457
|
+
tap.test('test with full Deno permissions', async () => {
|
|
458
|
+
// Runs with --allow-all (e.g., for FFI, subprocess spawning, etc.)
|
|
823
459
|
});
|
|
460
|
+
|
|
461
|
+
export default tap.start();
|
|
824
462
|
```
|
|
825
463
|
|
|
826
|
-
###
|
|
464
|
+
### Available Directives
|
|
465
|
+
|
|
466
|
+
| Directive | Effect |
|
|
467
|
+
|---|---|
|
|
468
|
+
| `// tstest:deno:allowAll` | Grants all Deno permissions (`--allow-all`) |
|
|
469
|
+
| `// tstest:deno:allowRun` | Adds `--allow-run` for subprocess spawning |
|
|
470
|
+
| `// tstest:deno:allowFfi` | Adds `--allow-ffi` for native library calls |
|
|
471
|
+
| `// tstest:deno:allowHrtime` | Adds `--allow-hrtime` for high-res timers |
|
|
472
|
+
| `// tstest:deno:flag:--unstable-ffi` | Passes any arbitrary Deno flag |
|
|
473
|
+
| `// tstest:node:flag:--max-old-space-size=4096` | Passes flags to Node.js |
|
|
474
|
+
| `// tstest:bun:flag:--smol` | Passes flags to Bun |
|
|
475
|
+
|
|
476
|
+
### Multiple Directives
|
|
477
|
+
|
|
478
|
+
Combine as many directives as needed:
|
|
827
479
|
|
|
828
480
|
```typescript
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
});
|
|
481
|
+
// tstest:deno:allowRun
|
|
482
|
+
// tstest:deno:allowFfi
|
|
483
|
+
// tstest:deno:flag:--unstable-ffi
|
|
484
|
+
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
|
834
485
|
|
|
835
|
-
|
|
836
|
-
|
|
486
|
+
tap.test('test with Rust FFI', async () => {
|
|
487
|
+
// Has --allow-run, --allow-ffi, and --unstable-ffi in addition to defaults
|
|
837
488
|
});
|
|
489
|
+
|
|
490
|
+
export default tap.start();
|
|
838
491
|
```
|
|
839
492
|
|
|
840
|
-
###
|
|
493
|
+
### Shared Directives via 00init.ts
|
|
841
494
|
|
|
842
|
-
|
|
495
|
+
Directives in a `00init.ts` file apply to all test files in that directory. Test file directives are merged with (and extend) init file directives.
|
|
843
496
|
|
|
844
497
|
```typescript
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
before: async () => {
|
|
849
|
-
console.log('Before all tests');
|
|
850
|
-
await globalSetup();
|
|
851
|
-
},
|
|
852
|
-
after: async () => {
|
|
853
|
-
console.log('After all tests');
|
|
854
|
-
await globalCleanup();
|
|
855
|
-
}
|
|
856
|
-
});
|
|
498
|
+
// test/00init.ts
|
|
499
|
+
// tstest:deno:allowRun
|
|
500
|
+
```
|
|
857
501
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
502
|
+
```typescript
|
|
503
|
+
// test/test.mytest.deno.ts
|
|
504
|
+
// tstest:deno:allowFfi
|
|
505
|
+
// Both --allow-run (from 00init.ts) and --allow-ffi are active
|
|
506
|
+
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
|
862
507
|
```
|
|
863
508
|
|
|
864
509
|
## Advanced Features
|
|
865
510
|
|
|
866
511
|
### Watch Mode
|
|
867
512
|
|
|
868
|
-
Automatically re-run tests when files change:
|
|
869
|
-
|
|
870
513
|
```bash
|
|
871
|
-
# Watch all files in the project
|
|
872
514
|
tstest test/ --watch
|
|
873
|
-
|
|
874
|
-
# Watch with custom ignore patterns
|
|
875
515
|
tstest test/ --watch --watch-ignore "dist/**,coverage/**"
|
|
876
|
-
|
|
877
|
-
# Short form
|
|
878
|
-
tstest test/ -w
|
|
879
516
|
```
|
|
880
517
|
|
|
881
|
-
**Features:**
|
|
882
518
|
- 👀 Shows which files triggered the re-run
|
|
883
519
|
- ⏱️ 300ms debouncing to batch rapid changes
|
|
884
|
-
- 🔄 Clears console between runs
|
|
885
|
-
- 📁 Intelligently ignores common non-source files
|
|
886
|
-
|
|
887
|
-
### Real-time Test Progress
|
|
888
|
-
|
|
889
|
-
tstest provides real-time updates during test execution:
|
|
890
|
-
|
|
891
|
-
```
|
|
892
|
-
▶️ test/api.test.ts (1/4)
|
|
893
|
-
Runtime: node.js
|
|
894
|
-
⏳ Running: api endpoint validation...
|
|
895
|
-
✅ api endpoint validation (145ms)
|
|
896
|
-
⏳ Running: error handling...
|
|
897
|
-
✅ error handling (23ms)
|
|
898
|
-
Summary: 2/2 PASSED
|
|
899
|
-
```
|
|
520
|
+
- 🔄 Clears console between runs
|
|
900
521
|
|
|
901
|
-
### Visual Diffs
|
|
522
|
+
### Visual Diffs
|
|
902
523
|
|
|
903
|
-
When assertions fail,
|
|
524
|
+
When assertions fail, you get beautiful diffs:
|
|
904
525
|
|
|
905
526
|
```
|
|
906
527
|
❌ should return correct user data
|
|
907
528
|
|
|
908
|
-
String Diff:
|
|
909
|
-
- Expected
|
|
910
|
-
+ Received
|
|
911
|
-
|
|
912
|
-
- Hello World
|
|
913
|
-
+ Hello Universe
|
|
914
|
-
|
|
915
529
|
Object Diff:
|
|
916
530
|
{
|
|
917
531
|
name: "John",
|
|
@@ -921,255 +535,110 @@ When assertions fail, tstest shows beautiful side-by-side diffs:
|
|
|
921
535
|
}
|
|
922
536
|
```
|
|
923
537
|
|
|
924
|
-
### Enhanced
|
|
925
|
-
|
|
926
|
-
The `--logfile` option provides intelligent test logging with automatic organization:
|
|
538
|
+
### Enhanced Logging
|
|
927
539
|
|
|
928
540
|
```bash
|
|
929
541
|
tstest test/ --logfile
|
|
930
542
|
```
|
|
931
543
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
544
|
+
| Folder | Contents |
|
|
545
|
+
|---|---|
|
|
546
|
+
| `.nogit/testlogs/` | Current run logs |
|
|
547
|
+
| `.nogit/testlogs/previous/` | Previous run logs |
|
|
548
|
+
| `.nogit/testlogs/00err/` | Failed test logs |
|
|
549
|
+
| `.nogit/testlogs/00diff/` | Changed output diffs |
|
|
937
550
|
|
|
938
|
-
|
|
939
|
-
- Previous logs are automatically moved to the `previous/` folder
|
|
940
|
-
- Failed tests create copies in `00err/` for quick identification
|
|
941
|
-
- Tests with changed output create diff reports in `00diff/`
|
|
942
|
-
- The `00err/` and `00diff/` folders are cleared on each run
|
|
551
|
+
### JSON Output (CI/CD)
|
|
943
552
|
|
|
944
|
-
|
|
553
|
+
```bash
|
|
554
|
+
tstest test/ --json > test-results.json
|
|
945
555
|
```
|
|
946
|
-
DIFF REPORT: test__api__integration.log
|
|
947
|
-
Generated: 2025-05-24T01:29:13.847Z
|
|
948
|
-
================================================================================
|
|
949
556
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
Previous version had 40 lines
|
|
955
|
-
Current version has 40 lines
|
|
557
|
+
```json
|
|
558
|
+
{"event":"discovery","count":4,"pattern":"test","executionMode":"directory"}
|
|
559
|
+
{"event":"testResult","testName":"prepare test","passed":true,"duration":1}
|
|
560
|
+
{"event":"summary","summary":{"totalFiles":4,"totalTests":4,"totalPassed":4,"totalFailed":0}}
|
|
956
561
|
```
|
|
957
562
|
|
|
958
|
-
###
|
|
563
|
+
### Tag Filtering
|
|
959
564
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
```bash
|
|
963
|
-
# Timeout any test file that runs longer than 60 seconds
|
|
964
|
-
tstest test/ --timeout 60
|
|
965
|
-
|
|
966
|
-
# Shorter timeout for unit tests
|
|
967
|
-
tstest test/unit/ --timeout 10
|
|
565
|
+
```typescript
|
|
566
|
+
tap.tags('unit', 'api').test('api unit test', async () => { /* ... */ });
|
|
968
567
|
```
|
|
969
568
|
|
|
970
|
-
When a test exceeds the timeout:
|
|
971
|
-
- The test process is terminated (SIGTERM)
|
|
972
|
-
- The test is marked as failed
|
|
973
|
-
- An error log is created in `.nogit/testlogs/00err/`
|
|
974
|
-
- Clear error message shows the timeout duration
|
|
975
|
-
|
|
976
|
-
### Test File Range Control
|
|
977
|
-
|
|
978
|
-
Run specific ranges of test files using `--startFrom` and `--stopAt`:
|
|
979
|
-
|
|
980
569
|
```bash
|
|
981
|
-
|
|
982
|
-
tstest test/ --startFrom 5
|
|
983
|
-
|
|
984
|
-
# Run only files 5 through 10
|
|
985
|
-
tstest test/ --startFrom 5 --stopAt 10
|
|
986
|
-
|
|
987
|
-
# Run only the first 3 test files
|
|
988
|
-
tstest test/ --stopAt 3
|
|
989
|
-
```
|
|
990
|
-
|
|
991
|
-
This is particularly useful for:
|
|
992
|
-
- Debugging specific test failures in large test suites
|
|
993
|
-
- Running tests in chunks on different CI runners
|
|
994
|
-
- Quickly testing changes to specific test files
|
|
995
|
-
|
|
996
|
-
The output shows which files are skipped:
|
|
997
|
-
```
|
|
998
|
-
⏭️ test/auth.test.ts (1/10)
|
|
999
|
-
Skipped: before start range (5)
|
|
1000
|
-
⏭️ test/user.test.ts (2/10)
|
|
1001
|
-
Skipped: before start range (5)
|
|
1002
|
-
▶️ test/api.test.ts (5/10)
|
|
1003
|
-
Runtime: node.js
|
|
1004
|
-
✅ api endpoints work (145ms)
|
|
570
|
+
tstest test/ --tags unit,api
|
|
1005
571
|
```
|
|
1006
572
|
|
|
1007
|
-
###
|
|
573
|
+
### Test File Range
|
|
1008
574
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
⏱️ Performance Metrics:
|
|
1012
|
-
Average per test: 135ms
|
|
1013
|
-
Slowest test: api integration test (486ms)
|
|
575
|
+
```bash
|
|
576
|
+
tstest test/ --startFrom 5 --stopAt 10 # Run files 5-10 only
|
|
1014
577
|
```
|
|
1015
578
|
|
|
1016
|
-
###
|
|
579
|
+
### Browser Testing with webhelpers
|
|
1017
580
|
|
|
1018
|
-
|
|
581
|
+
```typescript
|
|
582
|
+
import { tap, webhelpers } from '@git.zone/tstest/tapbundle';
|
|
1019
583
|
|
|
584
|
+
tap.test('DOM test', async () => {
|
|
585
|
+
const element = await webhelpers.fixture(webhelpers.html`
|
|
586
|
+
<div class="container">
|
|
587
|
+
<h1>Hello</h1>
|
|
588
|
+
</div>
|
|
589
|
+
`);
|
|
590
|
+
expect(element.querySelector('h1').textContent).toEqual('Hello');
|
|
591
|
+
});
|
|
1020
592
|
```
|
|
1021
|
-
━━━ Parallel Group: para__1 ━━━
|
|
1022
|
-
▶️ test/auth.para__1.ts
|
|
1023
|
-
▶️ test/user.para__1.ts
|
|
1024
|
-
... tests run concurrently ...
|
|
1025
|
-
──────────────────────────────────
|
|
1026
|
-
|
|
1027
|
-
━━━ Parallel Group: para__2 ━━━
|
|
1028
|
-
▶️ test/db.para__2.ts
|
|
1029
|
-
▶️ test/api.para__2.ts
|
|
1030
|
-
... tests run concurrently ...
|
|
1031
|
-
──────────────────────────────────
|
|
1032
|
-
```
|
|
1033
|
-
|
|
1034
|
-
Files with the same parallel group suffix (e.g., `para__1`) run simultaneously, while different groups run sequentially.
|
|
1035
593
|
|
|
1036
|
-
###
|
|
594
|
+
### TapWrap (Global Lifecycle)
|
|
1037
595
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
# GitHub Actions example
|
|
1041
|
-
tstest test/ --json > test-results.json
|
|
1042
|
-
|
|
1043
|
-
# Or minimal output
|
|
1044
|
-
tstest test/ --quiet
|
|
1045
|
-
```
|
|
596
|
+
```typescript
|
|
597
|
+
import { TapWrap } from '@git.zone/tstest/tapbundle';
|
|
1046
598
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
--timeout 300 \
|
|
1052
|
-
--logfile \
|
|
1053
|
-
--json > test-results.json
|
|
1054
|
-
|
|
1055
|
-
# Run specific test chunks in parallel CI jobs
|
|
1056
|
-
tstest test/ --startFrom 1 --stopAt 10 # Job 1
|
|
1057
|
-
tstest test/ --startFrom 11 --stopAt 20 # Job 2
|
|
1058
|
-
tstest test/ --startFrom 21 # Job 3
|
|
599
|
+
const tapWrap = new TapWrap({
|
|
600
|
+
before: async () => { await globalSetup(); },
|
|
601
|
+
after: async () => { await globalCleanup(); },
|
|
602
|
+
});
|
|
1059
603
|
```
|
|
1060
604
|
|
|
1061
|
-
|
|
605
|
+
## tapbundle Protocol V2
|
|
1062
606
|
|
|
1063
|
-
|
|
607
|
+
tstest includes an enhanced TAP protocol that extends TAP 13 with structured metadata while staying backwards compatible. Protocol markers (`⟦TSTEST:...⟧`) are invisible to standard TAP parsers.
|
|
1064
608
|
|
|
1065
|
-
```
|
|
1066
|
-
|
|
1067
|
-
tstest test/ --logfile --verbose
|
|
1068
|
-
|
|
1069
|
-
# Check error logs
|
|
1070
|
-
ls .nogit/testlogs/00err/
|
|
609
|
+
```typescript
|
|
610
|
+
import { ProtocolEmitter, ProtocolParser } from '@git.zone/tstest/tapbundle_protocol';
|
|
1071
611
|
|
|
1072
|
-
|
|
1073
|
-
|
|
612
|
+
// Emit
|
|
613
|
+
const emitter = new ProtocolEmitter();
|
|
614
|
+
console.log(emitter.emitProtocolHeader()); // ⟦TSTEST:PROTOCOL:2.0.0⟧
|
|
615
|
+
console.log(emitter.emitTest({
|
|
616
|
+
ok: true, testNumber: 1, description: 'test',
|
|
617
|
+
metadata: { time: 42, tags: ['unit'] }
|
|
618
|
+
}).join('\n'));
|
|
1074
619
|
|
|
1075
|
-
|
|
1076
|
-
|
|
620
|
+
// Parse
|
|
621
|
+
const parser = new ProtocolParser();
|
|
622
|
+
const messages = parser.parseLine('ok 1 - test ⟦TSTEST:time:42⟧');
|
|
1077
623
|
```
|
|
1078
624
|
|
|
1079
|
-
## Changelog
|
|
1080
|
-
|
|
1081
|
-
### Version 3.1.1
|
|
1082
|
-
- 🐛 Fixed TapTools parameter passing to suite lifecycle hooks (beforeAll/afterAll)
|
|
1083
|
-
- 📦 Updated @push.rocks/smarts3 dependency to ^3.0.0
|
|
1084
|
-
|
|
1085
|
-
### Version 3.1.0
|
|
1086
|
-
- 🎯 **postTask() API** - Global teardown method for cleanup after all tests
|
|
1087
|
-
- 🏗️ **Suite beforeAll/afterAll** - Lifecycle hooks that run once per describe block
|
|
1088
|
-
- ⚡ **parallel() Fluent API** - New fluent entry point for parallel tests
|
|
1089
|
-
- 📚 Enhanced tapbundle documentation with complete API reference
|
|
1090
|
-
|
|
1091
|
-
### Version 3.0.0
|
|
1092
|
-
- 🔥 **BREAKING:** Renamed tapbundle_node to tapbundle_serverside for clarity
|
|
1093
|
-
- 🔧 Migrated all server-side utilities to tapbundle_serverside
|
|
1094
|
-
- 📦 Improved module separation and organization
|
|
1095
|
-
|
|
1096
|
-
### Version 2.4.0
|
|
1097
|
-
- 🚀 **Multi-Runtime Architecture** - Support for Deno, Bun, Node.js, and Chromium
|
|
1098
|
-
- 🔀 **New Naming Convention** - Flexible `.runtime1+runtime2.ts` pattern
|
|
1099
|
-
- 🌐 **Universal Testing** - `.all.ts` pattern runs tests on all supported runtimes
|
|
1100
|
-
- 🔄 **Migration Tool** - Easy migration from legacy naming (`.browser.ts`, `.both.ts`)
|
|
1101
|
-
- 🦕 **Deno Support** - Full Deno runtime with Node.js compatibility
|
|
1102
|
-
- 🐰 **Bun Support** - Ultra-fast Bun runtime integration
|
|
1103
|
-
- ⚡ **Dynamic Port Selection** - Random port allocation (30000-40000) prevents conflicts
|
|
1104
|
-
- 🏗️ **Runtime Adapter Pattern** - Extensible architecture for adding new runtimes
|
|
1105
|
-
- 📝 **Deprecation Warnings** - Helpful migration suggestions for legacy naming
|
|
1106
|
-
- ✅ **Comprehensive Tests** - Full test coverage for parser and migration tool
|
|
1107
|
-
|
|
1108
|
-
### Version 1.11.0
|
|
1109
|
-
- 👀 Added Watch Mode with `--watch`/`-w` flag for automatic test re-runs
|
|
1110
|
-
- 📊 Implemented real-time test progress updates with event streaming
|
|
1111
|
-
- 🎨 Added visual diffs for failed assertions with side-by-side comparison
|
|
1112
|
-
- 🔄 Enhanced event-based test lifecycle reporting
|
|
1113
|
-
- ⚙️ Added test configuration system with `.tstest.json` files
|
|
1114
|
-
- 🚀 Implemented Protocol V2 with Unicode delimiters for better TAP parsing
|
|
1115
|
-
- 🐛 Fixed `tap.todo()` to create proper test objects
|
|
1116
|
-
- 🐛 Fixed `tap.skip.test()` to correctly create and count test objects
|
|
1117
|
-
- 🐛 Fixed `tap.only.test()` implementation with `--only` flag support
|
|
1118
|
-
- 📁 Added settings inheritance for cascading test configuration
|
|
1119
|
-
- ⏱️ Added debouncing for file change events in watch mode
|
|
1120
|
-
|
|
1121
|
-
### Version 1.10.0
|
|
1122
|
-
- ⏱️ Added `--timeout <seconds>` option for test file timeout protection
|
|
1123
|
-
- 🎯 Added `--startFrom <n>` and `--stopAt <n>` options for test file range control
|
|
1124
|
-
- 📁 Enhanced `--logfile` with intelligent log organization:
|
|
1125
|
-
- Previous logs moved to `previous/` folder
|
|
1126
|
-
- Failed tests copied to `00err/` folder
|
|
1127
|
-
- Changed tests create diff reports in `00diff/` folder
|
|
1128
|
-
- 🔍 Improved test discovery to show skipped files with clear reasons
|
|
1129
|
-
- 🐛 Fixed TypeScript compilation warnings and unused variables
|
|
1130
|
-
- 📊 Test summaries now include skipped file counts
|
|
1131
|
-
|
|
1132
|
-
### Version 1.9.2
|
|
1133
|
-
- 🐛 Fixed test timing display issue (removed duplicate timing in output)
|
|
1134
|
-
- 📝 Improved internal protocol design documentation
|
|
1135
|
-
- 🔧 Added protocol v2 utilities for future improvements
|
|
1136
|
-
|
|
1137
|
-
### Version 1.9.1
|
|
1138
|
-
- 🐛 Fixed log file naming to preserve directory structure
|
|
1139
|
-
- 📁 Log files now prevent collisions: `test__dir__file.log`
|
|
1140
|
-
|
|
1141
|
-
### Version 1.9.0
|
|
1142
|
-
- 📚 Comprehensive documentation update
|
|
1143
|
-
- 🏗️ Embedded tapbundle for better integration
|
|
1144
|
-
- 🌐 Full browser compatibility
|
|
1145
|
-
|
|
1146
|
-
### Version 1.8.0
|
|
1147
|
-
- 📦 Embedded tapbundle directly into tstest project
|
|
1148
|
-
- 🌐 Made tapbundle fully browser-compatible
|
|
1149
|
-
- 📸 Added snapshot testing with base64-encoded communication protocol
|
|
1150
|
-
- 🏷️ Introduced tag-based test filtering
|
|
1151
|
-
- 🔧 Enhanced test lifecycle hooks (beforeEach/afterEach)
|
|
1152
|
-
- 🎯 Fixed parallel test execution and grouping
|
|
1153
|
-
- ⏳ Improved timeout and retry mechanisms
|
|
1154
|
-
- 🛠️ Added test fixtures for reusable test data
|
|
1155
|
-
- 📊 Enhanced TAP parser for better test reporting
|
|
1156
|
-
- 🐛 Fixed glob pattern handling in shell scripts
|
|
1157
|
-
|
|
1158
625
|
## License and Legal Information
|
|
1159
626
|
|
|
1160
|
-
This repository contains open-source code
|
|
627
|
+
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
|
|
1161
628
|
|
|
1162
629
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
|
1163
630
|
|
|
1164
631
|
### Trademarks
|
|
1165
632
|
|
|
1166
|
-
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein.
|
|
633
|
+
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
|
|
634
|
+
|
|
635
|
+
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
|
|
1167
636
|
|
|
1168
637
|
### Company Information
|
|
1169
638
|
|
|
1170
639
|
Task Venture Capital GmbH
|
|
1171
|
-
Registered at District
|
|
640
|
+
Registered at District Court Bremen HRB 35230 HB, Germany
|
|
1172
641
|
|
|
1173
|
-
For any legal inquiries or
|
|
642
|
+
For any legal inquiries or further information, please contact us via email at hello@task.vc.
|
|
1174
643
|
|
|
1175
644
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|