@@ -73,6 +73,7 @@ let isEarlyFlakeDetectionFaulty = false
73
73
let isFlakyTestRetriesEnabled = false
74
74
let isKnownTestsEnabled = false
75
75
let isTestManagementTestsEnabled = false
76
+ let testManagementAttemptToFixRetries = 0
76
77
let testManagementTests = { }
77
78
let numTestRetries = 0
78
79
let knownTests = [ ]
@@ -121,10 +122,10 @@ function isNewTest (testSuite, testName) {
121
122
}
122
123
123
124
function getTestProperties ( testSuite , testName ) {
124
- const { disabled, quarantined } =
125
+ const { attempt_to_fix : attemptToFix , disabled, quarantined } =
125
126
testManagementTests ?. cucumber ?. suites ?. [ testSuite ] ?. tests ?. [ testName ] ?. properties || { }
126
127
127
- return { disabled, quarantined }
128
+ return { attemptToFix , disabled, quarantined }
128
129
}
129
130
130
131
function getTestStatusFromRetries ( testStatuses ) {
@@ -303,22 +304,46 @@ function wrapRun (pl, isLatestVersion) {
303
304
}
304
305
let isNew = false
305
306
let isEfdRetry = false
307
+ let isAttemptToFix = false
308
+ let isAttemptToFixRetry = false
309
+ let hasFailedAllRetries = false
310
+ let hasPassedAllRetries = false
306
311
let isDisabled = false
307
312
let isQuarantined = false
308
- if ( isKnownTestsEnabled && status !== 'skip' ) {
309
- const numRetries = numRetriesByPickleId . get ( this . pickle . id )
310
-
311
- isNew = numRetries !== undefined
312
- isEfdRetry = numRetries > 0
313
- }
314
313
if ( isTestManagementTestsEnabled ) {
315
314
const testSuitePath = getTestSuitePath ( testFileAbsolutePath , process . cwd ( ) )
316
315
const testProperties = getTestProperties ( testSuitePath , this . pickle . name )
317
- isDisabled = testProperties . disabled
318
- if ( ! isDisabled ) {
319
- isQuarantined = testProperties . quarantined
316
+ const numRetries = numRetriesByPickleId . get ( this . pickle . id )
317
+ isAttemptToFix = testProperties . attemptToFix
318
+ isAttemptToFixRetry = isAttemptToFix && numRetries > 0
319
+ if ( ! isAttemptToFix ) {
320
+ isDisabled = testProperties . disabled
321
+ if ( ! isDisabled ) {
322
+ isQuarantined = testProperties . quarantined
323
+ }
324
+ }
325
+
326
+ if ( isAttemptToFixRetry ) {
327
+ const statuses = lastStatusByPickleId . get ( this . pickle . id )
328
+ if ( statuses . length === testManagementAttemptToFixRetries + 1 ) {
329
+ // The first status is the original test status
330
+ const statusesExceptFirst = statuses . slice ( 1 )
331
+ const { pass, fail } = statusesExceptFirst . reduce ( ( acc , status ) => {
332
+ acc [ status ] ++
333
+ return acc
334
+ } , { pass : 0 , fail : 0 } )
335
+ hasFailedAllRetries = fail === testManagementAttemptToFixRetries
336
+ hasPassedAllRetries = pass === testManagementAttemptToFixRetries
337
+ }
320
338
}
321
339
}
340
+
341
+ if ( isKnownTestsEnabled && status !== 'skip' && ! isAttemptToFix ) {
342
+ const numRetries = numRetriesByPickleId . get ( this . pickle . id )
343
+
344
+ isNew = numRetries !== undefined
345
+ isEfdRetry = numRetries > 0
346
+ }
322
347
const attemptAsyncResource = numAttemptToAsyncResource . get ( numAttempt )
323
348
324
349
const error = getErrorFromCucumberResult ( result )
@@ -334,6 +359,9 @@ function wrapRun (pl, isLatestVersion) {
334
359
isNew,
335
360
isEfdRetry,
336
361
isFlakyRetry : numAttempt > 0 ,
362
+ isAttemptToFixRetry,
363
+ hasFailedAllRetries,
364
+ hasPassedAllRetries,
337
365
isDisabled,
338
366
isQuarantined
339
367
} )
@@ -426,6 +454,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
426
454
numTestRetries = configurationResponse . libraryConfig ?. flakyTestRetriesCount
427
455
isKnownTestsEnabled = configurationResponse . libraryConfig ?. isKnownTestsEnabled
428
456
isTestManagementTestsEnabled = configurationResponse . libraryConfig ?. isTestManagementEnabled
457
+ testManagementAttemptToFixRetries = configurationResponse . libraryConfig ?. testManagementAttemptToFixRetries
429
458
430
459
if ( isKnownTestsEnabled ) {
431
460
const knownTestsResponse = await getChannelPromise ( knownTestsCh )
@@ -576,29 +605,42 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
576
605
}
577
606
578
607
let isNew = false
608
+ let isAttemptToFix = false
579
609
let isDisabled = false
580
610
let isQuarantined = false
581
611
582
- if ( isKnownTestsEnabled ) {
612
+ if ( isTestManagementTestsEnabled ) {
613
+ const testProperties = getTestProperties ( testSuitePath , pickle . name )
614
+ isAttemptToFix = testProperties . attemptToFix
615
+ if ( ! isAttemptToFix ) {
616
+ isDisabled = testProperties . disabled
617
+ if ( isDisabled ) {
618
+ this . options . dryRun = true
619
+ } else {
620
+ isQuarantined = testProperties . quarantined
621
+ }
622
+ }
623
+ }
624
+
625
+ if ( isKnownTestsEnabled && ! isAttemptToFix ) {
583
626
isNew = isNewTest ( testSuitePath , pickle . name )
584
627
if ( isNew ) {
585
628
numRetriesByPickleId . set ( pickle . id , 0 )
586
629
}
587
630
}
588
- if ( isTestManagementTestsEnabled ) {
589
- const testProperties = getTestProperties ( testSuitePath , pickle . name )
590
- isDisabled = testProperties . disabled
591
- if ( isDisabled ) {
592
- this . options . dryRun = true
593
- } else {
594
- isQuarantined = testProperties . quarantined
595
- }
596
- }
597
631
// TODO: for >=11 we could use `runTestCaseResult` instead of accumulating results in `lastStatusByPickleId`
598
632
let runTestCaseResult = await runTestCaseFunction . apply ( this , arguments )
599
633
600
634
const testStatuses = lastStatusByPickleId . get ( pickle . id )
601
635
const lastTestStatus = testStatuses [ testStatuses . length - 1 ]
636
+
637
+ if ( isAttemptToFix && lastTestStatus !== 'skip' ) {
638
+ for ( let retryIndex = 0 ; retryIndex < testManagementAttemptToFixRetries ; retryIndex ++ ) {
639
+ numRetriesByPickleId . set ( pickle . id , retryIndex + 1 )
640
+ runTestCaseResult = await runTestCaseFunction . apply ( this , arguments )
641
+ }
642
+ }
643
+
602
644
// If it's a new test and it hasn't been skipped, we run it again
603
645
if ( isEarlyFlakeDetectionEnabled && lastTestStatus !== 'skip' && isNew ) {
604
646
for ( let retryIndex = 0 ; retryIndex < earlyFlakeDetectionNumRetries ; retryIndex ++ ) {
@@ -609,6 +651,7 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
609
651
let testStatus = lastTestStatus
610
652
let shouldBePassedByEFD = false
611
653
let shouldBePassedByQuarantine = false
654
+ let shouldBePassedByAttemptToFix = false
612
655
if ( isNew && isEarlyFlakeDetectionEnabled ) {
613
656
/**
614
657
* If Early Flake Detection (EFD) is enabled the logic is as follows:
@@ -625,9 +668,17 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
625
668
}
626
669
}
627
670
628
- if ( isTestManagementTestsEnabled && isQuarantined ) {
629
- this . success = true
630
- shouldBePassedByQuarantine = true
671
+ if ( isTestManagementTestsEnabled ) {
672
+ if ( isAttemptToFix ) {
673
+ const testProperties = getTestProperties ( testSuitePath , pickle . name )
674
+ if ( testProperties . disabled || testProperties . quarantined ) {
675
+ this . success = true
676
+ shouldBePassedByAttemptToFix = true
677
+ }
678
+ } else if ( isQuarantined ) {
679
+ this . success = true
680
+ shouldBePassedByQuarantine = true
681
+ }
631
682
}
632
683
633
684
if ( ! pickleResultByFile [ testFileAbsolutePath ] ) {
@@ -661,8 +712,8 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
661
712
return shouldBePassedByEFD
662
713
}
663
714
664
- if ( isNewerCucumberVersion && isTestManagementTestsEnabled && isQuarantined ) {
665
- return shouldBePassedByQuarantine
715
+ if ( isNewerCucumberVersion && isTestManagementTestsEnabled && ( isQuarantined || isAttemptToFix ) ) {
716
+ return shouldBePassedByQuarantine || shouldBePassedByAttemptToFix
666
717
}
667
718
668
719
return runTestCaseResult
0 commit comments