@@ -2170,6 +2170,76 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
21702170 } )
21712171 } )
21722172
2173+ it ( 'resets mock state between early flake detection retries' , async ( ) => {
2174+ receiver . setInfoResponse ( { endpoints : [ '/evp_proxy/v4' ] } )
2175+ // Test is considered new (not in known tests)
2176+ receiver . setKnownTests ( { jest : { } } )
2177+ const NUM_RETRIES_EFD = 3
2178+ receiver . setSettings ( {
2179+ early_flake_detection : {
2180+ enabled : true ,
2181+ slow_test_retries : {
2182+ '5s' : NUM_RETRIES_EFD
2183+ } ,
2184+ faulty_session_threshold : 100
2185+ } ,
2186+ known_tests_enabled : true
2187+ } )
2188+
2189+ let stdout = ''
2190+ const eventsPromise = receiver
2191+ . gatherPayloadsMaxTimeout ( ( { url } ) => url . endsWith ( '/api/v2/citestcycle' ) , ( payloads ) => {
2192+ const events = payloads . flatMap ( ( { payload } ) => payload . events )
2193+ const tests = events . filter ( event => event . type === 'test' ) . map ( event => event . content )
2194+
2195+ // Should have 1 original + NUM_RETRIES_EFD retry attempts
2196+ const mockTests = tests . filter (
2197+ test => test . meta [ TEST_NAME ] === 'early flake detection tests with mock resets mock state between retries'
2198+ )
2199+ assert . strictEqual ( mockTests . length , NUM_RETRIES_EFD + 1 )
2200+
2201+ // All tests should pass because mock state is reset between retries
2202+ for ( const test of mockTests ) {
2203+ assert . strictEqual ( test . meta [ TEST_STATUS ] , 'pass' )
2204+ }
2205+
2206+ // All should be marked as new
2207+ for ( const test of mockTests ) {
2208+ assert . strictEqual ( test . meta [ TEST_IS_NEW ] , 'true' )
2209+ }
2210+ } )
2211+
2212+ childProcess = exec (
2213+ runTestsCommand ,
2214+ {
2215+ cwd,
2216+ env : {
2217+ ...getCiVisEvpProxyConfig ( receiver . port ) ,
2218+ TESTS_TO_RUN : 'test-early-flake-detection/test-efd-with-mock'
2219+ } ,
2220+ }
2221+ )
2222+
2223+ childProcess . stdout ?. on ( 'data' , ( chunk ) => {
2224+ stdout += chunk . toString ( )
2225+ } )
2226+
2227+ childProcess . stderr ?. on ( 'data' , ( chunk ) => {
2228+ stdout += chunk . toString ( )
2229+ } )
2230+
2231+ const [ exitCode ] = await Promise . all ( [
2232+ once ( childProcess , 'exit' ) ,
2233+ eventsPromise
2234+ ] )
2235+
2236+ // Verify the test actually ran
2237+ assert . match ( stdout , / I a m r u n n i n g E F D w i t h m o c k / )
2238+
2239+ // All retries should pass, so exit code should be 0
2240+ assert . strictEqual ( exitCode [ 0 ] , 0 )
2241+ } )
2242+
21732243 it ( 'handles parameterized tests as a single unit' , ( done ) => {
21742244 receiver . setInfoResponse ( { endpoints : [ '/evp_proxy/v4' ] } )
21752245 // Tests from ci-visibility/test-early-flake-detection/test-parameterized.js will be considered new
@@ -4208,6 +4278,79 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
42084278 ] )
42094279 } )
42104280
4281+ it ( 'resets mock state between attempt to fix retries' , async ( ) => {
4282+ const NUM_RETRIES = 3
4283+ receiver . setSettings ( { test_management : { enabled : true , attempt_to_fix_retries : NUM_RETRIES } } )
4284+
4285+ receiver . setTestManagementTests ( {
4286+ jest : {
4287+ suites : {
4288+ 'ci-visibility/test-management/test-attempt-to-fix-with-mock.js' : {
4289+ tests : {
4290+ 'attempt to fix tests with mock resets mock state between retries' : {
4291+ properties : {
4292+ attempt_to_fix : true
4293+ }
4294+ }
4295+ }
4296+ }
4297+ }
4298+ }
4299+ } )
4300+
4301+ let stdout = ''
4302+ const eventsPromise = receiver
4303+ . gatherPayloadsMaxTimeout ( ( { url } ) => url . endsWith ( '/api/v2/citestcycle' ) , ( payloads ) => {
4304+ const events = payloads . flatMap ( ( { payload } ) => payload . events )
4305+ const tests = events . filter ( event => event . type === 'test' ) . map ( event => event . content )
4306+
4307+ // Should have 1 original + NUM_RETRIES retry attempts
4308+ const mockTests = tests . filter (
4309+ test => test . meta [ TEST_NAME ] === 'attempt to fix tests with mock resets mock state between retries'
4310+ )
4311+ assert . strictEqual ( mockTests . length , NUM_RETRIES + 1 )
4312+
4313+ // All tests should pass because mock state is reset between retries
4314+ for ( const test of mockTests ) {
4315+ assert . strictEqual ( test . meta [ TEST_STATUS ] , 'pass' )
4316+ }
4317+
4318+ // Last attempt should be marked as attempt_to_fix_passed
4319+ const lastTest = mockTests [ mockTests . length - 1 ]
4320+ assert . strictEqual ( lastTest . meta [ TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED ] , 'true' )
4321+ } )
4322+
4323+ childProcess = exec (
4324+ runTestsCommand ,
4325+ {
4326+ cwd,
4327+ env : {
4328+ ...getCiVisAgentlessConfig ( receiver . port ) ,
4329+ TESTS_TO_RUN : 'test-management/test-attempt-to-fix-with-mock'
4330+ } ,
4331+ }
4332+ )
4333+
4334+ childProcess . stdout ?. on ( 'data' , ( chunk ) => {
4335+ stdout += chunk . toString ( )
4336+ } )
4337+
4338+ childProcess . stderr ?. on ( 'data' , ( chunk ) => {
4339+ stdout += chunk . toString ( )
4340+ } )
4341+
4342+ const [ exitCode ] = await Promise . all ( [
4343+ once ( childProcess , 'exit' ) ,
4344+ eventsPromise
4345+ ] )
4346+
4347+ // Verify the test actually ran
4348+ assert . match ( stdout , / I a m r u n n i n g a t t e m p t t o f i x w i t h m o c k / )
4349+
4350+ // All retries should pass, so exit code should be 0
4351+ assert . strictEqual ( exitCode [ 0 ] , 0 )
4352+ } )
4353+
42114354 it ( 'does not fail retry if a test is quarantined' , ( done ) => {
42124355 receiver . setSettings ( { test_management : { enabled : true , attempt_to_fix_retries : 3 } } )
42134356 receiver . setTestManagementTests ( {
@@ -4936,6 +5079,24 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
49365079 })`
49375080 )
49385081 execSync ( 'git add ci-visibility/test-impacted-test/test-impacted-1.js' , { cwd, stdio : 'ignore' } )
5082+
5083+ // Also modify test file with mock for mock state reset test
5084+ fs . writeFileSync (
5085+ path . join ( cwd , 'ci-visibility/test-impacted-test/test-impacted-with-mock.js' ) ,
5086+ `'use strict'
5087+
5088+ const mockFn = jest.fn()
5089+
5090+ describe('impacted tests with mock', () => {
5091+ it('resets mock state between retries', () => {
5092+ console.log('I am running impacted test with mock')
5093+ mockFn()
5094+ expect(mockFn).toHaveBeenCalledTimes(1)
5095+ })
5096+ })`
5097+ )
5098+ execSync ( 'git add ci-visibility/test-impacted-test/test-impacted-with-mock.js' , { cwd, stdio : 'ignore' } )
5099+
49395100 execSync ( 'git commit -m "modify test-impacted-1.js"' , { cwd, stdio : 'ignore' } )
49405101 } )
49415102
@@ -5161,6 +5322,76 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
51615322 } )
51625323 runImpactedTest ( done , { isModified : true , isEfd : true , isNew : true } )
51635324 } )
5325+
5326+ it ( 'resets mock state between impacted test retries' , async ( ) => {
5327+ // Test is considered new (not in known tests)
5328+ receiver . setKnownTests ( { jest : { } } )
5329+ receiver . setSettings ( {
5330+ impacted_tests_enabled : true ,
5331+ early_flake_detection : {
5332+ enabled : true ,
5333+ slow_test_retries : {
5334+ '5s' : NUM_RETRIES
5335+ } ,
5336+ faulty_session_threshold : 100
5337+ } ,
5338+ known_tests_enabled : true
5339+ } )
5340+
5341+ let stdout = ''
5342+ const eventsPromise = receiver
5343+ . gatherPayloadsMaxTimeout ( ( { url } ) => url . endsWith ( '/api/v2/citestcycle' ) , ( payloads ) => {
5344+ const events = payloads . flatMap ( ( { payload } ) => payload . events )
5345+ const tests = events . filter ( event => event . type === 'test' ) . map ( event => event . content )
5346+
5347+ // Should have 1 original + NUM_RETRIES retry attempts
5348+ const mockTests = tests . filter (
5349+ test => test . meta [ TEST_NAME ] === 'impacted tests with mock resets mock state between retries'
5350+ )
5351+ assert . strictEqual ( mockTests . length , NUM_RETRIES + 1 )
5352+
5353+ // All tests should pass because mock state is reset between retries
5354+ for ( const test of mockTests ) {
5355+ assert . strictEqual ( test . meta [ TEST_STATUS ] , 'pass' )
5356+ }
5357+
5358+ // All should be marked as modified (impacted)
5359+ for ( const test of mockTests ) {
5360+ assert . strictEqual ( test . meta [ TEST_IS_MODIFIED ] , 'true' )
5361+ }
5362+ } )
5363+
5364+ childProcess = exec (
5365+ runTestsCommand ,
5366+ {
5367+ cwd,
5368+ env : {
5369+ ...getCiVisAgentlessConfig ( receiver . port ) ,
5370+ TESTS_TO_RUN : 'test-impacted-test/test-impacted-with-mock' ,
5371+ GITHUB_BASE_REF : ''
5372+ } ,
5373+ }
5374+ )
5375+
5376+ childProcess . stdout ?. on ( 'data' , ( chunk ) => {
5377+ stdout += chunk . toString ( )
5378+ } )
5379+
5380+ childProcess . stderr ?. on ( 'data' , ( chunk ) => {
5381+ stdout += chunk . toString ( )
5382+ } )
5383+
5384+ const [ exitCode ] = await Promise . all ( [
5385+ once ( childProcess , 'exit' ) ,
5386+ eventsPromise
5387+ ] )
5388+
5389+ // Verify the test actually ran
5390+ assert . match ( stdout , / I a m r u n n i n g i m p a c t e d t e s t w i t h m o c k / )
5391+
5392+ // All retries should pass, so exit code should be 0
5393+ assert . strictEqual ( exitCode [ 0 ] , 0 )
5394+ } )
51645395 } )
51655396 } )
51665397
0 commit comments