diff --git a/packages/core/src/process/4-mutation-test-executor.ts b/packages/core/src/process/4-mutation-test-executor.ts index b186667149..2f0a98c26b 100644 --- a/packages/core/src/process/4-mutation-test-executor.ts +++ b/packages/core/src/process/4-mutation-test-executor.ts @@ -126,7 +126,10 @@ export class MutationTestExecutor { let passedMutant$ = input$; for (const checkerName of this.options.checkers) { // Use this checker - const [checkFailedResult$, checkPassedResult$] = partition(this.executeSingleChecker(checkerName, passedMutant$), isEarlyResult); + const [checkFailedResult$, checkPassedResult$] = partition( + this.executeSingleChecker(checkerName, passedMutant$).pipe(shareReplay()), + isEarlyResult + ); // Prepare for the next one passedMutant$ = checkPassedResult$; @@ -159,7 +162,6 @@ export class MutationTestExecutor { .schedule(group$, (checker, group) => checker.check(checkerName, group)) .pipe( mergeMap((mutantGroupResults) => mutantGroupResults), - shareReplay(), map(([mutantRunPlan, checkResult]) => checkResult.status === CheckStatus.Passed ? mutantRunPlan diff --git a/packages/core/test/unit/process/4-mutation-test-executor.spec.ts b/packages/core/test/unit/process/4-mutation-test-executor.spec.ts index 19c2a5f1ec..df2882e1e0 100644 --- a/packages/core/test/unit/process/4-mutation-test-executor.spec.ts +++ b/packages/core/test/unit/process/4-mutation-test-executor.spec.ts @@ -282,6 +282,25 @@ describe(MutationTestExecutor.name, () => { sinon.assert.calledWithExactly(checker.check, 'foo', [plan2]); }); + it('should report failed check mutants only once (#3461)', async () => { + // Arrange + const plan1 = mutantRunPlan({ id: '1' }); + const plan2 = mutantRunPlan({ id: '2' }); + const failedCheckResult = factory.failedCheckResult(); + arrangeScenario({ checkResult: failedCheckResult }); + checker.group.resolves([[plan1], [plan2]]); + mutantTestPlans.push(plan1); + mutantTestPlans.push(plan2); + + // Act + await sut.execute(); + + // Assert + expect(mutationTestReportHelperMock.reportCheckFailed).calledTwice; + sinon.assert.calledWithExactly(mutationTestReportHelperMock.reportCheckFailed, plan1.mutant, failedCheckResult); + sinon.assert.calledWithExactly(mutationTestReportHelperMock.reportCheckFailed, plan1.mutant, failedCheckResult); + }); + it('should free checker resources after checking stage is complete', async () => { // Arrange const plan = mutantRunPlan({ id: '1' });