@git.zone/tstest 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,228 @@
1
+ import { coloredString as cs } from '@push.rocks/consolecolor';
2
+ import * as plugins from './tstest.plugins.js';
3
+ export class TsTestLogger {
4
+ constructor(options = {}) {
5
+ this.fileResults = [];
6
+ this.currentFileResult = null;
7
+ this.options = options;
8
+ this.startTime = Date.now();
9
+ }
10
+ format(text, color) {
11
+ if (this.options.noColor || !color) {
12
+ return text;
13
+ }
14
+ return cs(text, color);
15
+ }
16
+ log(message) {
17
+ if (this.options.json)
18
+ return;
19
+ console.log(message);
20
+ if (this.options.logFile) {
21
+ // TODO: Implement file logging
22
+ }
23
+ }
24
+ // Section separators
25
+ sectionStart(title) {
26
+ if (this.options.quiet || this.options.json)
27
+ return;
28
+ this.log(this.format(`\n━━━ ${title} ━━━`, 'cyan'));
29
+ }
30
+ sectionEnd() {
31
+ if (this.options.quiet || this.options.json)
32
+ return;
33
+ this.log(this.format('─'.repeat(50), 'dim'));
34
+ }
35
+ // Progress indication
36
+ progress(current, total, message) {
37
+ if (this.options.quiet || this.options.json)
38
+ return;
39
+ const percentage = Math.round((current / total) * 100);
40
+ const filled = Math.round((current / total) * 20);
41
+ const empty = 20 - filled;
42
+ this.log(this.format(`\n📊 Progress: ${current}/${total} (${percentage}%)`, 'cyan'));
43
+ this.log(this.format(`[${'█'.repeat(filled)}${'░'.repeat(empty)}] ${message}`, 'dim'));
44
+ }
45
+ // Test discovery
46
+ testDiscovery(count, pattern, executionMode) {
47
+ if (this.options.json) {
48
+ console.log(JSON.stringify({ event: 'discovery', count, pattern, executionMode }));
49
+ return;
50
+ }
51
+ if (this.options.quiet) {
52
+ this.log(`Found ${count} tests`);
53
+ }
54
+ else {
55
+ this.log(this.format(`\n🔍 Test Discovery`, 'bold'));
56
+ this.log(this.format(` Mode: ${executionMode}`, 'dim'));
57
+ this.log(this.format(` Pattern: ${pattern}`, 'dim'));
58
+ this.log(this.format(` Found: ${count} test file(s)`, 'green'));
59
+ }
60
+ }
61
+ // Test execution
62
+ testFileStart(filename, runtime, index, total) {
63
+ this.currentFileResult = {
64
+ file: filename,
65
+ passed: 0,
66
+ failed: 0,
67
+ total: 0,
68
+ duration: 0,
69
+ tests: []
70
+ };
71
+ if (this.options.json) {
72
+ console.log(JSON.stringify({ event: 'fileStart', filename, runtime, index, total }));
73
+ return;
74
+ }
75
+ if (this.options.quiet)
76
+ return;
77
+ this.log(this.format(`\n▶️ ${filename} (${index}/${total})`, 'blue'));
78
+ this.log(this.format(` Runtime: ${runtime}`, 'dim'));
79
+ }
80
+ testResult(testName, passed, duration, error) {
81
+ if (this.currentFileResult) {
82
+ this.currentFileResult.tests.push({ name: testName, passed, duration, error });
83
+ this.currentFileResult.total++;
84
+ if (passed) {
85
+ this.currentFileResult.passed++;
86
+ }
87
+ else {
88
+ this.currentFileResult.failed++;
89
+ }
90
+ this.currentFileResult.duration += duration;
91
+ }
92
+ if (this.options.json) {
93
+ console.log(JSON.stringify({ event: 'testResult', testName, passed, duration, error }));
94
+ return;
95
+ }
96
+ const icon = passed ? '✅' : '❌';
97
+ const color = passed ? 'green' : 'red';
98
+ if (this.options.quiet) {
99
+ this.log(`${icon} ${testName}`);
100
+ }
101
+ else {
102
+ this.log(this.format(` ${icon} ${testName} (${duration}ms)`, color));
103
+ if (error && !passed) {
104
+ this.log(this.format(` ${error}`, 'red'));
105
+ }
106
+ }
107
+ }
108
+ testFileEnd(passed, failed, duration) {
109
+ if (this.currentFileResult) {
110
+ this.fileResults.push(this.currentFileResult);
111
+ this.currentFileResult = null;
112
+ }
113
+ if (this.options.json) {
114
+ console.log(JSON.stringify({ event: 'fileEnd', passed, failed, duration }));
115
+ return;
116
+ }
117
+ if (!this.options.quiet) {
118
+ const total = passed + failed;
119
+ const status = failed === 0 ? 'PASSED' : 'FAILED';
120
+ const color = failed === 0 ? 'green' : 'red';
121
+ this.log(this.format(` Summary: ${passed}/${total} ${status}`, color));
122
+ }
123
+ }
124
+ // TAP output forwarding
125
+ tapOutput(message, isError = false) {
126
+ if (this.options.json)
127
+ return;
128
+ if (this.options.verbose || isError) {
129
+ const prefix = isError ? ' ⚠️ ' : ' ';
130
+ const color = isError ? 'red' : 'dim';
131
+ this.log(this.format(`${prefix}${message}`, color));
132
+ }
133
+ }
134
+ // Browser console
135
+ browserConsole(message, level = 'log') {
136
+ if (this.options.json) {
137
+ console.log(JSON.stringify({ event: 'browserConsole', message, level }));
138
+ return;
139
+ }
140
+ if (!this.options.quiet) {
141
+ const prefix = level === 'error' ? '🌐❌' : '🌐';
142
+ const color = level === 'error' ? 'red' : 'magenta';
143
+ this.log(this.format(` ${prefix} ${message}`, color));
144
+ }
145
+ }
146
+ // Final summary
147
+ summary() {
148
+ const totalDuration = Date.now() - this.startTime;
149
+ const summary = {
150
+ totalFiles: this.fileResults.length,
151
+ totalTests: this.fileResults.reduce((sum, r) => sum + r.total, 0),
152
+ totalPassed: this.fileResults.reduce((sum, r) => sum + r.passed, 0),
153
+ totalFailed: this.fileResults.reduce((sum, r) => sum + r.failed, 0),
154
+ totalDuration,
155
+ fileResults: this.fileResults
156
+ };
157
+ if (this.options.json) {
158
+ console.log(JSON.stringify({ event: 'summary', summary }));
159
+ return;
160
+ }
161
+ if (this.options.quiet) {
162
+ const status = summary.totalFailed === 0 ? 'PASSED' : 'FAILED';
163
+ this.log(`\nSummary: ${summary.totalPassed}/${summary.totalTests} | ${totalDuration}ms | ${status}`);
164
+ return;
165
+ }
166
+ // Detailed summary
167
+ this.log(this.format('\n📊 Test Summary', 'bold'));
168
+ this.log(this.format('┌────────────────────────────────┐', 'dim'));
169
+ this.log(this.format(`│ Total Files: ${summary.totalFiles.toString().padStart(14)} │`, 'white'));
170
+ this.log(this.format(`│ Total Tests: ${summary.totalTests.toString().padStart(14)} │`, 'white'));
171
+ this.log(this.format(`│ Passed: ${summary.totalPassed.toString().padStart(14)} │`, 'green'));
172
+ this.log(this.format(`│ Failed: ${summary.totalFailed.toString().padStart(14)} │`, summary.totalFailed > 0 ? 'red' : 'green'));
173
+ this.log(this.format(`│ Duration: ${totalDuration.toString().padStart(14)}ms │`, 'white'));
174
+ this.log(this.format('└────────────────────────────────┘', 'dim'));
175
+ // File results
176
+ if (summary.totalFailed > 0) {
177
+ this.log(this.format('\n❌ Failed Tests:', 'red'));
178
+ this.fileResults.forEach(fileResult => {
179
+ if (fileResult.failed > 0) {
180
+ this.log(this.format(`\n ${fileResult.file}`, 'yellow'));
181
+ fileResult.tests.filter(t => !t.passed).forEach(test => {
182
+ this.log(this.format(` ❌ ${test.name}`, 'red'));
183
+ if (test.error) {
184
+ this.log(this.format(` ${test.error}`, 'dim'));
185
+ }
186
+ });
187
+ }
188
+ });
189
+ }
190
+ // Performance metrics
191
+ if (this.options.verbose) {
192
+ const avgDuration = Math.round(totalDuration / summary.totalTests);
193
+ const slowestTest = this.fileResults
194
+ .flatMap(r => r.tests)
195
+ .sort((a, b) => b.duration - a.duration)[0];
196
+ this.log(this.format('\n⏱️ Performance Metrics:', 'cyan'));
197
+ this.log(this.format(` Average per test: ${avgDuration}ms`, 'white'));
198
+ if (slowestTest) {
199
+ this.log(this.format(` Slowest test: ${slowestTest.name} (${slowestTest.duration}ms)`, 'yellow'));
200
+ }
201
+ }
202
+ // Final status
203
+ const status = summary.totalFailed === 0 ? 'ALL TESTS PASSED! 🎉' : 'SOME TESTS FAILED! ❌';
204
+ const statusColor = summary.totalFailed === 0 ? 'green' : 'red';
205
+ this.log(this.format(`\n${status}`, statusColor));
206
+ }
207
+ // Error display
208
+ error(message, file, stack) {
209
+ if (this.options.json) {
210
+ console.log(JSON.stringify({ event: 'error', message, file, stack }));
211
+ return;
212
+ }
213
+ if (this.options.quiet) {
214
+ console.error(`ERROR: ${message}`);
215
+ }
216
+ else {
217
+ this.log(this.format('\n⚠️ Error', 'red'));
218
+ if (file)
219
+ this.log(this.format(` File: ${file}`, 'yellow'));
220
+ this.log(this.format(` ${message}`, 'red'));
221
+ if (stack && this.options.verbose) {
222
+ this.log(this.format(` Stack:`, 'dim'));
223
+ this.log(this.format(stack.split('\n').map(line => ` ${line}`).join('\n'), 'dim'));
224
+ }
225
+ }
226
+ }
227
+ }
228
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHN0ZXN0LmxvZ2dpbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy90c3Rlc3QubG9nZ2luZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsYUFBYSxJQUFJLEVBQUUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQy9ELE9BQU8sS0FBSyxPQUFPLE1BQU0scUJBQXFCLENBQUM7QUFpQy9DLE1BQU0sT0FBTyxZQUFZO0lBTXZCLFlBQVksVUFBc0IsRUFBRTtRQUg1QixnQkFBVyxHQUFxQixFQUFFLENBQUM7UUFDbkMsc0JBQWlCLEdBQTBCLElBQUksQ0FBQztRQUd0RCxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUM5QixDQUFDO0lBRU8sTUFBTSxDQUFDLElBQVksRUFBRSxLQUFjO1FBQ3pDLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNuQyxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFDRCxPQUFPLEVBQUUsQ0FBQyxJQUFJLEVBQUUsS0FBWSxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVPLEdBQUcsQ0FBQyxPQUFlO1FBQ3pCLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJO1lBQUUsT0FBTztRQUM5QixPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRXJCLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN6QiwrQkFBK0I7UUFDakMsQ0FBQztJQUNILENBQUM7SUFFRCxxQkFBcUI7SUFDckIsWUFBWSxDQUFDLEtBQWE7UUFDeEIsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUk7WUFBRSxPQUFPO1FBQ3BELElBQUksQ0FBQyxHQUFH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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@git.zone/tstest",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "private": false,
5
5
  "description": "a test utility to run tests that match test/**/*.ts",
6
6
  "main": "dist_ts/index.js",
package/readme.plan.md CHANGED
@@ -1,51 +1,199 @@
1
- # Plan for adding single file and glob pattern execution support to tstest
1
+ # Plan for improving logging and output in tstest
2
2
 
3
3
  !! FIRST: Reread /home/philkunz/.claude/CLAUDE.md to ensure following all guidelines !!
4
4
 
5
- ## Goal - ✅ COMPLETED
6
- - ✅ Make `tstest test/test.abc.ts` run the specified file directly
7
- - ✅ Support glob patterns like `tstest test/*.spec.ts` or `tstest test/**/*.test.ts`
8
- - ✅ Maintain backward compatibility with directory argument
9
-
10
- ## Current behavior - UPDATED
11
- - ✅ tstest now supports three modes: directory, single file, and glob patterns
12
- - Directory mode now searches recursively using `**/test*.ts` pattern
13
- - ✅ Single file mode runs a specific test file
14
- - ✅ Glob mode runs files matching the pattern
15
-
16
- ## Completed changes
17
-
18
- ### 1. Update cli argument handling in index.ts
19
- - ✅ Detect argument type: file path, glob pattern, or directory
20
- - Check if argument contains glob characters (*, **, ?, [], etc.)
21
- - ✅ Pass appropriate mode to TsTest constructor
22
- -Added TestExecutionMode enum
23
-
24
- ### 2. Modify TsTest constructor and class
25
- - ✅ Add support for three modes: directory, file, glob
26
- - ✅ Update constructor to accept pattern/path and mode
27
- - ✅ Added executionMode property to track the mode
28
-
29
- ### 3. ✅ Update TestDirectory class
30
- - ✅ Used `listFileTree` for glob pattern support
31
- - ✅ Used `SmartFile.fromFilePath` for single file loading
32
- - ✅ Refactored to support all three modes in `_init` method
33
- - ✅ Return appropriate file array based on mode
34
- - ✅ Changed default directory behavior to recursive search
35
- - ✅ When directory argument: use `**/test*.ts` pattern for recursive search
36
- -This ensures subdirectories are included in test discovery
37
-
38
- ### 4. Test the implementation
39
- - ✅ Created test file `test/test.single.ts` for single file functionality
40
- - ✅ Created test file `test/test.glob.ts` for glob pattern functionality
41
- - Created test in subdirectory `test/subdir/test.sub.ts` for recursive search
42
- - ✅ Tested with existing test files for backward compatibility
43
- -Tested glob patterns: `test/test.*.ts` works correctly
44
- - Verified that default behavior now includes subdirectories
45
-
46
- ## Implementation completed
47
- 1. CLI argument type detection implemented
48
- 2. ✅ TsTest class supports all three modes
49
- 3. ✅ TestDirectory handles files, globs, and directories
50
- 4.Default pattern changed from `test*.ts` to `**/test*.ts` for recursive search
51
- 5.Comprehensive tests added and all modes verified
5
+ ## Goal - ✅ MOSTLY COMPLETED
6
+ - ✅ Make test output cleaner and more visually appealing
7
+ - ✅ Add structured logging capabilities
8
+ - ✅ Support different verbosity levels
9
+ - ✅ Improve CI/CD compatibility
10
+ - Add progress indicators and timing summaries
11
+
12
+ ## Current State - UPDATED
13
+ - ✅ Clean, modern visual design with Unicode characters
14
+ - ✅ Structured output format (JSON support)
15
+ - ✅ Multiple verbosity levels (quiet, normal, verbose)
16
+ - Real-time output with cleaner formatting
17
+ - ✅ Better error aggregation and display
18
+ -TAP protocol support integrated with new logger
19
+
20
+ ## Completed Improvements
21
+
22
+ ### 1. Created new TsTestLogger class
23
+ - ✅ Centralized logging with consistent formatting
24
+ -Support for different output modes (normal, quiet, verbose)
25
+ - ✅ Better visual hierarchy with modern Unicode characters
26
+ - ✅ Progress indicators for multiple test files
27
+ - ✅ Structured error collection and display
28
+
29
+ ### 2. ✅ Updated visual design
30
+ - ✅ Replaced heavy separators with cleaner alternatives
31
+ - ✅ Used better emoji and Unicode characters
32
+ - ✅ Added indentation for hierarchical display
33
+ - ✅ Grouped related information visually
34
+ - ✅ Added color coding consistently
35
+
36
+ ### 3. Added command-line options
37
+ - ✅ `--quiet` for minimal CI-friendly output
38
+ -`--verbose` for detailed debugging information
39
+ - ✅ `--no-color` for environments without color support
40
+ - ✅ `--json` for structured JSON output
41
+ - `--log-file <path>` for persistent logging (TODO)
42
+
43
+ ### 4. Improved progress feedback
44
+ - Show progress bar for multiple files (TODO)
45
+ - ✅ Display current file being executed
46
+ - Show real-time test counts
47
+ - Add ETA for long test suites (TODO)
48
+
49
+ ### 5. ✅ Better error and summary display
50
+ -Collect all errors and display at end
51
+ -Show timing metrics and performance summary (in verbose mode)
52
+ - ✅ Highlight slowest tests (in verbose mode)
53
+ - ✅ Add test failure context
54
+
55
+ ### 6. ✅ Browser console integration
56
+ - ✅ Clearly separate browser logs from test output
57
+ - ⏳ Add browser log filtering options (TODO)
58
+ - ✅ Format browser errors specially
59
+
60
+ ## Implementation Steps - COMPLETED
61
+
62
+ ### Phase 1: ✅ Core Logger Implementation
63
+ 1. ✅ Created `tstest.logging.ts` with TsTestLogger class
64
+ 2. ✅ Added LogOptions interface for configuration
65
+ 3. ✅ Implemented basic formatting methods
66
+ 4. ✅ Added progress and summary methods
67
+
68
+ ### Phase 2: ✅ Integration
69
+ 1. ✅ Updated CLI to accept new command-line options
70
+ 2. ✅ Modified TsTest class to use new logger
71
+ 3. ✅ Updated TapParser to use structured logging
72
+ 4. ✅ Updated TapCombinator for better summaries
73
+
74
+ ### Phase 3: ✅ Visual Improvements
75
+ 1. ✅ Replaced all existing separators
76
+ 2. ✅ Updated color scheme
77
+ 3. ✅ Added emoji and Unicode characters
78
+ 4. ✅ Implemented hierarchical output
79
+
80
+ ### Phase 4: ✅ Advanced Features
81
+ 1. ✅ Add JSON output format
82
+ 2. ⏳ Implement file-based logging (TODO)
83
+ 3. ✅ Add performance metrics collection
84
+ 4. ✅ Create error aggregation system
85
+
86
+ ### Phase 5: ✅ Browser Integration
87
+ 1. ✅ Update browser console forwarding
88
+ 2. ✅ Add browser log formatting
89
+ 3. ✅ Implement browser-specific indicators
90
+
91
+ ## Files modified
92
+ - ✅ `ts/tstest.logging.ts` - New logger implementation (created)
93
+ - ✅ `ts/index.ts` - Added CLI options parsing
94
+ - ✅ `ts/tstest.classes.tstest.ts` - Integrated new logger
95
+ - ✅ `ts/tstest.classes.tap.parser.ts` - Updated output formatting
96
+ - ✅ `ts/tstest.classes.tap.combinator.ts` - Improved summary display
97
+ - ❌ `ts/tstest.logprefixes.ts` - Still in use, can be deprecated later
98
+ - ❌ `package.json` - No new dependencies needed
99
+
100
+ ## Success Criteria - ACHIEVED
101
+ - ✅ Cleaner, more readable test output
102
+ - ✅ Configurable verbosity levels
103
+ - ✅ Better CI/CD integration
104
+ - ✅ Improved error visibility
105
+ - ✅ Performance metrics available
106
+ - ✅ Consistent visual design
107
+ - ✅ Maintained backward compatibility
108
+
109
+ ## Example Output Comparison
110
+
111
+ ### Current Output
112
+ ```
113
+ ☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰☰
114
+ **TSTEST** FOUND 4 TESTFILE(S):
115
+ **TSTEST** test/test.ts
116
+ ------------------------------------------------
117
+ => Running test/test.ts in node.js runtime.
118
+ = = = = = = = = = = = = = = = = = = = = = = = =
119
+ ```
120
+
121
+ ### Actual Output (IMPLEMENTED)
122
+ ```
123
+ 🔍 Test Discovery
124
+ Mode: directory
125
+ Pattern: test
126
+ Found: 4 test file(s)
127
+
128
+ ▶️ test/test.ts (1/4)
129
+ Runtime: node.js
130
+ ✅ prepare test (0ms)
131
+ Summary: 1/1 PASSED
132
+
133
+ ▶️ test/test.single.ts (2/4)
134
+ Runtime: node.js
135
+ ✅ single file test execution (1ms)
136
+ Summary: 1/1 PASSED
137
+
138
+ 📊 Test Summary
139
+ ┌────────────────────────────────┐
140
+ │ Total Files: 4 │
141
+ │ Total Tests: 4 │
142
+ │ Passed: 4 │
143
+ │ Failed: 0 │
144
+ │ Duration: 5739ms │
145
+ └────────────────────────────────┘
146
+
147
+ ALL TESTS PASSED! 🎉
148
+ ```
149
+
150
+ ### Additional Features Implemented
151
+
152
+ 1. **Quiet Mode**:
153
+ ```
154
+ Found 1 tests
155
+ ✅ single file test execution
156
+
157
+ Summary: 1/1 | 1210ms | PASSED
158
+ ```
159
+
160
+ 2. **JSON Mode**:
161
+ ```json
162
+ {"event":"discovery","count":1,"pattern":"test/test.single.ts","executionMode":"file"}
163
+ {"event":"fileStart","filename":"test/test.single.ts","runtime":"node.js","index":1,"total":1}
164
+ {"event":"testResult","testName":"single file test execution","passed":true,"duration":0}
165
+ {"event":"summary","summary":{"totalFiles":1,"totalTests":1,"totalPassed":1,"totalFailed":0,"totalDuration":1223,"fileResults":[...]}}
166
+ ```
167
+
168
+ 3. **Error Display**:
169
+ ```
170
+ ❌ Failed Tests:
171
+
172
+ test/test.fail.ts
173
+ ❌ This test should fail
174
+
175
+ SOME TESTS FAILED! ❌
176
+ ```
177
+
178
+ ## Summary of Implementation
179
+
180
+ The logging improvement plan has been successfully implemented with the following achievements:
181
+
182
+ 1. **Created a new centralized TsTestLogger class** that handles all output formatting
183
+ 2. **Added multiple output modes**: quiet, normal, verbose, and JSON
184
+ 3. **Improved visual design** with modern Unicode characters and emojis
185
+ 4. **Added CLI argument parsing** for all new options
186
+ 5. **Integrated the logger throughout the codebase** (TsTest, TapParser, TapCombinator)
187
+ 6. **Better error aggregation and display** with failed tests shown at the end
188
+ 7. **Performance metrics** available in verbose mode
189
+ 8. **Clean, hierarchical output** that's much more readable
190
+
191
+ ### Remaining TODOs
192
+
193
+ Only a few minor features remain unimplemented:
194
+ - File-based logging (--log-file option)
195
+ - Progress bar visualization
196
+ - ETA for long test suites
197
+ - Browser log filtering options
198
+
199
+ The core logging improvements are complete and provide a much better user experience!
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@git.zone/tstest',
6
- version: '1.1.0',
6
+ version: '1.2.0',
7
7
  description: 'a test utility to run tests that match test/**/*.ts'
8
8
  }
package/ts/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { TsTest } from './tstest.classes.tstest.js';
2
+ import type { LogOptions } from './tstest.logging.js';
2
3
 
3
4
  export enum TestExecutionMode {
4
5
  DIRECTORY = 'directory',
@@ -7,12 +8,54 @@ export enum TestExecutionMode {
7
8
  }
8
9
 
9
10
  export const runCli = async () => {
10
- if (!process.argv[2]) {
11
+ // Parse command line arguments
12
+ const args = process.argv.slice(2);
13
+ const logOptions: LogOptions = {};
14
+ let testPath: string | null = null;
15
+
16
+ // Parse options
17
+ for (let i = 0; i < args.length; i++) {
18
+ const arg = args[i];
19
+
20
+ switch (arg) {
21
+ case '--quiet':
22
+ case '-q':
23
+ logOptions.quiet = true;
24
+ break;
25
+ case '--verbose':
26
+ case '-v':
27
+ logOptions.verbose = true;
28
+ break;
29
+ case '--no-color':
30
+ logOptions.noColor = true;
31
+ break;
32
+ case '--json':
33
+ logOptions.json = true;
34
+ break;
35
+ case '--log-file':
36
+ if (i + 1 < args.length) {
37
+ logOptions.logFile = args[++i];
38
+ }
39
+ break;
40
+ default:
41
+ if (!arg.startsWith('-')) {
42
+ testPath = arg;
43
+ }
44
+ }
45
+ }
46
+
47
+ if (!testPath) {
11
48
  console.error('You must specify a test directory/file/pattern as argument. Please try again.');
49
+ console.error('\nUsage: tstest <path> [options]');
50
+ console.error('\nOptions:');
51
+ console.error(' --quiet, -q Minimal output');
52
+ console.error(' --verbose, -v Verbose output');
53
+ console.error(' --no-color Disable colored output');
54
+ console.error(' --json Output results as JSON');
55
+ console.error(' --log-file Write logs to file');
12
56
  process.exit(1);
13
57
  }
14
58
 
15
- const testPath = process.argv[2];
16
59
  let executionMode: TestExecutionMode;
17
60
 
18
61
  // Detect execution mode based on the argument
@@ -24,6 +67,6 @@ export const runCli = async () => {
24
67
  executionMode = TestExecutionMode.DIRECTORY;
25
68
  }
26
69
 
27
- const tsTestInstance = new TsTest(process.cwd(), testPath, executionMode);
70
+ const tsTestInstance = new TsTest(process.cwd(), testPath, executionMode, logOptions);
28
71
  await tsTestInstance.run();
29
72
  };