@git.zone/tstest 1.0.96 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/readme.plan.md ADDED
@@ -0,0 +1,199 @@
1
+ # Plan for improving logging and output in tstest
2
+
3
+ !! FIRST: Reread /home/philkunz/.claude/CLAUDE.md to ensure following all guidelines !!
4
+
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.0.96',
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,10 +1,72 @@
1
1
  import { TsTest } from './tstest.classes.tstest.js';
2
+ import type { LogOptions } from './tstest.logging.js';
3
+
4
+ export enum TestExecutionMode {
5
+ DIRECTORY = 'directory',
6
+ FILE = 'file',
7
+ GLOB = 'glob'
8
+ }
2
9
 
3
10
  export const runCli = async () => {
4
- if (!process.argv[2]) {
5
- console.error('You must specify a test directory as argument. Please try again.');
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) {
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');
6
56
  process.exit(1);
7
57
  }
8
- const tsTestInstance = new TsTest(process.cwd(), process.argv[2]);
58
+
59
+ let executionMode: TestExecutionMode;
60
+
61
+ // Detect execution mode based on the argument
62
+ if (testPath.includes('*') || testPath.includes('?') || testPath.includes('[') || testPath.includes('{')) {
63
+ executionMode = TestExecutionMode.GLOB;
64
+ } else if (testPath.endsWith('.ts')) {
65
+ executionMode = TestExecutionMode.FILE;
66
+ } else {
67
+ executionMode = TestExecutionMode.DIRECTORY;
68
+ }
69
+
70
+ const tsTestInstance = new TsTest(process.cwd(), testPath, executionMode, logOptions);
9
71
  await tsTestInstance.run();
10
72
  };
@@ -6,59 +6,37 @@ import { coloredString as cs } from '@push.rocks/consolecolor';
6
6
 
7
7
  import { TapParser } from './tstest.classes.tap.parser.js';
8
8
  import * as logPrefixes from './tstest.logprefixes.js';
9
+ import { TsTestLogger } from './tstest.logging.js';
9
10
 
10
11
  export class TapCombinator {
11
12
  tapParserStore: TapParser[] = [];
13
+ private logger: TsTestLogger;
14
+
15
+ constructor(logger: TsTestLogger) {
16
+ this.logger = logger;
17
+ }
18
+
12
19
  addTapParser(tapParserArg: TapParser) {
13
20
  this.tapParserStore.push(tapParserArg);
14
21
  }
15
22
 
16
23
  evaluate() {
17
- console.log(
18
- `${logPrefixes.TsTestPrefix} RESULTS FOR ${this.tapParserStore.length} TESTFILE(S):`
19
- );
20
-
21
- let failGlobal = false; // determine wether tstest should fail
24
+ // Call the logger's summary method
25
+ this.logger.summary();
26
+
27
+ // Check for failures
28
+ let failGlobal = false;
22
29
  for (const tapParser of this.tapParserStore) {
23
- if (!tapParser.expectedTests) {
24
- failGlobal = true;
25
- let overviewString =
26
- logPrefixes.TsTestPrefix +
27
- cs(` ${tapParser.fileName} ${plugins.figures.cross}`, 'red') +
28
- ` ${plugins.figures.pointer} ` +
29
- `does not specify tests!`;
30
- console.log(overviewString);
31
- } else if (tapParser.expectedTests !== tapParser.receivedTests) {
32
- failGlobal = true;
33
- let overviewString =
34
- logPrefixes.TsTestPrefix +
35
- cs(` ${tapParser.fileName} ${plugins.figures.cross}`, 'red') +
36
- ` ${plugins.figures.pointer} ` +
37
- tapParser.getTestOverviewAsString() +
38
- `did not execute all specified tests!`;
39
- console.log(overviewString);
40
- } else if (tapParser.getErrorTests().length === 0) {
41
- let overviewString =
42
- logPrefixes.TsTestPrefix +
43
- cs(` ${tapParser.fileName} ${plugins.figures.tick}`, 'green') +
44
- ` ${plugins.figures.pointer} ` +
45
- tapParser.getTestOverviewAsString();
46
- console.log(overviewString);
47
- } else {
30
+ if (!tapParser.expectedTests ||
31
+ tapParser.expectedTests !== tapParser.receivedTests ||
32
+ tapParser.getErrorTests().length > 0) {
48
33
  failGlobal = true;
49
- let overviewString =
50
- logPrefixes.TsTestPrefix +
51
- cs(` ${tapParser.fileName} ${plugins.figures.cross}`, 'red') +
52
- ` ${plugins.figures.pointer} ` +
53
- tapParser.getTestOverviewAsString();
54
- console.log(overviewString);
34
+ break;
55
35
  }
56
36
  }
57
- console.log(cs(plugins.figures.hamburger.repeat(48), 'cyan'));
58
- if (!failGlobal) {
59
- console.log(cs('FINAL RESULT: SUCCESS!', 'green'));
60
- } else {
61
- console.log(cs('FINAL RESULT: FAIL!', 'red'));
37
+
38
+ // Exit with error code if tests failed
39
+ if (failGlobal) {
62
40
  process.exit(1);
63
41
  }
64
42
  }
@@ -7,6 +7,7 @@ import { coloredString as cs } from '@push.rocks/consolecolor';
7
7
  import * as plugins from './tstest.plugins.js';
8
8
  import { TapTestResult } from './tstest.classes.tap.testresult.js';
9
9
  import * as logPrefixes from './tstest.logprefixes.js';
10
+ import { TsTestLogger } from './tstest.logging.js';
10
11
 
11
12
  export class TapParser {
12
13
  testStore: TapTestResult[] = [];
@@ -19,11 +20,15 @@ export class TapParser {
19
20
  activeTapTestResult: TapTestResult;
20
21
 
21
22
  pretaskRegex = /^::__PRETASK:(.*)$/;
23
+
24
+ private logger: TsTestLogger;
22
25
 
23
26
  /**
24
27
  * the constructor for TapParser
25
28
  */
26
- constructor(public fileName: string) {}
29
+ constructor(public fileName: string, logger?: TsTestLogger) {
30
+ this.logger = logger;
31
+ }
27
32
 
28
33
  private _getNewTapTestResult() {
29
34
  this.activeTapTestResult = new TapTestResult(this.testStore.length + 1);
@@ -45,9 +50,9 @@ export class TapParser {
45
50
  logLineIsTapProtocol = true;
46
51
  const regexResult = this.expectedTestsRegex.exec(logLine);
47
52
  this.expectedTests = parseInt(regexResult[2]);
48
- console.log(
49
- `${logPrefixes.TapPrefix} ${cs(`Expecting ${this.expectedTests} tests!`, 'blue')}`
50
- );
53
+ if (this.logger) {
54
+ this.logger.tapOutput(`Expecting ${this.expectedTests} tests!`);
55
+ }
51
56
 
52
57
  // initiating first TapResult
53
58
  this._getNewTapTestResult();
@@ -55,7 +60,9 @@ export class TapParser {
55
60
  logLineIsTapProtocol = true;
56
61
  const pretaskContentMatch = this.pretaskRegex.exec(logLine);
57
62
  if (pretaskContentMatch && pretaskContentMatch[1]) {
58
- console.log(`${logPrefixes.TapPretaskPrefix} Pretask ->${pretaskContentMatch[1]}: Success.`);
63
+ if (this.logger) {
64
+ this.logger.tapOutput(`Pretask -> ${pretaskContentMatch[1]}: Success.`);
65
+ }
59
66
  }
60
67
  } else if (this.testStatusRegex.test(logLine)) {
61
68
  logLineIsTapProtocol = true;
@@ -73,26 +80,20 @@ export class TapParser {
73
80
 
74
81
  // test for protocol error
75
82
  if (testId !== this.activeTapTestResult.id) {
76
- console.log(
77
- `${logPrefixes.TapErrorPrefix} Something is strange! Test Ids are not equal!`
78
- );
83
+ if (this.logger) {
84
+ this.logger.error('Something is strange! Test Ids are not equal!');
85
+ }
79
86
  }
80
87
  this.activeTapTestResult.setTestResult(testOk);
81
88
 
82
89
  if (testOk) {
83
- console.log(
84
- logPrefixes.TapPrefix,
85
- `${cs(`T${testId} ${plugins.figures.tick}`, 'green')} ${plugins.figures.arrowRight} ` +
86
- cs(testSubject, 'blue') +
87
- ` | ${cs(`${testDuration} ms`, 'orange')}`
88
- );
90
+ if (this.logger) {
91
+ this.logger.testResult(testSubject, true, testDuration);
92
+ }
89
93
  } else {
90
- console.log(
91
- logPrefixes.TapPrefix,
92
- `${cs(`T${testId} ${plugins.figures.cross}`, 'red')} ${plugins.figures.arrowRight} ` +
93
- cs(testSubject, 'blue') +
94
- ` | ${cs(`${testDuration} ms`, 'orange')}`
95
- );
94
+ if (this.logger) {
95
+ this.logger.testResult(testSubject, false, testDuration);
96
+ }
96
97
  }
97
98
  }
98
99
 
@@ -100,7 +101,9 @@ export class TapParser {
100
101
  if (this.activeTapTestResult) {
101
102
  this.activeTapTestResult.addLogLine(logLine);
102
103
  }
103
- console.log(logLine);
104
+ if (this.logger) {
105
+ this.logger.tapOutput(logLine);
106
+ }
104
107
  }
105
108
 
106
109
  if (this.activeTapTestResult && this.activeTapTestResult.testSettled) {
@@ -172,38 +175,32 @@ export class TapParser {
172
175
 
173
176
  // check wether all tests ran
174
177
  if (this.expectedTests === this.receivedTests) {
175
- console.log(
176
- `${logPrefixes.TapPrefix} ${cs(
177
- `${this.receivedTests} out of ${this.expectedTests} Tests completed!`,
178
- 'green'
179
- )}`
180
- );
178
+ if (this.logger) {
179
+ this.logger.tapOutput(`${this.receivedTests} out of ${this.expectedTests} Tests completed!`);
180
+ }
181
181
  } else {
182
- console.log(
183
- `${logPrefixes.TapErrorPrefix} ${cs(
184
- `Only ${this.receivedTests} out of ${this.expectedTests} completed!`,
185
- 'red'
186
- )}`
187
- );
182
+ if (this.logger) {
183
+ this.logger.error(`Only ${this.receivedTests} out of ${this.expectedTests} completed!`);
184
+ }
188
185
  }
189
186
  if (!this.expectedTests) {
190
- console.log(cs('Error: No tests were defined. Therefore the testfile failed!', 'red'));
187
+ if (this.logger) {
188
+ this.logger.error('No tests were defined. Therefore the testfile failed!');
189
+ }
191
190
  } else if (this.expectedTests !== this.receivedTests) {
192
- console.log(
193
- cs(
194
- 'Error: The amount of received tests and expectedTests is unequal! Therefore the testfile failed',
195
- 'red'
196
- )
197
- );
191
+ if (this.logger) {
192
+ this.logger.error('The amount of received tests and expectedTests is unequal! Therefore the testfile failed');
193
+ }
198
194
  } else if (this.getErrorTests().length === 0) {
199
- console.log(`${logPrefixes.TapPrefix} ${cs(`All tests are successfull!!!`, 'green')}`);
195
+ if (this.logger) {
196
+ this.logger.tapOutput('All tests are successfull!!!');
197
+ this.logger.testFileEnd(this.receivedTests, 0, 0);
198
+ }
200
199
  } else {
201
- console.log(
202
- `${logPrefixes.TapPrefix} ${cs(
203
- `${this.getErrorTests().length} tests threw an error!!!`,
204
- 'red'
205
- )}`
206
- );
200
+ if (this.logger) {
201
+ this.logger.tapOutput(`${this.getErrorTests().length} tests threw an error!!!`, true);
202
+ this.logger.testFileEnd(this.receivedTests - this.getErrorTests().length, this.getErrorTests().length, 0);
203
+ }
207
204
  }
208
205
  }
209
206
  }
@@ -1,6 +1,7 @@
1
1
  import * as plugins from './tstest.plugins.js';
2
2
  import * as paths from './tstest.paths.js';
3
3
  import { SmartFile } from '@push.rocks/smartfile';
4
+ import { TestExecutionMode } from './index.js';
4
5
 
5
6
  // tap related stuff
6
7
  import { TapCombinator } from './tstest.classes.tap.combinator.js';
@@ -14,14 +15,14 @@ export class TestDirectory {
14
15
  cwd: string;
15
16
 
16
17
  /**
17
- * the relative location of the test dir
18
+ * the test path or pattern
18
19
  */
19
- relativePath: string;
20
+ testPath: string;
20
21
 
21
22
  /**
22
- * the absolute path of the test dir
23
+ * the execution mode
23
24
  */
24
- absolutePath: string;
25
+ executionMode: TestExecutionMode;
25
26
 
26
27
  /**
27
28
  * an array of Smartfiles
@@ -30,27 +31,71 @@ export class TestDirectory {
30
31
 
31
32
  /**
32
33
  * the constructor for TestDirectory
33
- * tell it the path
34
- * @param pathToTestDirectory
34
+ * @param cwdArg - the current working directory
35
+ * @param testPathArg - the test path/pattern
36
+ * @param executionModeArg - the execution mode
35
37
  */
36
- constructor(cwdArg: string, relativePathToTestDirectory: string) {
38
+ constructor(cwdArg: string, testPathArg: string, executionModeArg: TestExecutionMode) {
37
39
  this.cwd = cwdArg;
38
- this.relativePath = relativePathToTestDirectory;
40
+ this.testPath = testPathArg;
41
+ this.executionMode = executionModeArg;
39
42
  }
40
43
 
41
44
  private async _init() {
42
- this.testfileArray = await plugins.smartfile.fs.fileTreeToObject(
43
- plugins.path.join(this.cwd, this.relativePath),
44
- 'test*.ts'
45
- );
45
+ switch (this.executionMode) {
46
+ case TestExecutionMode.FILE:
47
+ // Single file mode
48
+ const filePath = plugins.path.isAbsolute(this.testPath)
49
+ ? this.testPath
50
+ : plugins.path.join(this.cwd, this.testPath);
51
+
52
+ if (await plugins.smartfile.fs.fileExists(filePath)) {
53
+ this.testfileArray = [await plugins.smartfile.SmartFile.fromFilePath(filePath)];
54
+ } else {
55
+ throw new Error(`Test file not found: ${filePath}`);
56
+ }
57
+ break;
58
+
59
+ case TestExecutionMode.GLOB:
60
+ // Glob pattern mode - use listFileTree which supports glob patterns
61
+ const globPattern = this.testPath;
62
+ const matchedFiles = await plugins.smartfile.fs.listFileTree(this.cwd, globPattern);
63
+
64
+ this.testfileArray = await Promise.all(
65
+ matchedFiles.map(async (filePath) => {
66
+ const absolutePath = plugins.path.isAbsolute(filePath)
67
+ ? filePath
68
+ : plugins.path.join(this.cwd, filePath);
69
+ return await plugins.smartfile.SmartFile.fromFilePath(absolutePath);
70
+ })
71
+ );
72
+ break;
73
+
74
+ case TestExecutionMode.DIRECTORY:
75
+ // Directory mode - now recursive with ** pattern
76
+ const dirPath = plugins.path.join(this.cwd, this.testPath);
77
+ const testPattern = '**/test*.ts';
78
+
79
+ const testFiles = await plugins.smartfile.fs.listFileTree(dirPath, testPattern);
80
+
81
+ this.testfileArray = await Promise.all(
82
+ testFiles.map(async (filePath) => {
83
+ const absolutePath = plugins.path.isAbsolute(filePath)
84
+ ? filePath
85
+ : plugins.path.join(dirPath, filePath);
86
+ return await plugins.smartfile.SmartFile.fromFilePath(absolutePath);
87
+ })
88
+ );
89
+ break;
90
+ }
46
91
  }
47
92
 
48
93
  async getTestFilePathArray() {
49
94
  await this._init();
50
95
  const testFilePaths: string[] = [];
51
96
  for (const testFile of this.testfileArray) {
52
- const filePath = plugins.path.join(this.relativePath, testFile.path);
53
- testFilePaths.push(filePath);
97
+ // Use the path directly from the SmartFile
98
+ testFilePaths.push(testFile.path);
54
99
  }
55
100
  return testFilePaths;
56
101
  }