@git.zone/tstest 1.9.1 → 1.9.3
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 +1 -1
- package/dist_ts/tstest.classes.tap.parser.js +3 -3
- package/dist_ts/tstest.logging.js +10 -3
- package/dist_ts_tapbundle/index.d.ts +1 -0
- package/dist_ts_tapbundle/index.js +3 -1
- package/dist_ts_tapbundle/tapbundle.protocols.d.ts +88 -0
- package/dist_ts_tapbundle/tapbundle.protocols.js +168 -0
- package/package.json +1 -1
- package/readme.hints.md +47 -2
- package/readme.md +357 -51
- package/readme.plan.md +101 -133
- package/readme.protocol.md +287 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/tstest.classes.tap.parser.ts +2 -2
- package/ts/tstest.logging.ts +10 -2
package/readme.plan.md
CHANGED
|
@@ -2,6 +2,81 @@
|
|
|
2
2
|
|
|
3
3
|
!! FIRST: Reread /home/philkunz/.claude/CLAUDE.md to ensure following all guidelines !!
|
|
4
4
|
|
|
5
|
+
## Improved Internal Protocol (NEW - Critical)
|
|
6
|
+
|
|
7
|
+
### Current Issues
|
|
8
|
+
- TAP protocol uses `#` for metadata which conflicts with test descriptions containing `#`
|
|
9
|
+
- Fragile regex parsing that breaks with special characters
|
|
10
|
+
- Limited extensibility for new metadata types
|
|
11
|
+
|
|
12
|
+
### Proposed Solution: Protocol V2
|
|
13
|
+
- Use Unicode delimiters `⟦TSTEST:META:{}⟧` that won't appear in test names
|
|
14
|
+
- Structured JSON metadata format
|
|
15
|
+
- Separate protocol blocks for complex data (errors, snapshots)
|
|
16
|
+
- Backwards compatible with gradual migration
|
|
17
|
+
|
|
18
|
+
### Implementation
|
|
19
|
+
- Phase 1: Add protocol v2 parser alongside v1
|
|
20
|
+
- Phase 2: Generate v2 by default with --legacy flag for v1
|
|
21
|
+
- Phase 3: Full migration to v2 in next major version
|
|
22
|
+
|
|
23
|
+
See `readme.protocol.md` for detailed specification.
|
|
24
|
+
|
|
25
|
+
## Test Configuration System (NEW)
|
|
26
|
+
|
|
27
|
+
### Global Test Configuration via 00init.ts
|
|
28
|
+
- **Discovery**: Check for `test/00init.ts` before running tests
|
|
29
|
+
- **Execution**: Import and execute before any test files if found
|
|
30
|
+
- **Purpose**: Define project-wide default test settings
|
|
31
|
+
|
|
32
|
+
### tap.settings() API
|
|
33
|
+
```typescript
|
|
34
|
+
interface TapSettings {
|
|
35
|
+
// Timing
|
|
36
|
+
timeout?: number; // Default timeout for all tests (ms)
|
|
37
|
+
slowThreshold?: number; // Mark tests as slow if they exceed this (ms)
|
|
38
|
+
|
|
39
|
+
// Execution Control
|
|
40
|
+
bail?: boolean; // Stop on first test failure
|
|
41
|
+
retries?: number; // Number of retries for failed tests
|
|
42
|
+
retryDelay?: number; // Delay between retries (ms)
|
|
43
|
+
|
|
44
|
+
// Output Control
|
|
45
|
+
suppressConsole?: boolean; // Suppress console output in passing tests
|
|
46
|
+
verboseErrors?: boolean; // Show full stack traces
|
|
47
|
+
showTestDuration?: boolean; // Show duration for each test
|
|
48
|
+
|
|
49
|
+
// Parallel Execution
|
|
50
|
+
maxConcurrency?: number; // Max parallel tests (for .para files)
|
|
51
|
+
isolateTests?: boolean; // Run each test in fresh context
|
|
52
|
+
|
|
53
|
+
// Lifecycle Hooks
|
|
54
|
+
beforeAll?: () => Promise<void> | void;
|
|
55
|
+
afterAll?: () => Promise<void> | void;
|
|
56
|
+
beforeEach?: (testName: string) => Promise<void> | void;
|
|
57
|
+
afterEach?: (testName: string, passed: boolean) => Promise<void> | void;
|
|
58
|
+
|
|
59
|
+
// Environment
|
|
60
|
+
env?: Record<string, string>; // Additional environment variables
|
|
61
|
+
|
|
62
|
+
// Features
|
|
63
|
+
enableSnapshots?: boolean; // Enable snapshot testing
|
|
64
|
+
snapshotDirectory?: string; // Custom snapshot directory
|
|
65
|
+
updateSnapshots?: boolean; // Update snapshots instead of comparing
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Settings Inheritance
|
|
70
|
+
- Global (00init.ts) → File level → Test level
|
|
71
|
+
- More specific settings override less specific ones
|
|
72
|
+
- Arrays/objects are merged, primitives are replaced
|
|
73
|
+
|
|
74
|
+
### Implementation Phases
|
|
75
|
+
1. **Core Infrastructure**: Settings storage and merge logic
|
|
76
|
+
2. **Discovery**: 00init.ts loading mechanism
|
|
77
|
+
3. **Application**: Apply settings to test execution
|
|
78
|
+
4. **Advanced**: Parallel execution and snapshot configuration
|
|
79
|
+
|
|
5
80
|
## 1. Enhanced Communication Between tapbundle and tstest
|
|
6
81
|
|
|
7
82
|
### 1.1 Real-time Test Progress API
|
|
@@ -18,45 +93,9 @@
|
|
|
18
93
|
|
|
19
94
|
## 2. Enhanced toolsArg Functionality
|
|
20
95
|
|
|
21
|
-
### 2.
|
|
22
|
-
```typescript
|
|
23
|
-
tap.test('conditional test', async (toolsArg) => {
|
|
24
|
-
const result = await someOperation();
|
|
25
|
-
|
|
26
|
-
// Skip the rest of the test
|
|
27
|
-
if (!result) {
|
|
28
|
-
return toolsArg.skip('Precondition not met');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Conditional skipping
|
|
32
|
-
await toolsArg.skipIf(condition, 'Reason for skipping');
|
|
33
|
-
|
|
34
|
-
// Mark test as todo
|
|
35
|
-
await toolsArg.todo('Not implemented yet');
|
|
36
|
-
});
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### 2.2 Test Metadata and Configuration ✅
|
|
40
|
-
```typescript
|
|
41
|
-
// Fluent syntax ✅
|
|
42
|
-
tap.tags('slow', 'integration')
|
|
43
|
-
.priority('high')
|
|
44
|
-
.timeout(5000)
|
|
45
|
-
.retry(3)
|
|
46
|
-
.test('configurable test', async (toolsArg) => {
|
|
47
|
-
// Test implementation
|
|
48
|
-
});
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### 2.3 Test Data and Context Sharing ✅
|
|
96
|
+
### 2.3 Test Data and Context Sharing (Partial)
|
|
52
97
|
```typescript
|
|
53
98
|
tap.test('data-driven test', async (toolsArg) => {
|
|
54
|
-
// Access shared context ✅
|
|
55
|
-
const sharedData = toolsArg.context.get('sharedData');
|
|
56
|
-
|
|
57
|
-
// Set data for other tests ✅
|
|
58
|
-
toolsArg.context.set('resultData', computedValue);
|
|
59
|
-
|
|
60
99
|
// Parameterized test data (not yet implemented)
|
|
61
100
|
const testData = toolsArg.data<TestInput>();
|
|
62
101
|
expect(processData(testData)).toEqual(expected);
|
|
@@ -65,32 +104,7 @@ tap.test('data-driven test', async (toolsArg) => {
|
|
|
65
104
|
|
|
66
105
|
## 3. Nested Tests and Test Suites
|
|
67
106
|
|
|
68
|
-
### 3.
|
|
69
|
-
```typescript
|
|
70
|
-
tap.describe('User Authentication', () => {
|
|
71
|
-
tap.beforeEach(async (toolsArg) => {
|
|
72
|
-
// Setup for each test in this suite
|
|
73
|
-
await toolsArg.context.set('db', await createTestDatabase());
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
tap.afterEach(async (toolsArg) => {
|
|
77
|
-
// Cleanup after each test
|
|
78
|
-
await toolsArg.context.get('db').cleanup();
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
tap.test('should login with valid credentials', async (toolsArg) => {
|
|
82
|
-
// Test implementation
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
tap.describe('Password Reset', () => {
|
|
86
|
-
tap.test('should send reset email', async (toolsArg) => {
|
|
87
|
-
// Nested test
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### 3.2 Hierarchical Test Organization
|
|
107
|
+
### 3.2 Hierarchical Test Organization (Not yet implemented)
|
|
94
108
|
- Support for multiple levels of nesting
|
|
95
109
|
- Inherited context and configuration from parent suites
|
|
96
110
|
- Aggregated reporting for test suites
|
|
@@ -98,15 +112,7 @@ tap.describe('User Authentication', () => {
|
|
|
98
112
|
|
|
99
113
|
## 4. Advanced Test Features
|
|
100
114
|
|
|
101
|
-
### 4.1 Snapshot Testing
|
|
102
|
-
```typescript
|
|
103
|
-
tap.test('component render', async (toolsArg) => {
|
|
104
|
-
const output = renderComponent(props);
|
|
105
|
-
|
|
106
|
-
// Compare with stored snapshot
|
|
107
|
-
await toolsArg.matchSnapshot(output, 'component-output');
|
|
108
|
-
});
|
|
109
|
-
```
|
|
115
|
+
### 4.1 Snapshot Testing ✅ (Basic implementation complete)
|
|
110
116
|
|
|
111
117
|
### 4.2 Performance Benchmarking
|
|
112
118
|
```typescript
|
|
@@ -124,30 +130,9 @@ tap.test('performance test', async (toolsArg) => {
|
|
|
124
130
|
});
|
|
125
131
|
```
|
|
126
132
|
|
|
127
|
-
### 4.3 Test Fixtures and Factories ✅
|
|
128
|
-
```typescript
|
|
129
|
-
tap.test('with fixtures', async (toolsArg) => {
|
|
130
|
-
// Create test fixtures
|
|
131
|
-
const user = await toolsArg.fixture('user', { name: 'Test User' });
|
|
132
|
-
const post = await toolsArg.fixture('post', { author: user });
|
|
133
|
-
|
|
134
|
-
// Use factory functions
|
|
135
|
-
const users = await toolsArg.factory('user').createMany(5);
|
|
136
|
-
});
|
|
137
|
-
```
|
|
138
133
|
|
|
139
134
|
## 5. Test Execution Improvements
|
|
140
135
|
|
|
141
|
-
### 5.1 Parallel Test Execution ✅
|
|
142
|
-
- Run independent tests concurrently ✅
|
|
143
|
-
- Configurable concurrency limits (via file naming convention)
|
|
144
|
-
- Resource pooling for shared resources
|
|
145
|
-
- Proper isolation between parallel tests ✅
|
|
146
|
-
|
|
147
|
-
Implementation:
|
|
148
|
-
- Tests with `para__<groupNumber>` in filename run in parallel
|
|
149
|
-
- Different groups run sequentially
|
|
150
|
-
- Tests without `para__` run serially
|
|
151
136
|
|
|
152
137
|
### 5.2 Watch Mode
|
|
153
138
|
- Automatically re-run tests on file changes
|
|
@@ -155,11 +140,8 @@ Implementation:
|
|
|
155
140
|
- Fast feedback loop for development
|
|
156
141
|
- Integration with IDE/editor plugins
|
|
157
142
|
|
|
158
|
-
### 5.3 Advanced Test Filtering
|
|
143
|
+
### 5.3 Advanced Test Filtering (Partial)
|
|
159
144
|
```typescript
|
|
160
|
-
// Run tests by tags ✅
|
|
161
|
-
tstest --tags "unit,fast"
|
|
162
|
-
|
|
163
145
|
// Exclude tests by pattern (not yet implemented)
|
|
164
146
|
tstest --exclude "**/slow/**"
|
|
165
147
|
|
|
@@ -198,50 +180,36 @@ tstest --changed
|
|
|
198
180
|
- Links to documentation
|
|
199
181
|
- Code examples in error output
|
|
200
182
|
|
|
201
|
-
### 7.2 Interactive Mode (Needs Detailed Specification)
|
|
202
|
-
- REPL for exploring test failures
|
|
203
|
-
- Need to define: How to enter interactive mode? When tests fail?
|
|
204
|
-
- What commands/features should be available in the REPL?
|
|
205
|
-
- Debugging integration
|
|
206
|
-
- Node.js inspector protocol integration?
|
|
207
|
-
- Breakpoint support?
|
|
208
|
-
- Step-through test execution
|
|
209
|
-
- Pause between tests?
|
|
210
|
-
- Step into/over/out functionality?
|
|
211
|
-
- Interactive test data manipulation
|
|
212
|
-
- Modify test inputs on the fly?
|
|
213
|
-
- Inspect intermediate values?
|
|
214
|
-
|
|
215
|
-
### 7.3 ~~VS Code Extension~~ (Scratched)
|
|
216
|
-
- ~~Test explorer integration~~
|
|
217
|
-
- ~~Inline test results~~
|
|
218
|
-
- ~~CodeLens for running individual tests~~
|
|
219
|
-
- ~~Debugging support~~
|
|
220
|
-
|
|
221
183
|
## Implementation Phases
|
|
222
184
|
|
|
223
|
-
### Phase 1:
|
|
224
|
-
1. Implement
|
|
225
|
-
2. Add
|
|
226
|
-
3.
|
|
185
|
+
### Phase 1: Improved Internal Protocol (Priority: Critical) (NEW)
|
|
186
|
+
1. Implement Protocol V2 parser in tstest
|
|
187
|
+
2. Add protocol version negotiation
|
|
188
|
+
3. Update tapbundle to generate V2 format with feature flag
|
|
189
|
+
4. Test with real-world test suites containing special characters
|
|
190
|
+
|
|
191
|
+
### Phase 2: Test Configuration System (Priority: High)
|
|
192
|
+
1. Implement tap.settings() API with TypeScript interfaces
|
|
193
|
+
2. Add 00init.ts discovery and loading mechanism
|
|
194
|
+
3. Implement settings inheritance and merge logic
|
|
195
|
+
4. Apply settings to test execution (timeouts, retries, etc.)
|
|
227
196
|
|
|
228
|
-
### Phase
|
|
229
|
-
1.
|
|
230
|
-
2.
|
|
231
|
-
3.
|
|
232
|
-
4. Implement parallel test execution ✅
|
|
197
|
+
### Phase 3: Enhanced Communication (Priority: High)
|
|
198
|
+
1. Build on Protocol V2 for richer communication
|
|
199
|
+
2. Implement real-time test progress API
|
|
200
|
+
3. Add structured error reporting with diffs and traces
|
|
233
201
|
|
|
234
|
-
### Phase
|
|
202
|
+
### Phase 4: Developer Experience (Priority: Medium)
|
|
235
203
|
1. Add watch mode
|
|
236
204
|
2. Implement custom reporters
|
|
237
|
-
3.
|
|
238
|
-
4. Add
|
|
205
|
+
3. Complete advanced test filtering options
|
|
206
|
+
4. Add performance benchmarking API
|
|
239
207
|
|
|
240
|
-
### Phase
|
|
208
|
+
### Phase 5: Analytics and Performance (Priority: Low)
|
|
241
209
|
1. Build test analytics dashboard
|
|
242
|
-
2.
|
|
243
|
-
3.
|
|
244
|
-
4.
|
|
210
|
+
2. Implement coverage integration
|
|
211
|
+
3. Create trend analysis tools
|
|
212
|
+
4. Add test impact analysis
|
|
245
213
|
|
|
246
214
|
## Technical Considerations
|
|
247
215
|
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# Improved Internal Protocol Design
|
|
2
|
+
|
|
3
|
+
## Current Issues with TAP Protocol
|
|
4
|
+
|
|
5
|
+
1. **Delimiter Conflict**: Using `#` for metadata conflicts with test descriptions containing `#`
|
|
6
|
+
2. **Ambiguous Parsing**: No clear boundary between test name and metadata
|
|
7
|
+
3. **Limited Extensibility**: Adding new metadata requires regex changes
|
|
8
|
+
4. **Mixed Concerns**: Protocol data mixed with human-readable output
|
|
9
|
+
|
|
10
|
+
## Proposed Internal Protocol v2
|
|
11
|
+
|
|
12
|
+
### Design Principles
|
|
13
|
+
|
|
14
|
+
1. **Clear Separation**: Protocol data must be unambiguously separated from user content
|
|
15
|
+
2. **Extensibility**: Easy to add new metadata without breaking parsers
|
|
16
|
+
3. **Backwards Compatible**: Can coexist with standard TAP for gradual migration
|
|
17
|
+
4. **Machine Readable**: Structured format for reliable parsing
|
|
18
|
+
5. **Human Friendly**: Still readable in raw form
|
|
19
|
+
|
|
20
|
+
### Protocol Options
|
|
21
|
+
|
|
22
|
+
#### Option 1: Special Delimiters
|
|
23
|
+
```
|
|
24
|
+
ok 1 - test description ::TSTEST:: {"time":123,"retry":0}
|
|
25
|
+
not ok 2 - another test ::TSTEST:: {"time":45,"error":"timeout"}
|
|
26
|
+
ok 3 - skipped test ::TSTEST:: {"time":0,"skip":"not ready"}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Pros**:
|
|
30
|
+
- Simple to implement
|
|
31
|
+
- Backwards compatible with TAP parsers (they ignore the suffix)
|
|
32
|
+
- Easy to parse with split()
|
|
33
|
+
|
|
34
|
+
**Cons**:
|
|
35
|
+
- Still could conflict if test name contains `::TSTEST::`
|
|
36
|
+
- Not standard TAP
|
|
37
|
+
|
|
38
|
+
#### Option 2: Separate Metadata Lines
|
|
39
|
+
```
|
|
40
|
+
ok 1 - test description
|
|
41
|
+
::METADATA:: {"test":1,"time":123,"retry":0}
|
|
42
|
+
not ok 2 - another test
|
|
43
|
+
::METADATA:: {"test":2,"time":45,"error":"timeout"}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Pros**:
|
|
47
|
+
- Complete separation of concerns
|
|
48
|
+
- No chance of conflicts
|
|
49
|
+
- Can include arbitrary metadata
|
|
50
|
+
|
|
51
|
+
**Cons**:
|
|
52
|
+
- Requires correlation between lines
|
|
53
|
+
- More complex parsing
|
|
54
|
+
|
|
55
|
+
#### Option 3: YAML Blocks (TAP 13 Compatible)
|
|
56
|
+
```
|
|
57
|
+
ok 1 - test description
|
|
58
|
+
---
|
|
59
|
+
time: 123
|
|
60
|
+
retry: 0
|
|
61
|
+
...
|
|
62
|
+
not ok 2 - another test
|
|
63
|
+
---
|
|
64
|
+
time: 45
|
|
65
|
+
error: timeout
|
|
66
|
+
stack: |
|
|
67
|
+
Error: timeout
|
|
68
|
+
at Test.run (test.js:10:5)
|
|
69
|
+
...
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Pros**:
|
|
73
|
+
- Standard TAP 13 feature
|
|
74
|
+
- Structured data format
|
|
75
|
+
- Human readable
|
|
76
|
+
- Extensible
|
|
77
|
+
|
|
78
|
+
**Cons**:
|
|
79
|
+
- More verbose
|
|
80
|
+
- YAML parsing overhead
|
|
81
|
+
|
|
82
|
+
#### Option 4: Binary Protocol Markers (Recommended)
|
|
83
|
+
```
|
|
84
|
+
ok 1 - test description
|
|
85
|
+
␛[TSTEST:eyJ0aW1lIjoxMjMsInJldHJ5IjowfQ==]␛
|
|
86
|
+
not ok 2 - another test
|
|
87
|
+
␛[TSTEST:eyJ0aW1lIjo0NSwiZXJyb3IiOiJ0aW1lb3V0In0=]␛
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Using ASCII escape character (␛ = \x1B) with base64 encoded JSON.
|
|
91
|
+
|
|
92
|
+
**Pros**:
|
|
93
|
+
- Zero chance of accidental conflicts
|
|
94
|
+
- Compact
|
|
95
|
+
- Fast to parse
|
|
96
|
+
- Invisible in most terminals
|
|
97
|
+
|
|
98
|
+
**Cons**:
|
|
99
|
+
- Not human readable in raw form
|
|
100
|
+
- Requires base64 encoding/decoding
|
|
101
|
+
|
|
102
|
+
### Recommended Implementation: Hybrid Approach
|
|
103
|
+
|
|
104
|
+
Use multiple strategies based on context:
|
|
105
|
+
|
|
106
|
+
1. **For timing and basic metadata**: Use structured delimiters
|
|
107
|
+
```
|
|
108
|
+
ok 1 - test name ⟦time:123,retry:0⟧
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
2. **For complex data (errors, snapshots)**: Use separate protocol lines
|
|
112
|
+
```
|
|
113
|
+
ok 1 - test failed
|
|
114
|
+
⟦TSTEST:ERROR⟧
|
|
115
|
+
{"message":"Assertion failed","stack":"...","diff":"..."}
|
|
116
|
+
⟦/TSTEST:ERROR⟧
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
3. **For human-readable output**: Keep standard TAP comments
|
|
120
|
+
```
|
|
121
|
+
# Test suite: User Authentication
|
|
122
|
+
ok 1 - should login
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Implementation Plan
|
|
126
|
+
|
|
127
|
+
#### Phase 1: Parser Enhancement
|
|
128
|
+
1. Add new protocol parser alongside existing TAP parser
|
|
129
|
+
2. Support both old and new formats during transition
|
|
130
|
+
3. Add protocol version negotiation
|
|
131
|
+
|
|
132
|
+
#### Phase 2: Metadata Structure
|
|
133
|
+
```typescript
|
|
134
|
+
interface TestMetadata {
|
|
135
|
+
// Timing
|
|
136
|
+
time: number; // milliseconds
|
|
137
|
+
startTime?: number; // Unix timestamp
|
|
138
|
+
endTime?: number; // Unix timestamp
|
|
139
|
+
|
|
140
|
+
// Status
|
|
141
|
+
skip?: string; // skip reason
|
|
142
|
+
todo?: string; // todo reason
|
|
143
|
+
retry?: number; // retry attempt
|
|
144
|
+
maxRetries?: number; // max retries allowed
|
|
145
|
+
|
|
146
|
+
// Error details
|
|
147
|
+
error?: {
|
|
148
|
+
message: string;
|
|
149
|
+
stack?: string;
|
|
150
|
+
diff?: string;
|
|
151
|
+
actual?: any;
|
|
152
|
+
expected?: any;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// Test context
|
|
156
|
+
file?: string; // source file
|
|
157
|
+
line?: number; // line number
|
|
158
|
+
column?: number; // column number
|
|
159
|
+
|
|
160
|
+
// Custom data
|
|
161
|
+
tags?: string[]; // test tags
|
|
162
|
+
custom?: Record<string, any>;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Phase 3: Protocol Messages
|
|
167
|
+
|
|
168
|
+
##### Success Message
|
|
169
|
+
```
|
|
170
|
+
ok 1 - user authentication works
|
|
171
|
+
⟦TSTEST:META:{"time":123,"tags":["auth","unit"]}⟧
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
##### Failure Message
|
|
175
|
+
```
|
|
176
|
+
not ok 2 - login fails with invalid password
|
|
177
|
+
⟦TSTEST:META:{"time":45,"retry":1,"maxRetries":3}⟧
|
|
178
|
+
⟦TSTEST:ERROR⟧
|
|
179
|
+
{
|
|
180
|
+
"message": "Expected 401 but got 500",
|
|
181
|
+
"stack": "Error: Expected 401 but got 500\n at Test.run (auth.test.ts:25:10)",
|
|
182
|
+
"actual": 500,
|
|
183
|
+
"expected": 401
|
|
184
|
+
}
|
|
185
|
+
⟦/TSTEST:ERROR⟧
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
##### Skip Message
|
|
189
|
+
```
|
|
190
|
+
ok 3 - database integration test ⟦TSTEST:SKIP:No database connection⟧
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
##### Snapshot Communication
|
|
194
|
+
```
|
|
195
|
+
⟦TSTEST:SNAPSHOT:user-profile⟧
|
|
196
|
+
{
|
|
197
|
+
"name": "John Doe",
|
|
198
|
+
"email": "john@example.com",
|
|
199
|
+
"roles": ["user", "admin"]
|
|
200
|
+
}
|
|
201
|
+
⟦/TSTEST:SNAPSHOT⟧
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Migration Strategy
|
|
205
|
+
|
|
206
|
+
1. **Version Detection**: First line indicates protocol version
|
|
207
|
+
```
|
|
208
|
+
⟦TSTEST:PROTOCOL:2.0⟧
|
|
209
|
+
TAP version 13
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
2. **Gradual Rollout**:
|
|
213
|
+
- v1.10: Add protocol v2 parser, keep v1 generator
|
|
214
|
+
- v1.11: Generate v2 by default, v1 with --legacy flag
|
|
215
|
+
- v2.0: Remove v1 support
|
|
216
|
+
|
|
217
|
+
3. **Feature Flags**:
|
|
218
|
+
```typescript
|
|
219
|
+
tap.settings({
|
|
220
|
+
protocol: 'v2', // or 'v1', 'auto'
|
|
221
|
+
protocolFeatures: {
|
|
222
|
+
structuredErrors: true,
|
|
223
|
+
enhancedTiming: true,
|
|
224
|
+
binaryMarkers: false
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Benefits of New Protocol
|
|
230
|
+
|
|
231
|
+
1. **Reliability**: No more regex fragility or description conflicts
|
|
232
|
+
2. **Performance**: Faster parsing with clear boundaries
|
|
233
|
+
3. **Extensibility**: Easy to add new metadata fields
|
|
234
|
+
4. **Debugging**: Rich error information with stack traces and diffs
|
|
235
|
+
5. **Integration**: Better IDE and CI/CD tool integration
|
|
236
|
+
6. **Forward Compatible**: Room for future enhancements
|
|
237
|
+
|
|
238
|
+
### Example Parser Implementation
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
class ProtocolV2Parser {
|
|
242
|
+
private readonly MARKER_START = '⟦TSTEST:';
|
|
243
|
+
private readonly MARKER_END = '⟧';
|
|
244
|
+
|
|
245
|
+
parseMetadata(line: string): TestMetadata | null {
|
|
246
|
+
const start = line.lastIndexOf(this.MARKER_START);
|
|
247
|
+
if (start === -1) return null;
|
|
248
|
+
|
|
249
|
+
const end = line.indexOf(this.MARKER_END, start);
|
|
250
|
+
if (end === -1) return null;
|
|
251
|
+
|
|
252
|
+
const content = line.substring(start + this.MARKER_START.length, end);
|
|
253
|
+
const [type, data] = content.split(':', 2);
|
|
254
|
+
|
|
255
|
+
switch (type) {
|
|
256
|
+
case 'META':
|
|
257
|
+
return JSON.parse(data);
|
|
258
|
+
case 'SKIP':
|
|
259
|
+
return { skip: data };
|
|
260
|
+
case 'TODO':
|
|
261
|
+
return { todo: data };
|
|
262
|
+
default:
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
parseTestLine(line: string): ParsedTest {
|
|
268
|
+
// First extract any metadata
|
|
269
|
+
const metadata = this.parseMetadata(line);
|
|
270
|
+
|
|
271
|
+
// Then parse the TAP part (without metadata)
|
|
272
|
+
const cleanLine = this.removeMetadata(line);
|
|
273
|
+
const tapResult = this.parseTAP(cleanLine);
|
|
274
|
+
|
|
275
|
+
return { ...tapResult, metadata };
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Next Steps
|
|
281
|
+
|
|
282
|
+
1. Implement proof of concept with basic metadata support
|
|
283
|
+
2. Test with real-world test suites for edge cases
|
|
284
|
+
3. Benchmark parsing performance
|
|
285
|
+
4. Get feedback from users
|
|
286
|
+
5. Finalize protocol specification
|
|
287
|
+
6. Implement in both tapbundle and tstest
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -16,7 +16,7 @@ export class TapParser {
|
|
|
16
16
|
expectedTests: number;
|
|
17
17
|
receivedTests: number;
|
|
18
18
|
|
|
19
|
-
testStatusRegex = /(ok|not\sok)\s([0-9]+)\s-\s(
|
|
19
|
+
testStatusRegex = /(ok|not\sok)\s([0-9]+)\s-\s(.*?)(\s#\s(.*))?$/;
|
|
20
20
|
activeTapTestResult: TapTestResult;
|
|
21
21
|
collectingErrorDetails: boolean = false;
|
|
22
22
|
currentTestError: string[] = [];
|
|
@@ -77,7 +77,7 @@ export class TapParser {
|
|
|
77
77
|
return false;
|
|
78
78
|
})();
|
|
79
79
|
|
|
80
|
-
const testSubject = regexResult[3];
|
|
80
|
+
const testSubject = regexResult[3].trim();
|
|
81
81
|
const testMetadata = regexResult[5]; // This will be either "time=XXXms" or "SKIP reason" or "TODO reason"
|
|
82
82
|
|
|
83
83
|
let testDuration = 0;
|
package/ts/tstest.logging.ts
CHANGED
|
@@ -153,8 +153,16 @@ export class TsTestLogger {
|
|
|
153
153
|
|
|
154
154
|
// Only set up test log file if --logfile option is specified
|
|
155
155
|
if (this.options.logFile) {
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
// Create a safe filename that preserves directory structure
|
|
157
|
+
// Convert relative path to a flat filename by replacing separators with __
|
|
158
|
+
const relativeFilename = path.relative(process.cwd(), filename);
|
|
159
|
+
const safeFilename = relativeFilename
|
|
160
|
+
.replace(/\\/g, '/') // Normalize Windows paths
|
|
161
|
+
.replace(/\//g, '__') // Replace path separators with double underscores
|
|
162
|
+
.replace(/\.ts$/, '') // Remove .ts extension
|
|
163
|
+
.replace(/^\.\.__|^\.__|^__/, ''); // Clean up leading separators from relative paths
|
|
164
|
+
|
|
165
|
+
this.currentTestLogFile = path.join('.nogit', 'testlogs', `${safeFilename}.log`);
|
|
158
166
|
|
|
159
167
|
// Ensure the directory exists
|
|
160
168
|
const logDir = path.dirname(this.currentTestLogFile);
|