@@ -335,7 +335,7 @@ class TestContext {
335335 const assert = { __proto__ : null } ;
336336 // Each assertion counts against an active `t.plan()`. A flaky test re-arms
337337 // `test.plan` on every retry, so it must be read live (deferred to call
338- // time). A non-flaky test counts against the plan captured once here, at
338+ // time). A non-flaky test counts against the plan captured here once , at
339339 // first `.assert` access: this preserves the historical behavior that a
340340 // `t.plan()` called *after* the first assertion is not retroactively
341341 // counted (see test-runner/flaky/assert-before-plan). The flaky-vs-captured
@@ -753,11 +753,12 @@ class Test extends AsyncResource {
753753 this . plan = null ;
754754 this . expectedAssertions = plan ;
755755 this . cancelled = false ;
756- if ( flaky === undefined || flaky === null ) {
757- // Inherit flaky only from a suite parent: a suite propagates it to its
756+ if ( flaky == null ) {
757+ // Inherit flaky only from a suite parent: a suite propagates to its
758758 // test-cases, but a test must not propagate it to its own subtests.
759759 this . flakyRetries = this . parent ?. reportedType === 'suite' ?
760- ( this . parent . flakyRetries ?? 0 ) : 0 ;
760+ ( this . parent . flakyRetries ?? 0 ) :
761+ 0 ;
761762 } else if ( typeof flaky === 'boolean' ) {
762763 this . flakyRetries = flaky ? kDefaultFlakyRetries : 0 ;
763764 } else if ( typeof flaky === 'number' ) {
@@ -1322,12 +1323,17 @@ class Test extends AsyncResource {
13221323 this . report = noop ;
13231324 queueMicrotask ( ( ) => this . postRun ( ) ) ;
13241325 }
1325- // Reset per-attempt state before retrying a flaky test. Anything that would
1326- // otherwise leak between attempts is cleared here so the retry starts from a
1327- // clean slate. `before`/`after` (suite-once) and the accumulated parent hooks
1328- // are intentionally left untouched. `baseDiagnosticsCount` is the diagnostics
1329- // length captured before the first attempt, so diagnostics emitted during
1330- // construction survive while a previous attempt's are discarded.
1326+ /**
1327+ * Reset per-attempt state before retrying a flaky test. Anything that would
1328+ * otherwise leak between attempts is cleared here so the retry starts from a
1329+ * clean slate. `before`/`after` (suite-once) and the accumulated parent hooks
1330+ * are intentionally left untouched. `baseDiagnosticsCount` is the diagnostics
1331+ * length captured before the first attempt, so diagnostics emitted during
1332+ * construction survive while a previous attempt's are discarded.
1333+ * @param {TestContext } ctx
1334+ * @param {number } baseDiagnosticsCount
1335+ * @param {{ beforeEach: number, ownAfterEachCount: number } } baseHookCounts
1336+ */
13311337 #resetForRetry( ctx , baseDiagnosticsCount , baseHookCounts ) {
13321338 this . error = null ;
13331339 this . passed = false ;
@@ -1339,11 +1345,11 @@ class Test extends AsyncResource {
13391345 // Reset assertion bookkeeping; re-arm the plan if one was requested via the
13401346 // `plan` option so that `t.plan(N)` does not accumulate across attempts.
13411347 this . plan = null ;
1342- if ( this . expectedAssertions ) {
1348+ if ( this . expectedAssertions != null ) {
13431349 ctx . plan ( this . expectedAssertions ) ;
13441350 }
1345- // Drop subtests created by the previous attempt so they are not double
1346- // counted or double reported. outputSubtestCount must be reset too:
1351+ // Drop subtests created by the previous attempt so they are not double-
1352+ // counted or double- reported. ` outputSubtestCount` must be reset too:
13471353 // otherwise it accumulates across attempts while `subtests` holds only the
13481354 // final attempt's children, inflating the plan count and - when the final
13491355 // attempt creates no subtest - leaving outputSubtestCount > 0 with an empty
@@ -1364,8 +1370,11 @@ class Test extends AsyncResource {
13641370 // The re-executing body re-registers its per-attempt hooks; before/after
13651371 // are kept (runOnce, and an earlier attempt's teardown must survive).
13661372 ArrayPrototypeSplice ( this . hooks . beforeEach , baseHookCounts . beforeEach ) ;
1367- ArrayPrototypeSplice ( this . hooks . afterEach , baseHookCounts . ownAfterEachCount ,
1368- this . hooks . ownAfterEachCount - baseHookCounts . ownAfterEachCount ) ;
1373+ ArrayPrototypeSplice (
1374+ this . hooks . afterEach ,
1375+ baseHookCounts . ownAfterEachCount ,
1376+ ( this . hooks . ownAfterEachCount - baseHookCounts . ownAfterEachCount ) ,
1377+ ) ;
13691378 this . hooks . ownAfterEachCount = baseHookCounts . ownAfterEachCount ;
13701379 // Abort the previous attempt's controller so any signal-bound work it
13711380 // started (e.g. a timer awaiting t.signal) is torn down instead of leaking.
@@ -1377,13 +1386,20 @@ class Test extends AsyncResource {
13771386 this . abortController = new AbortController ( ) ;
13781387 this . signal = this . abortController . signal ;
13791388 }
1380- // The retry-eligibility terms shared by the catch-path `willRetry` gate and
1381- // the loop's `shouldRetry` decision. Kept in one place so a future stop
1382- // condition cannot be added to one site and forgotten at the other.
1389+ /**
1390+ * The retry-eligibility terms shared by the catch-path `willRetry` gate and
1391+ * the loop's `shouldRetry` decision. Kept in one place so a future stop
1392+ * condition cannot be added to one site and forgotten at the other.
1393+ * @param {number } attempt
1394+ * @param {number } maxAttempts
1395+ * @returns {boolean }
1396+ */
13831397 #retriesRemaining( attempt , maxAttempts ) {
1384- return attempt < maxAttempts &&
1398+ return (
1399+ attempt < maxAttempts &&
13851400 ! this . expectFailure &&
1386- ! ( this . signal . aborted || this . outerSignal ?. aborted ) ;
1401+ ! ( this . signal . aborted || this . outerSignal ?. aborted )
1402+ ) ;
13871403 }
13881404
13891405 async run ( ) {
@@ -1436,7 +1452,11 @@ class Test extends AsyncResource {
14361452 let afterEach = makeAfterEach ( ) ;
14371453 let stopPromise ;
14381454 const basePublishEnd = ( ) => testChannel . end . publish ( channelContext ) ;
1439- const basePublishError = ( err ) => testChannel . error . publish ( { __proto__ : null , ...channelContext , error : err } ) ;
1455+ const basePublishError = ( err ) => testChannel . error . publish ( {
1456+ __proto__ : null ,
1457+ ...channelContext ,
1458+ error : err ,
1459+ } ) ;
14401460 let publishEnd = basePublishEnd ;
14411461 let publishError = basePublishError ;
14421462
@@ -1447,11 +1467,13 @@ class Test extends AsyncResource {
14471467 const maxAttempts = this . flakyRetries + 1 ;
14481468 const baseDiagnosticsCount = this . diagnostics . length ;
14491469 // Baseline for #resetForRetry to truncate body-registered hooks back to.
1450- const baseHookCounts = this . isFlaky ? {
1451- __proto__ : null ,
1452- beforeEach : this . hooks . beforeEach . length ,
1453- ownAfterEachCount : this . hooks . ownAfterEachCount ,
1454- } : null ;
1470+ const baseHookCounts = this . isFlaky ?
1471+ {
1472+ __proto__ : null ,
1473+ beforeEach : this . hooks . beforeEach . length ,
1474+ ownAfterEachCount : this . hooks . ownAfterEachCount ,
1475+ } :
1476+ null ;
14551477
14561478 for ( let attempt = 1 ; attempt <= maxAttempts ; attempt ++ ) {
14571479 if ( attempt > 1 ) {
@@ -1481,16 +1503,15 @@ class Test extends AsyncResource {
14811503 // the test runs within both the runStores context (for AsyncLocalStorage/bindStore)
14821504 // AND the AsyncResource scope. It's critical that runStores wraps the function,
14831505 // not the runInAsyncScope call itself, to maintain AsyncLocalStorage bindings.
1484- let testFn = this . fn ;
1485- if ( channelContext !== null && testChannel . start . hasSubscribers ) {
1486- testFn = ( ...fnArgs ) => testChannel . start . runStores ( channelContext , ( ) => {
1506+ const testFn = ( channelContext !== null && testChannel . start . hasSubscribers ) ?
1507+ ( ...fnArgs ) => testChannel . start . runStores ( channelContext , ( ) => {
14871508 // Rebind from the base each attempt; binding on top of the
14881509 // previous binding would pin the first attempt's async context.
14891510 publishEnd = AsyncResource . bind ( basePublishEnd ) ;
14901511 publishError = AsyncResource . bind ( basePublishError ) ;
14911512 return ReflectApply ( this . fn , this , fnArgs ) ;
1492- } ) ;
1493- }
1513+ } ) :
1514+ this . fn ;
14941515
14951516 ArrayPrototypeUnshift ( runArgs , testFn , ctx ) ;
14961517
@@ -1541,20 +1562,26 @@ class Test extends AsyncResource {
15411562 await afterEach ( ) ;
15421563 // Keep `after` for the final attempt: a failed subtest is about to
15431564 // trigger a retry, which must not run against torn-down state.
1544- const subtestRetryPending =
1565+ const subtestRetryPending = (
15451566 this . #retriesRemaining( attempt , maxAttempts ) &&
1546- ArrayPrototypeSome ( this . subtests ,
1547- ( subtest ) => ! subtest . passed && ! subtest . isTodo ) ;
1567+ ArrayPrototypeSome (
1568+ this . subtests ,
1569+ ( subtest ) => ! subtest . passed && ! subtest . isTodo ,
1570+ )
1571+ ) ;
15481572 if ( ! subtestRetryPending ) {
15491573 await after ( ) ;
15501574 }
15511575 } catch ( err ) {
15521576 attemptError = err ;
15531577 if ( isTestFailureError ( err ) ) {
1554- if ( err . failureType === kTestTimeoutFailure &&
1555- ( ! this . isFlaky || this . expectFailure ) ) {
1556- // expectFailure never retries, so its timeout keeps the non-flaky
1557- // cancellation semantics instead of becoming an expected failure.
1578+ if (
1579+ err . failureType === kTestTimeoutFailure &&
1580+ ( ! this . isFlaky || this . expectFailure )
1581+ ) {
1582+ // expectFailure tests are intentionally not retried, so an
1583+ // expectFailure timeout flows through #cancel to preserve the
1584+ // existing non-flaky cancellation semantics.
15581585 this . #cancel( err ) ;
15591586 } else {
15601587 // A flaky timeout must not flow through #cancel: #cancel aborts the
@@ -1593,19 +1620,26 @@ class Test extends AsyncResource {
15931620 // the parent later, in postRun) is detected here so the parent still
15941621 // retries. An external abort and an expectFailure verdict stop retrying
15951622 // immediately.
1596- const subtestsFailed = this . isFlaky &&
1597- ArrayPrototypeSome ( this . subtests , ( subtest ) => ! subtest . passed && ! subtest . isTodo ) ;
1623+ const subtestsFailed = (
1624+ this . isFlaky &&
1625+ ArrayPrototypeSome ( this . subtests , ( subtest ) => ! subtest . passed && ! subtest . isTodo )
1626+ ) ;
15981627 if ( this . passed && ! subtestsFailed ) {
15991628 break ;
16001629 }
1601- const shouldRetry = this . #retriesRemaining( attempt , maxAttempts ) &&
1602- ( ! this . passed || subtestsFailed ) ;
1630+ const shouldRetry = (
1631+ this . #retriesRemaining( attempt , maxAttempts ) &&
1632+ ( ! this . passed || subtestsFailed )
1633+ ) ;
16031634 if ( ! shouldRetry ) {
16041635 // Run any final-attempt duties deferred toward a retry that is now
16051636 // called off (e.g. the outer signal aborted during afterEach).
16061637 try { await after ( ) ; } catch { /* test is already failing */ }
1607- if ( willRetry && attemptError !== undefined &&
1608- channelContext !== null && testChannel . error . hasSubscribers ) {
1638+ if (
1639+ willRetry && attemptError !== undefined &&
1640+ channelContext !== null &&
1641+ testChannel . error . hasSubscribers
1642+ ) {
16091643 publishError ( attemptError ) ;
16101644 }
16111645 break ;
@@ -1828,9 +1862,7 @@ class Test extends AsyncResource {
18281862
18291863 if ( this . isFlaky ) {
18301864 const flaky = this . reporter . getFlaky ( this . retryCount ) ;
1831- directive = directive === undefined ?
1832- flaky :
1833- { __proto__ : null , ...directive , ...flaky } ;
1865+ directive = { __proto__ : null , ...directive , ...flaky } ;
18341866 }
18351867
18361868 if ( this . reportedType ) {
@@ -1849,8 +1881,10 @@ class Test extends AsyncResource {
18491881 return { __proto__ : null , details, directive } ;
18501882 }
18511883
1852- // Counters must not see a subtree that a flaky ancestor may still discard:
1853- // park the count on that ancestor until it settles (report()) or retries.
1884+ /**
1885+ * Counters must not see a subtree that a flaky ancestor may still discard:
1886+ * park the count on that ancestor until it settles (report()) or retries.
1887+ */
18541888 #countCompleted( ) {
18551889 let ancestor = this . parent ;
18561890 while ( ancestor !== null ) {
@@ -1878,7 +1912,8 @@ class Test extends AsyncResource {
18781912 // outputSubtestCount was non-zero; fall back to this test's own nesting
18791913 // rather than dereferencing subtests[0] (which would crash the run).
18801914 const subtestNesting = this . subtests . length ?
1881- this . subtests [ 0 ] . nesting : this . nesting + 1 ;
1915+ this . subtests [ 0 ] . nesting :
1916+ this . nesting + 1 ;
18821917 this . reporter . plan ( subtestNesting , this . loc , this . outputSubtestCount ) ;
18831918 } else {
18841919 this . reportStarted ( ) ;
0 commit comments