@@ -6370,7 +6370,10 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
63706370 }
63716371 )
63726372
6373- // jest uses stderr to output logs
6373+ // jest uses stderr to output logs, stdout for console.log from tests
6374+ childProcess . stdout ?. on ( 'data' , ( chunk ) => {
6375+ stdout += chunk . toString ( )
6376+ } )
63746377 childProcess . stderr ?. on ( 'data' , ( chunk ) => {
63756378 stdout += chunk . toString ( )
63766379 } )
@@ -6382,9 +6385,9 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
63826385 if ( isQuarantining ) {
63836386 // even though a test fails, the exit code is 0 because the test is quarantined
63846387 assert . strictEqual ( exitCode , 0 )
6385- // Verify Datadog Test Optimization message is shown when exit code is flipped
6388+ // Verify Datadog Test Optimization message is shown for suppressed quarantine failures
63866389 assert . match ( stdout , / D a t a d o g T e s t O p t i m i z a t i o n / )
6387- assert . match ( stdout , / \d + t e s t f a i l u r e \( s \) w e r e i g n o r e d \. E x i t c o d e s e t t o 0 \. / )
6390+ assert . match ( stdout , / \d + t e s t f a i l u r e \( s \) w e r e i g n o r e d / )
63886391 assert . match ( stdout , / Q u a r a n t i n e / )
63896392 assert . match ( stdout , / t e s t - q u a r a n t i n e - 1 .* › .* q u a r a n t i n e t e s t s c a n q u a r a n t i n e a t e s t / )
63906393 } else {
@@ -6769,6 +6772,269 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
67696772 const [ [ exitCode ] ] = await Promise . all ( [ once ( childProcess , 'exit' ) , testAssertionsPromise ] )
67706773 assert . strictEqual ( exitCode , 1 , 'exit code 1 when suite fails (resolution error)' )
67716774 } )
6775+
6776+ it ( 'does not bail on quarantined test failures' , async ( ) => {
6777+ receiver . setSettings ( { test_management : { enabled : true } } )
6778+
6779+ const eventsPromise = receiver
6780+ . gatherPayloadsMaxTimeout ( ( { url } ) => url . endsWith ( '/api/v2/citestcycle' ) , ( payloads ) => {
6781+ const events = payloads . flatMap ( ( { payload } ) => payload . events )
6782+ const tests = events . filter ( event => event . type === 'test' ) . map ( event => event . content )
6783+ const testSession = events . find ( event => event . type === 'test_session_end' ) . content
6784+
6785+ assert . strictEqual ( testSession . meta [ TEST_STATUS ] , 'pass' )
6786+ assert . strictEqual ( testSession . meta [ TEST_MANAGEMENT_ENABLED ] , 'true' )
6787+
6788+ const resourceNames = tests . map ( span => span . resource )
6789+
6790+ // Both suites must have run — bail should not have stopped execution
6791+ assertObjectContains ( resourceNames , [
6792+ 'ci-visibility/test-management/test-quarantine-1.js.quarantine tests can quarantine a test' ,
6793+ 'ci-visibility/test-management/test-quarantine-1.js.quarantine tests can pass normally' ,
6794+ 'ci-visibility/test-management/test-quarantine-2.js.quarantine tests 2 can quarantine a test' ,
6795+ 'ci-visibility/test-management/test-quarantine-2.js.quarantine tests 2 can pass normally' ,
6796+ ] )
6797+
6798+ // The quarantined test should still report as failed with quarantine tag
6799+ const failedTest = tests . find (
6800+ test => test . meta [ TEST_NAME ] === 'quarantine tests can quarantine a test' &&
6801+ test . resource . includes ( 'test-quarantine-1' )
6802+ )
6803+ assert . strictEqual ( failedTest . meta [ TEST_STATUS ] , 'fail' )
6804+ assert . strictEqual ( failedTest . meta [ TEST_MANAGEMENT_IS_QUARANTINED ] , 'true' )
6805+
6806+ // The test suite containing the quarantined test should be reported as passed
6807+ const suites = events . filter ( event => event . type === 'test_suite_end' ) . map ( event => event . content )
6808+ const quarantineSuite = suites . find (
6809+ s => s . meta [ TEST_SUITE ] ?. includes ( 'test-quarantine-1' )
6810+ )
6811+ assert . strictEqual ( quarantineSuite . meta [ TEST_STATUS ] , 'pass' )
6812+ } )
6813+
6814+ let stderr = ''
6815+ childProcess = exec (
6816+ runTestsCommand ,
6817+ {
6818+ cwd,
6819+ env : {
6820+ ...getCiVisAgentlessConfig ( receiver . port ) ,
6821+ TESTS_TO_RUN : 'test-management/test-quarantine' ,
6822+ JEST_BAIL : '1' ,
6823+ SHOULD_CHECK_RESULTS : '1' ,
6824+ } ,
6825+ }
6826+ )
6827+ childProcess . stderr ?. on ( 'data' , ( chunk ) => {
6828+ stderr += chunk . toString ( )
6829+ } )
6830+
6831+ const [ [ exitCode ] ] = await Promise . all ( [ once ( childProcess , 'exit' ) , eventsPromise ] )
6832+
6833+ // With quarantine suppressing errors, Jest should not see failures,
6834+ // so bail should not stop the second suite from running
6835+ assert . match ( stderr , / T e s t S u i t e s : .* 2 p a s s e d / )
6836+ assert . strictEqual ( exitCode , 0 )
6837+ } )
6838+
6839+ it ( 'does not bail on quarantined test failures when ATR is enabled' , async ( ) => {
6840+ receiver . setSettings ( {
6841+ test_management : { enabled : true } ,
6842+ flaky_test_retries_enabled : true ,
6843+ } )
6844+
6845+ const eventsPromise = receiver
6846+ . gatherPayloadsMaxTimeout ( ( { url } ) => url . endsWith ( '/api/v2/citestcycle' ) , ( payloads ) => {
6847+ const events = payloads . flatMap ( ( { payload } ) => payload . events )
6848+ const tests = events . filter ( event => event . type === 'test' ) . map ( event => event . content )
6849+ const testSession = events . find ( event => event . type === 'test_session_end' ) . content
6850+
6851+ assert . strictEqual ( testSession . meta [ TEST_STATUS ] , 'pass' )
6852+
6853+ const resourceNames = tests . map ( span => span . resource )
6854+
6855+ // Both suites must have run — bail should not have stopped execution
6856+ assertObjectContains ( resourceNames , [
6857+ 'ci-visibility/test-management/test-quarantine-1.js.quarantine tests can quarantine a test' ,
6858+ 'ci-visibility/test-management/test-quarantine-2.js.quarantine tests 2 can quarantine a test' ,
6859+ ] )
6860+
6861+ // ATR should have retried the quarantined test
6862+ const quarantinedTests = tests . filter (
6863+ test => test . meta [ TEST_NAME ] === 'quarantine tests can quarantine a test' &&
6864+ test . resource . includes ( 'test-quarantine-1' )
6865+ )
6866+ assert . ok ( quarantinedTests . length > 1 , 'quarantined test should have been retried by ATR' )
6867+ for ( const test of quarantinedTests ) {
6868+ assert . strictEqual ( test . meta [ TEST_MANAGEMENT_IS_QUARANTINED ] , 'true' )
6869+ }
6870+ } )
6871+
6872+ let stderr = ''
6873+ childProcess = exec (
6874+ runTestsCommand ,
6875+ {
6876+ cwd,
6877+ env : {
6878+ ...getCiVisAgentlessConfig ( receiver . port ) ,
6879+ TESTS_TO_RUN : 'test-management/test-quarantine' ,
6880+ JEST_BAIL : '1' ,
6881+ SHOULD_CHECK_RESULTS : '1' ,
6882+ } ,
6883+ }
6884+ )
6885+ childProcess . stderr ?. on ( 'data' , ( chunk ) => {
6886+ stderr += chunk . toString ( )
6887+ } )
6888+
6889+ const [ [ exitCode ] ] = await Promise . all ( [ once ( childProcess , 'exit' ) , eventsPromise ] )
6890+
6891+ assert . match ( stderr , / T e s t S u i t e s : .* 2 / )
6892+ assert . strictEqual ( exitCode , 0 )
6893+ } )
6894+
6895+ it ( 'does not bail on quarantined + attempt to fix test failures' , async ( ) => {
6896+ receiver . setSettings ( {
6897+ test_management : { enabled : true , attempt_to_fix_retries : 2 } ,
6898+ } )
6899+
6900+ receiver . setTestManagementTests ( {
6901+ jest : {
6902+ suites : {
6903+ 'ci-visibility/test-management/test-quarantine-1.js' : {
6904+ tests : {
6905+ 'quarantine tests can quarantine a test' : {
6906+ properties : {
6907+ quarantined : true ,
6908+ attempt_to_fix : true ,
6909+ } ,
6910+ } ,
6911+ } ,
6912+ } ,
6913+ } ,
6914+ } ,
6915+ } )
6916+
6917+ const eventsPromise = receiver
6918+ . gatherPayloadsMaxTimeout ( ( { url } ) => url . endsWith ( '/api/v2/citestcycle' ) , ( payloads ) => {
6919+ const events = payloads . flatMap ( ( { payload } ) => payload . events )
6920+ const tests = events . filter ( event => event . type === 'test' ) . map ( event => event . content )
6921+ const testSession = events . find ( event => event . type === 'test_session_end' ) . content
6922+
6923+ assert . strictEqual ( testSession . meta [ TEST_STATUS ] , 'pass' )
6924+
6925+ const resourceNames = tests . map ( span => span . resource )
6926+
6927+ // Both suites must have run — bail should not have stopped execution
6928+ assertObjectContains ( resourceNames , [
6929+ 'ci-visibility/test-management/test-quarantine-1.js.quarantine tests can quarantine a test' ,
6930+ 'ci-visibility/test-management/test-quarantine-2.js.quarantine tests 2 can quarantine a test' ,
6931+ ] )
6932+
6933+ // ATF should have retried the test
6934+ const quarantinedTests = tests . filter (
6935+ test => test . meta [ TEST_NAME ] === 'quarantine tests can quarantine a test' &&
6936+ test . resource . includes ( 'test-quarantine-1' )
6937+ )
6938+ assert . ok ( quarantinedTests . length > 1 , 'quarantined test should have been retried by ATF' )
6939+
6940+ const atfRetries = quarantinedTests . filter (
6941+ t => t . meta [ TEST_RETRY_REASON ] === TEST_RETRY_REASON_TYPES . atf
6942+ )
6943+ assert . ok ( atfRetries . length > 0 , 'should have ATF retries' )
6944+ } )
6945+
6946+ let stderr = ''
6947+ childProcess = exec (
6948+ runTestsCommand ,
6949+ {
6950+ cwd,
6951+ env : {
6952+ ...getCiVisAgentlessConfig ( receiver . port ) ,
6953+ TESTS_TO_RUN : 'test-management/test-quarantine' ,
6954+ JEST_BAIL : '1' ,
6955+ SHOULD_CHECK_RESULTS : '1' ,
6956+ } ,
6957+ }
6958+ )
6959+ childProcess . stderr ?. on ( 'data' , ( chunk ) => {
6960+ stderr += chunk . toString ( )
6961+ } )
6962+
6963+ const [ [ exitCode ] ] = await Promise . all ( [ once ( childProcess , 'exit' ) , eventsPromise ] )
6964+
6965+ assert . match ( stderr , / T e s t S u i t e s : .* 2 / )
6966+ assert . strictEqual ( exitCode , 0 )
6967+ } )
6968+
6969+ it ( 'does not bail when quarantine, ATR, and attempt to fix are all enabled' , async ( ) => {
6970+ receiver . setSettings ( {
6971+ test_management : { enabled : true , attempt_to_fix_retries : 2 } ,
6972+ flaky_test_retries_enabled : true ,
6973+ } )
6974+
6975+ receiver . setTestManagementTests ( {
6976+ jest : {
6977+ suites : {
6978+ 'ci-visibility/test-management/test-quarantine-1.js' : {
6979+ tests : {
6980+ 'quarantine tests can quarantine a test' : {
6981+ properties : {
6982+ quarantined : true ,
6983+ attempt_to_fix : true ,
6984+ } ,
6985+ } ,
6986+ } ,
6987+ } ,
6988+ } ,
6989+ } ,
6990+ } )
6991+
6992+ const eventsPromise = receiver
6993+ . gatherPayloadsMaxTimeout ( ( { url } ) => url . endsWith ( '/api/v2/citestcycle' ) , ( payloads ) => {
6994+ const events = payloads . flatMap ( ( { payload } ) => payload . events )
6995+ const tests = events . filter ( event => event . type === 'test' ) . map ( event => event . content )
6996+ const testSession = events . find ( event => event . type === 'test_session_end' ) . content
6997+
6998+ assert . strictEqual ( testSession . meta [ TEST_STATUS ] , 'pass' )
6999+
7000+ const resourceNames = tests . map ( span => span . resource )
7001+
7002+ // Both suites must have run — bail should not have stopped execution
7003+ assertObjectContains ( resourceNames , [
7004+ 'ci-visibility/test-management/test-quarantine-1.js.quarantine tests can quarantine a test' ,
7005+ 'ci-visibility/test-management/test-quarantine-2.js.quarantine tests 2 can quarantine a test' ,
7006+ ] )
7007+
7008+ // The test should have been retried (by ATF since it takes precedence over ATR)
7009+ const quarantinedTests = tests . filter (
7010+ test => test . meta [ TEST_NAME ] === 'quarantine tests can quarantine a test' &&
7011+ test . resource . includes ( 'test-quarantine-1' )
7012+ )
7013+ assert . ok ( quarantinedTests . length > 1 , 'quarantined test should have been retried' )
7014+ } )
7015+
7016+ let stderr = ''
7017+ childProcess = exec (
7018+ runTestsCommand ,
7019+ {
7020+ cwd,
7021+ env : {
7022+ ...getCiVisAgentlessConfig ( receiver . port ) ,
7023+ TESTS_TO_RUN : 'test-management/test-quarantine' ,
7024+ JEST_BAIL : '1' ,
7025+ SHOULD_CHECK_RESULTS : '1' ,
7026+ } ,
7027+ }
7028+ )
7029+ childProcess . stderr ?. on ( 'data' , ( chunk ) => {
7030+ stderr += chunk . toString ( )
7031+ } )
7032+
7033+ const [ [ exitCode ] ] = await Promise . all ( [ once ( childProcess , 'exit' ) , eventsPromise ] )
7034+
7035+ assert . match ( stderr , / T e s t S u i t e s : .* 2 / )
7036+ assert . strictEqual ( exitCode , 0 )
7037+ } )
67727038 } )
67737039
67747040 it ( 'does not crash if the request to get test management tests fails' , async ( ) => {
0 commit comments