Skip to content

Commit da82da4

Browse files
Copilotquanru
andcommitted
feat(cli): add resultType to categorize execution results
- Added 'resultType' field to MidsceneYamlConfigResult to distinguish between: - 'success': All tasks completed successfully - 'failed': Complete execution failure (player error) - 'partialFailed': Some tasks failed with continueOnError=true - 'notExecuted': Not executed due to previous failures - Updated BatchRunner to track and display partial failures separately - Added 'Partial failed' count to execution summary - Updated tests to verify correct categorization This provides better visibility into what actually happened during execution, distinguishing between complete failures and partial failures where tasks failed but execution continued due to continueOnError setting. Co-authored-by: quanru <[email protected]>
1 parent 4f8b7ee commit da82da4

File tree

3 files changed

+99
-27
lines changed

3 files changed

+99
-27
lines changed

packages/cli/src/batch-runner.ts

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,28 @@ class BatchRunner {
355355

356356
for (const context of executedContexts) {
357357
const { file, player, duration } = context;
358-
// A file is successful only if:
359-
// 1. Player status is not 'error', AND
360-
// 2. No individual tasks have failed status
358+
// Determine result type based on player and task statuses
361359
const hasFailedTasks =
362360
player.taskStatusList?.some((task) => task.status === 'error') ?? false;
363-
const success = player.status !== 'error' && !hasFailedTasks;
361+
const hasPlayerError = player.status === 'error';
362+
363+
let success: boolean;
364+
let resultType: 'success' | 'failed' | 'partialFailed';
365+
366+
if (hasPlayerError) {
367+
// Complete failure - player itself failed
368+
success = false;
369+
resultType = 'failed';
370+
} else if (hasFailedTasks) {
371+
// Partial failure - some tasks failed but execution continued (continueOnError)
372+
success = false;
373+
resultType = 'partialFailed';
374+
} else {
375+
// Success - all tasks completed successfully
376+
success = true;
377+
resultType = 'success';
378+
}
379+
364380
let reportFile: string | undefined;
365381

366382
if (player.reportFile) {
@@ -380,9 +396,10 @@ class BatchRunner {
380396
output: outputPath,
381397
report: reportFile,
382398
duration,
399+
resultType,
383400
error:
384401
player.errorInSetup?.message ||
385-
(player.status === 'error' ? 'Execution failed' : undefined) ||
402+
(hasPlayerError ? 'Execution failed' : undefined) ||
386403
(hasFailedTasks ? 'Some tasks failed' : undefined),
387404
});
388405
}
@@ -395,6 +412,7 @@ class BatchRunner {
395412
output: undefined,
396413
report: undefined,
397414
duration: 0,
415+
resultType: 'notExecuted',
398416
error: 'Not executed (previous task failed)',
399417
});
400418
}
@@ -441,8 +459,15 @@ class BatchRunner {
441459
const indexData = {
442460
summary: {
443461
total: this.results.length,
444-
successful: this.results.filter((r) => r.success).length,
445-
failed: this.results.filter((r) => !r.success).length,
462+
successful: this.results.filter((r) => r.resultType === 'success')
463+
.length,
464+
failed: this.results.filter((r) => r.resultType === 'failed').length,
465+
partialFailed: this.results.filter(
466+
(r) => r.resultType === 'partialFailed',
467+
).length,
468+
notExecuted: this.results.filter(
469+
(r) => r.resultType === 'notExecuted',
470+
).length,
446471
totalDuration: this.results.reduce(
447472
(sum, r) => sum + (r.duration || 0),
448473
0,
@@ -452,6 +477,7 @@ class BatchRunner {
452477
results: this.results.map((result) => ({
453478
script: relative(outputDir, result.file),
454479
success: result.success,
480+
resultType: result.resultType,
455481
output: result.output
456482
? (() => {
457483
const relativePath = relative(outputDir, result.output);
@@ -479,17 +505,26 @@ class BatchRunner {
479505
total: number;
480506
successful: number;
481507
failed: number;
508+
partialFailed: number;
482509
notExecuted: number;
483510
totalDuration: number;
484511
} {
485-
const successful = this.results.filter((r) => r.success).length;
486-
const notExecuted = this.results.filter((r) => !r.executed).length;
487-
const failed = this.results.filter((r) => r.executed && !r.success).length;
512+
const successful = this.results.filter(
513+
(r) => r.resultType === 'success',
514+
).length;
515+
const failed = this.results.filter((r) => r.resultType === 'failed').length;
516+
const partialFailed = this.results.filter(
517+
(r) => r.resultType === 'partialFailed',
518+
).length;
519+
const notExecuted = this.results.filter(
520+
(r) => r.resultType === 'notExecuted',
521+
).length;
488522

489523
return {
490524
total: this.results.length,
491525
successful,
492526
failed,
527+
partialFailed,
493528
notExecuted,
494529
totalDuration: this.results.reduce(
495530
(sum, r) => sum + (r.duration || 0),
@@ -500,16 +535,26 @@ class BatchRunner {
500535

501536
getFailedFiles(): string[] {
502537
return this.results
503-
.filter((r) => r.executed && !r.success)
538+
.filter((r) => r.resultType === 'failed')
539+
.map((r) => r.file);
540+
}
541+
542+
getPartialFailedFiles(): string[] {
543+
return this.results
544+
.filter((r) => r.resultType === 'partialFailed')
504545
.map((r) => r.file);
505546
}
506547

507548
getNotExecutedFiles(): string[] {
508-
return this.results.filter((r) => !r.executed).map((r) => r.file);
549+
return this.results
550+
.filter((r) => r.resultType === 'notExecuted')
551+
.map((r) => r.file);
509552
}
510553

511554
getSuccessfulFiles(): string[] {
512-
return this.results.filter((r) => r.success).map((r) => r.file);
555+
return this.results
556+
.filter((r) => r.resultType === 'success')
557+
.map((r) => r.file);
513558
}
514559

515560
getResults(): MidsceneYamlConfigResult[] {
@@ -518,12 +563,16 @@ class BatchRunner {
518563

519564
printExecutionSummary(): boolean {
520565
const summary = this.getExecutionSummary();
521-
const success = summary.failed === 0 && summary.notExecuted === 0;
566+
const success =
567+
summary.failed === 0 &&
568+
summary.partialFailed === 0 &&
569+
summary.notExecuted === 0;
522570

523571
console.log('\n📊 Execution Summary:');
524572
console.log(` Total files: ${summary.total}`);
525573
console.log(` Successful: ${summary.successful}`);
526574
console.log(` Failed: ${summary.failed}`);
575+
console.log(` Partial failed: ${summary.partialFailed}`);
527576
console.log(` Not executed: ${summary.notExecuted}`);
528577
console.log(` Duration: ${(summary.totalDuration / 1000).toFixed(2)}s`);
529578
console.log(` Summary: ${this.getSummaryAbsolutePath()}`);
@@ -542,6 +591,15 @@ class BatchRunner {
542591
});
543592
}
544593

594+
if (summary.partialFailed > 0) {
595+
console.log(
596+
'\n⚠️ Partial failed files (some tasks failed with continueOnError)',
597+
);
598+
this.getPartialFailedFiles().forEach((file) => {
599+
console.log(` ${file}`);
600+
});
601+
}
602+
545603
if (summary.notExecuted > 0) {
546604
console.log('\n⏸️ Not executed files');
547605
this.getNotExecutedFiles().forEach((file) => {

packages/cli/tests/unit-test/batch-runner.test.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ describe('BatchRunner', () => {
372372

373373
test('continueOnError: failed tasks should be counted as failed files', async () => {
374374
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
375-
375+
376376
// Create a mock player that simulates continueOnError behavior:
377377
// - player.status = 'done' (execution completed)
378378
// - but taskStatusList contains failed tasks
@@ -386,10 +386,15 @@ describe('BatchRunner', () => {
386386
reportFile: '/test/report.html',
387387
result: { test: 'data' },
388388
errorInSetup: null,
389-
taskStatusList: isFile1
389+
taskStatusList: isFile1
390390
? [
391-
{ status: 'error', error: new Error('Assertion failed: this is not a search engine') },
392-
{ status: 'done' }
391+
{
392+
status: 'error',
393+
error: new Error(
394+
'Assertion failed: this is not a search engine',
395+
),
396+
},
397+
{ status: 'done' },
393398
]
394399
: [{ status: 'done' }],
395400
run: vi.fn().mockImplementation(async () => {
@@ -408,22 +413,23 @@ describe('BatchRunner', () => {
408413
vi.mocked(createYamlPlayer).mockImplementation(async (file) =>
409414
createMockPlayerWithFailedTasks(file),
410415
);
411-
416+
412417
const config = { ...mockBatchConfig, continueOnError: true };
413418
const executor = new BatchRunner(config);
414419
await executor.run();
415-
420+
416421
const summary = executor.getExecutionSummary();
417422
const success = executor.printExecutionSummary();
418-
419-
// This currently fails - demonstrates the bug
420-
// Should show 1 failed file, but currently shows 0
421-
expect(summary.failed).toBe(1); // This test will fail, showing the bug
422-
expect(success).toBe(false);
423+
424+
// Files with failed tasks and continueOnError should be counted as partialFailed
425+
expect(summary.partialFailed).toBe(1);
426+
expect(summary.failed).toBe(0); // No complete failures
427+
expect(summary.successful).toBe(2); // The other two files succeeded
428+
expect(success).toBe(false); // Overall should still be false due to partial failure
423429
expect(consoleSpy).toHaveBeenCalledWith(
424-
expect.stringContaining('❌ Failed files'),
430+
expect.stringContaining('⚠️ Partial failed files'),
425431
);
426-
432+
427433
consoleSpy.mockRestore();
428434
});
429435
});

packages/core/src/yaml.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,4 +235,12 @@ export interface MidsceneYamlConfigResult {
235235
report?: string | null;
236236
error?: string;
237237
duration?: number;
238+
/**
239+
* Type of result:
240+
* - 'success': All tasks completed successfully
241+
* - 'failed': Execution failed (player error)
242+
* - 'partialFailed': Some tasks failed but execution continued (continueOnError)
243+
* - 'notExecuted': Not executed due to previous failures
244+
*/
245+
resultType?: 'success' | 'failed' | 'partialFailed' | 'notExecuted';
238246
}

0 commit comments

Comments
 (0)