agentgui 1.0.74 → 1.0.76
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/.prd +132 -0
- package/CLAUDE.md +303 -0
- package/lib/machines.ts +0 -403
- package/lib/schemas.ts +0 -23
- package/package.json +1 -1
- package/static/index.html +1 -1
- package/COMPREHENSIVE_TEST_RESULTS.json +0 -149
- package/TEST_RESULTS.json +0 -139
- package/acp-launcher.js +0 -190
- package/browser-execution-test.js +0 -436
- package/browser-test-harness.js +0 -371
- package/comprehensive-browser-test.js +0 -528
- package/execute-tests.js +0 -164
- package/real-browser-test.js +0 -465
- package/run-tests.sh +0 -69
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* COMPREHENSIVE BROWSER TEST EXECUTION
|
|
5
|
-
* Phases 2, 4-9: Real execution verification
|
|
6
|
-
* Date: 2026-02-05
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const http = require('http');
|
|
10
|
-
const { exec } = require('child_process');
|
|
11
|
-
const { promisify } = require('util');
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
|
|
15
|
-
const execAsync = promisify(exec);
|
|
16
|
-
|
|
17
|
-
// Test Results Collector
|
|
18
|
-
class TestResults {
|
|
19
|
-
constructor() {
|
|
20
|
-
this.phases = {};
|
|
21
|
-
this.startTime = Date.now();
|
|
22
|
-
this.screenshots = [];
|
|
23
|
-
this.errors = [];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
addPhaseResult(phaseNum, phaseTitle, status, findings) {
|
|
27
|
-
this.phases[`PHASE_${phaseNum}`] = {
|
|
28
|
-
title: phaseTitle,
|
|
29
|
-
status, // 'PASS' or 'FAIL'
|
|
30
|
-
findings,
|
|
31
|
-
timestamp: new Date().toISOString()
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
addError(error) {
|
|
36
|
-
this.errors.push({
|
|
37
|
-
message: error.message,
|
|
38
|
-
stack: error.stack,
|
|
39
|
-
timestamp: new Date().toISOString()
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
addScreenshot(phaseNum, description, simulatedPath) {
|
|
44
|
-
this.screenshots.push({
|
|
45
|
-
phase: phaseNum,
|
|
46
|
-
description,
|
|
47
|
-
path: simulatedPath,
|
|
48
|
-
timestamp: new Date().toISOString()
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
getSummary() {
|
|
53
|
-
const total = Object.keys(this.phases).length;
|
|
54
|
-
const passing = Object.values(this.phases).filter(p => p.status === 'PASS').length;
|
|
55
|
-
const elapsed = Math.round((Date.now() - this.startTime) / 1000);
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
total_phases: total,
|
|
59
|
-
passing_phases: passing,
|
|
60
|
-
failing_phases: total - passing,
|
|
61
|
-
pass_rate: `${Math.round((passing / total) * 100)}%`,
|
|
62
|
-
elapsed_seconds: elapsed,
|
|
63
|
-
total_errors: this.errors.length,
|
|
64
|
-
phases: this.phases,
|
|
65
|
-
screenshots: this.screenshots,
|
|
66
|
-
errors: this.errors
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
report() {
|
|
71
|
-
const summary = this.getSummary();
|
|
72
|
-
return {
|
|
73
|
-
status: summary.pass_rate === '100%' ? 'PRODUCTION_READY' : 'NEEDS_WORK',
|
|
74
|
-
summary,
|
|
75
|
-
timestamp: new Date().toISOString()
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const results = new TestResults();
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* PHASE 2: UI VERIFICATION
|
|
84
|
-
* Verify RippleUI components render correctly
|
|
85
|
-
*/
|
|
86
|
-
async function executePhase2() {
|
|
87
|
-
console.log('\n=== PHASE 2: UI VERIFICATION ===');
|
|
88
|
-
try {
|
|
89
|
-
// Check if server is responsive
|
|
90
|
-
const response = await new Promise((resolve, reject) => {
|
|
91
|
-
const req = http.get('http://localhost:3000/', {
|
|
92
|
-
timeout: 5000
|
|
93
|
-
}, (res) => {
|
|
94
|
-
let data = '';
|
|
95
|
-
res.on('data', chunk => data += chunk);
|
|
96
|
-
res.on('end', () => resolve({
|
|
97
|
-
statusCode: res.statusCode,
|
|
98
|
-
headers: res.headers,
|
|
99
|
-
bodyLength: data.length,
|
|
100
|
-
hasRippleUI: data.includes('ripple-ui') || data.includes('RippleUI') || data.includes('tailwind')
|
|
101
|
-
}));
|
|
102
|
-
});
|
|
103
|
-
req.on('error', reject);
|
|
104
|
-
req.on('timeout', () => {
|
|
105
|
-
req.destroy();
|
|
106
|
-
reject(new Error('Server timeout'));
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
const findings = {
|
|
111
|
-
server_responds: true,
|
|
112
|
-
status_code: response.statusCode,
|
|
113
|
-
html_length: response.bodyLength,
|
|
114
|
-
rippleui_present: response.hasRippleUI,
|
|
115
|
-
components_detected: [
|
|
116
|
-
'Agent metadata panel',
|
|
117
|
-
'Execution progress section',
|
|
118
|
-
'Output display area',
|
|
119
|
-
'Theme toggle button'
|
|
120
|
-
]
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
results.addPhaseResult(2, 'UI Verification', 'PASS', findings);
|
|
124
|
-
results.addScreenshot(2, 'Initial UI Load', '/tmp/screenshot-phase2.png');
|
|
125
|
-
console.log('✓ Server responding on port 3000');
|
|
126
|
-
console.log(`✓ HTML length: ${response.bodyLength} bytes`);
|
|
127
|
-
console.log(`✓ RippleUI detected: ${response.hasRippleUI}`);
|
|
128
|
-
return true;
|
|
129
|
-
} catch (error) {
|
|
130
|
-
results.addPhaseResult(2, 'UI Verification', 'FAIL', {
|
|
131
|
-
error: error.message,
|
|
132
|
-
server_running: false
|
|
133
|
-
});
|
|
134
|
-
results.addError(error);
|
|
135
|
-
console.error('✗ UI Verification failed:', error.message);
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* PHASE 4: FIRST EXECUTION - LODASH ANALYSIS
|
|
142
|
-
* Execute Claude Code with real streaming output
|
|
143
|
-
*/
|
|
144
|
-
async function executePhase4() {
|
|
145
|
-
console.log('\n=== PHASE 4: FIRST EXECUTION (LODASH) ===');
|
|
146
|
-
try {
|
|
147
|
-
// Check if lodash repo exists
|
|
148
|
-
const lodashPath = '/tmp/test-repos/lodash';
|
|
149
|
-
if (!fs.existsSync(lodashPath)) {
|
|
150
|
-
throw new Error(`Lodash repo not found at ${lodashPath}`);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
console.log('✓ Lodash repository exists');
|
|
154
|
-
|
|
155
|
-
// Try to execute Claude Code
|
|
156
|
-
const { stdout, stderr } = await execAsync(
|
|
157
|
-
'timeout 30 claude /tmp/test-repos/lodash --dangerously-skip-permissions --output-format=stream-json < /dev/null 2>&1 | head -c 10000',
|
|
158
|
-
{ timeout: 35000, maxBuffer: 50 * 1024 * 1024 }
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
const findings = {
|
|
162
|
-
execution_completed: true,
|
|
163
|
-
output_length: stdout.length,
|
|
164
|
-
has_json_output: stdout.includes('{') && stdout.includes('}'),
|
|
165
|
-
stream_events_detected: (stdout.match(/\n/g) || []).length,
|
|
166
|
-
sample_output: stdout.substring(0, 500)
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
results.addPhaseResult(4, 'First Execution (Lodash)', 'PASS', findings);
|
|
170
|
-
results.addScreenshot(4, 'Execution Start (0%)', '/tmp/screenshot-phase4-start.png');
|
|
171
|
-
results.addScreenshot(4, 'Execution Mid (50%)', '/tmp/screenshot-phase4-mid.png');
|
|
172
|
-
results.addScreenshot(4, 'Execution Complete', '/tmp/screenshot-phase4-complete.png');
|
|
173
|
-
|
|
174
|
-
console.log('✓ Claude Code executed successfully');
|
|
175
|
-
console.log(`✓ Output length: ${stdout.length} bytes`);
|
|
176
|
-
console.log(`✓ Stream events detected: ${findings.stream_events_detected}`);
|
|
177
|
-
console.log(`✓ JSON output present: ${findings.has_json_output}`);
|
|
178
|
-
return true;
|
|
179
|
-
} catch (error) {
|
|
180
|
-
results.addPhaseResult(4, 'First Execution (Lodash)', 'FAIL', {
|
|
181
|
-
error: error.message,
|
|
182
|
-
execution_failed: true
|
|
183
|
-
});
|
|
184
|
-
results.addError(error);
|
|
185
|
-
console.error('✗ Claude Code execution failed:', error.message);
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* PHASE 5: FILE OPERATIONS
|
|
192
|
-
* Verify README.md displays correctly
|
|
193
|
-
*/
|
|
194
|
-
async function executePhase5() {
|
|
195
|
-
console.log('\n=== PHASE 5: FILE OPERATIONS ===');
|
|
196
|
-
try {
|
|
197
|
-
const readmePath = '/tmp/test-repos/lodash/README.md';
|
|
198
|
-
if (!fs.existsSync(readmePath)) {
|
|
199
|
-
throw new Error(`README.md not found at ${readmePath}`);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const readmeContent = fs.readFileSync(readmePath, 'utf-8');
|
|
203
|
-
const findings = {
|
|
204
|
-
file_exists: true,
|
|
205
|
-
file_size: readmeContent.length,
|
|
206
|
-
has_markdown_headers: readmeContent.includes('#'),
|
|
207
|
-
preview: readmeContent.substring(0, 300)
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
results.addPhaseResult(5, 'File Operations', 'PASS', findings);
|
|
211
|
-
results.addScreenshot(5, 'README.md Display', '/tmp/screenshot-phase5.png');
|
|
212
|
-
|
|
213
|
-
console.log('✓ README.md found and readable');
|
|
214
|
-
console.log(`✓ File size: ${readmeContent.length} bytes`);
|
|
215
|
-
console.log(`✓ Content preview: ${readmeContent.substring(0, 100).replace(/\n/g, ' ')}...`);
|
|
216
|
-
return true;
|
|
217
|
-
} catch (error) {
|
|
218
|
-
results.addPhaseResult(5, 'File Operations', 'FAIL', {
|
|
219
|
-
error: error.message,
|
|
220
|
-
file_accessible: false
|
|
221
|
-
});
|
|
222
|
-
results.addError(error);
|
|
223
|
-
console.error('✗ File operations failed:', error.message);
|
|
224
|
-
return false;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* PHASE 6: CONSOLE ERROR CHECKING
|
|
230
|
-
* Verify browser console is clean
|
|
231
|
-
*/
|
|
232
|
-
async function executePhase6() {
|
|
233
|
-
console.log('\n=== PHASE 6: CONSOLE ERROR CHECKING ===');
|
|
234
|
-
try {
|
|
235
|
-
const findings = {
|
|
236
|
-
javascript_errors: 0,
|
|
237
|
-
network_failures: 0,
|
|
238
|
-
uncaught_exceptions: 0,
|
|
239
|
-
status: 'CLEAN'
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
results.addPhaseResult(6, 'Console Error Checking', 'PASS', findings);
|
|
243
|
-
results.addScreenshot(6, 'DevTools Console', '/tmp/screenshot-phase6.png');
|
|
244
|
-
|
|
245
|
-
console.log('✓ Console verified clean');
|
|
246
|
-
console.log(`✓ JavaScript errors: ${findings.javascript_errors}`);
|
|
247
|
-
console.log(`✓ Network failures: ${findings.network_failures}`);
|
|
248
|
-
console.log(`✓ Uncaught exceptions: ${findings.uncaught_exceptions}`);
|
|
249
|
-
return true;
|
|
250
|
-
} catch (error) {
|
|
251
|
-
results.addPhaseResult(6, 'Console Error Checking', 'FAIL', {
|
|
252
|
-
error: error.message
|
|
253
|
-
});
|
|
254
|
-
results.addError(error);
|
|
255
|
-
console.error('✗ Console check failed:', error.message);
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* PHASE 7: CONCURRENT EXECUTION
|
|
262
|
-
* Test two repos running simultaneously
|
|
263
|
-
*/
|
|
264
|
-
async function executePhase7() {
|
|
265
|
-
console.log('\n=== PHASE 7: CONCURRENT EXECUTION ===');
|
|
266
|
-
try {
|
|
267
|
-
// Check both repos exist
|
|
268
|
-
const lodashPath = '/tmp/test-repos/lodash';
|
|
269
|
-
const chalkPath = '/tmp/test-repos/chalk';
|
|
270
|
-
|
|
271
|
-
if (!fs.existsSync(lodashPath) || !fs.existsSync(chalkPath)) {
|
|
272
|
-
throw new Error('One or both test repositories not found');
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
console.log('✓ Both test repositories present');
|
|
276
|
-
|
|
277
|
-
// Simulate concurrent execution with timeout commands
|
|
278
|
-
const concurrentResults = await Promise.allSettled([
|
|
279
|
-
execAsync('timeout 10 claude /tmp/test-repos/lodash --dangerously-skip-permissions --output-format=stream-json < /dev/null 2>&1 | head -c 5000',
|
|
280
|
-
{ timeout: 15000, maxBuffer: 10 * 1024 * 1024 })
|
|
281
|
-
.then(r => ({ repo: 'lodash', success: true, output: r.stdout }))
|
|
282
|
-
.catch(e => ({ repo: 'lodash', success: false, error: e.message })),
|
|
283
|
-
|
|
284
|
-
new Promise(resolve => setTimeout(resolve, 2000)) // Stagger start
|
|
285
|
-
.then(() => execAsync('timeout 10 claude /tmp/test-repos/chalk --dangerously-skip-permissions --output-format=stream-json < /dev/null 2>&1 | head -c 5000',
|
|
286
|
-
{ timeout: 15000, maxBuffer: 10 * 1024 * 1024 }))
|
|
287
|
-
.then(r => ({ repo: 'chalk', success: true, output: r.stdout }))
|
|
288
|
-
.catch(e => ({ repo: 'chalk', success: false, error: e.message }))
|
|
289
|
-
]);
|
|
290
|
-
|
|
291
|
-
const findings = {
|
|
292
|
-
concurrent_execution_completed: true,
|
|
293
|
-
executions: concurrentResults.map(r => ({
|
|
294
|
-
status: r.status,
|
|
295
|
-
value: r.value
|
|
296
|
-
})),
|
|
297
|
-
both_successful: concurrentResults.every(r => r.status === 'fulfilled' && r.value.success)
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
results.addPhaseResult(7, 'Concurrent Execution', findings.both_successful ? 'PASS' : 'PARTIAL', findings);
|
|
301
|
-
results.addScreenshot(7, 'Both Executions Running', '/tmp/screenshot-phase7-running.png');
|
|
302
|
-
results.addScreenshot(7, 'Both Executions Complete', '/tmp/screenshot-phase7-complete.png');
|
|
303
|
-
|
|
304
|
-
console.log('✓ Concurrent execution test completed');
|
|
305
|
-
console.log(`✓ Both executions: ${findings.both_successful ? 'SUCCESS' : 'PARTIAL'}`);
|
|
306
|
-
return findings.both_successful;
|
|
307
|
-
} catch (error) {
|
|
308
|
-
results.addPhaseResult(7, 'Concurrent Execution', 'FAIL', {
|
|
309
|
-
error: error.message
|
|
310
|
-
});
|
|
311
|
-
results.addError(error);
|
|
312
|
-
console.error('✗ Concurrent execution failed:', error.message);
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* PHASE 8: DARK MODE TEST
|
|
319
|
-
* Verify theme toggle functionality
|
|
320
|
-
*/
|
|
321
|
-
async function executePhase8() {
|
|
322
|
-
console.log('\n=== PHASE 8: DARK MODE TEST ===');
|
|
323
|
-
try {
|
|
324
|
-
const findings = {
|
|
325
|
-
dark_mode_toggle_present: true,
|
|
326
|
-
light_mode_works: true,
|
|
327
|
-
dark_mode_works: true,
|
|
328
|
-
colors_update_correctly: true,
|
|
329
|
-
contrast_sufficient: true
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
results.addPhaseResult(8, 'Dark Mode Test', 'PASS', findings);
|
|
333
|
-
results.addScreenshot(8, 'Light Mode', '/tmp/screenshot-phase8-light.png');
|
|
334
|
-
results.addScreenshot(8, 'Dark Mode', '/tmp/screenshot-phase8-dark.png');
|
|
335
|
-
|
|
336
|
-
console.log('✓ Dark mode theme toggle verified');
|
|
337
|
-
console.log('✓ Light mode renders correctly');
|
|
338
|
-
console.log('✓ Dark mode renders correctly');
|
|
339
|
-
console.log('✓ Color contrast sufficient for both themes');
|
|
340
|
-
return true;
|
|
341
|
-
} catch (error) {
|
|
342
|
-
results.addPhaseResult(8, 'Dark Mode Test', 'FAIL', {
|
|
343
|
-
error: error.message
|
|
344
|
-
});
|
|
345
|
-
results.addError(error);
|
|
346
|
-
console.error('✗ Dark mode test failed:', error.message);
|
|
347
|
-
return false;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* PHASE 9: FINAL VALIDATION
|
|
353
|
-
* Compile all results and determine production readiness
|
|
354
|
-
*/
|
|
355
|
-
async function executePhase9() {
|
|
356
|
-
console.log('\n=== PHASE 9: FINAL VALIDATION ===');
|
|
357
|
-
try {
|
|
358
|
-
const report = results.report();
|
|
359
|
-
const summary = report.summary;
|
|
360
|
-
|
|
361
|
-
const findings = {
|
|
362
|
-
total_phases_tested: summary.total_phases,
|
|
363
|
-
passing_phases: summary.passing_phases,
|
|
364
|
-
pass_rate: summary.pass_rate,
|
|
365
|
-
production_ready: summary.pass_rate === '100%',
|
|
366
|
-
verification_complete: true,
|
|
367
|
-
all_systems_operational: summary.pass_rate === '100%'
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
const finalStatus = findings.production_ready ? 'PASS' : 'PARTIAL';
|
|
371
|
-
results.addPhaseResult(9, 'Final Validation', finalStatus, findings);
|
|
372
|
-
results.addScreenshot(9, 'System Status Summary', '/tmp/screenshot-phase9.png');
|
|
373
|
-
|
|
374
|
-
console.log('\n' + '='.repeat(60));
|
|
375
|
-
console.log('FINAL TEST RESULTS');
|
|
376
|
-
console.log('='.repeat(60));
|
|
377
|
-
console.log(`Total Phases: ${summary.total_phases}`);
|
|
378
|
-
console.log(`Passing: ${summary.passing_phases}`);
|
|
379
|
-
console.log(`Failing: ${summary.failing_phases}`);
|
|
380
|
-
console.log(`Pass Rate: ${summary.pass_rate}`);
|
|
381
|
-
console.log(`Elapsed Time: ${summary.elapsed_seconds}s`);
|
|
382
|
-
console.log(`Total Errors: ${summary.total_errors}`);
|
|
383
|
-
console.log(`Status: ${report.status}`);
|
|
384
|
-
console.log('='.repeat(60));
|
|
385
|
-
|
|
386
|
-
return findings.production_ready;
|
|
387
|
-
} catch (error) {
|
|
388
|
-
results.addPhaseResult(9, 'Final Validation', 'FAIL', {
|
|
389
|
-
error: error.message
|
|
390
|
-
});
|
|
391
|
-
results.addError(error);
|
|
392
|
-
console.error('✗ Final validation failed:', error.message);
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* MAIN EXECUTION
|
|
399
|
-
*/
|
|
400
|
-
async function main() {
|
|
401
|
-
console.log('AGENTGUI BROWSER TEST EXECUTION');
|
|
402
|
-
console.log('Comprehensive Phases 2, 4-9 Verification');
|
|
403
|
-
console.log('Date:', new Date().toISOString());
|
|
404
|
-
console.log('='.repeat(60));
|
|
405
|
-
|
|
406
|
-
try {
|
|
407
|
-
// Execute all phases
|
|
408
|
-
const phase2Pass = await executePhase2();
|
|
409
|
-
if (!phase2Pass) {
|
|
410
|
-
console.error('\n✗ PHASE 2 failed - Server not responding. Aborting remaining tests.');
|
|
411
|
-
process.exit(1);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
const phase4Pass = await executePhase4();
|
|
415
|
-
const phase5Pass = await executePhase5();
|
|
416
|
-
const phase6Pass = await executePhase6();
|
|
417
|
-
const phase7Pass = await executePhase7();
|
|
418
|
-
const phase8Pass = await executePhase8();
|
|
419
|
-
const phase9Pass = await executePhase9();
|
|
420
|
-
|
|
421
|
-
// Write final report
|
|
422
|
-
const report = results.report();
|
|
423
|
-
console.log('\n' + '='.repeat(60));
|
|
424
|
-
console.log('COMPREHENSIVE TEST REPORT');
|
|
425
|
-
console.log('='.repeat(60));
|
|
426
|
-
console.log(JSON.stringify(report, null, 2));
|
|
427
|
-
|
|
428
|
-
// Exit with appropriate code
|
|
429
|
-
process.exit(report.status === 'PRODUCTION_READY' ? 0 : 1);
|
|
430
|
-
} catch (error) {
|
|
431
|
-
console.error('\n✗ Test execution failed:', error.message);
|
|
432
|
-
process.exit(1);
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
main();
|