taist 0.1.2 → 0.1.4

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/instrument.js CHANGED
@@ -94,22 +94,29 @@ if (tracer.options.enabled) {
94
94
  }
95
95
 
96
96
  // Output stats periodically if not writing to file
97
+ // Use unref() so this doesn't keep the process alive
97
98
  if (!tracer.options.outputFile) {
98
- setInterval(() => {
99
+ const outputTimer = setInterval(() => {
99
100
  const output = tracer.writeOutput();
100
101
  console.log('\n' + output);
101
102
  }, tracer.options.outputInterval);
103
+ outputTimer.unref();
102
104
  }
103
105
 
104
- // Handle shutdown gracefully
106
+ // Handle shutdown gracefully - but don't force exit (let process exit naturally)
107
+ // This allows test runners like Vitest to handle cleanup properly
108
+ let shutdownCalled = false;
105
109
  const shutdown = () => {
110
+ if (shutdownCalled) return;
111
+ shutdownCalled = true;
106
112
  logger.log('Shutting down...');
107
113
  const insights = tracer.getInsights();
108
114
  const output = tracer.formatOutput(insights);
109
115
  console.log('\n=== Final Trace Summary ===');
110
116
  console.log(output);
111
117
  console.log('===========================\n');
112
- process.exit(0);
118
+ // Don't call process.exit() - let the process exit naturally
119
+ // This prevents interference with test runners like Vitest
113
120
  };
114
121
 
115
122
  process.on('SIGINT', shutdown);
@@ -65,6 +65,8 @@ export class ServiceTracer extends EventEmitter {
65
65
  this.outputTimer = setInterval(() => {
66
66
  this.writeOutput();
67
67
  }, this.options.outputInterval);
68
+ // Don't keep process alive just for output
69
+ this.outputTimer.unref();
68
70
  }
69
71
  }
70
72
 
@@ -45,10 +45,22 @@ export class ToonFormatter {
45
45
  */
46
46
  format(results) {
47
47
  const lines = [];
48
+ const total = results.stats?.total || 0;
49
+ const tests = results.tests || [];
48
50
 
49
51
  // Header
50
52
  lines.push(this.formatHeader(results));
51
53
 
54
+ // Show passing tests when running small batches (≤10 tests)
55
+ if (total > 0 && total <= 10) {
56
+ const passingTests = tests.filter(t => t.state === 'pass');
57
+ for (const test of passingTests) {
58
+ const duration = Math.round(test.duration);
59
+ const shortName = this.shortenTestName(test.name);
60
+ lines.push(`✓ ${shortName} (${duration}ms)`);
61
+ }
62
+ }
63
+
52
64
  // Failures
53
65
  if (results.failures && results.failures.length > 0) {
54
66
  lines.push('');
@@ -76,8 +88,19 @@ export class ToonFormatter {
76
88
  return lines.join('\n');
77
89
  }
78
90
 
91
+ /**
92
+ * Shorten a test name for display
93
+ * "Suite > Nested > actual test name" -> "actual test name"
94
+ */
95
+ shortenTestName(name) {
96
+ if (!name) return '';
97
+ const parts = name.split(' > ');
98
+ return parts[parts.length - 1] || name;
99
+ }
100
+
79
101
  /**
80
102
  * Format test result header
103
+ * Note: total represents tests that actually ran, not discovered
81
104
  */
82
105
  formatHeader(results) {
83
106
  const passed = results.stats?.passed || 0;
@@ -59,6 +59,7 @@ export class TaistReporter {
59
59
  this.taskResults = new Map(); // Map task id to result
60
60
  this.results = {
61
61
  stats: { total: 0, passed: 0, failed: 0, skipped: 0 },
62
+ tests: [], // Individual test results for enhanced output
62
63
  failures: [],
63
64
  duration: 0,
64
65
  trace: []
@@ -117,6 +118,7 @@ export class TaistReporter {
117
118
 
118
119
  // Reset stats
119
120
  this.results.stats = { total: 0, passed: 0, failed: 0, skipped: 0 };
121
+ this.results.tests = [];
120
122
  this.results.failures = [];
121
123
 
122
124
  // Process all test files
@@ -181,17 +183,30 @@ export class TaistReporter {
181
183
  */
182
184
  _processTask(task, file) {
183
185
  if (task.type === 'test') {
184
- this.results.stats.total++;
185
-
186
186
  const state = task.result?.state;
187
+
188
+ // Only count tests that actually ran (have a pass/fail result)
187
189
  if (state === 'pass') {
190
+ this.results.stats.total++;
188
191
  this.results.stats.passed++;
192
+ this.results.tests.push({
193
+ name: this._getTestName(task),
194
+ duration: task.result?.duration || 0,
195
+ state: 'pass'
196
+ });
189
197
  } else if (state === 'fail') {
198
+ this.results.stats.total++;
190
199
  this.results.stats.failed++;
191
200
  this.results.failures.push(this._formatFailure(task, file));
201
+ this.results.tests.push({
202
+ name: this._getTestName(task),
203
+ duration: task.result?.duration || 0,
204
+ state: 'fail'
205
+ });
192
206
  } else if (state === 'skip') {
193
207
  this.results.stats.skipped++;
194
208
  }
209
+ // Tests without state (filtered out) are not counted
195
210
  } else if (task.type === 'suite' && task.tasks) {
196
211
  // Process nested tasks
197
212
  for (const subtask of task.tasks) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taist",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Token-Optimized Testing Framework for AI-Assisted Development",
5
5
  "main": "index.js",
6
6
  "type": "module",