@@ -8,6 +8,7 @@ const {makeRequest} = require('./utils/requestHelper');
88const CrashReporter = require ( './utils/crashReporter' ) ;
99const Logger = require ( './utils/logger' ) ;
1010const { API_URL } = require ( './utils/constants' ) ;
11+ const hooksMap = { } ;
1112
1213class TestObservability {
1314 configure ( settings = { } ) {
@@ -414,9 +415,9 @@ class TestObservability {
414415
415416 try {
416417 if ( eventType === 'TestRunFinished' ) {
417- const currentSessionCapabilities = reportData . session [ args . envelope . testCaseStartedId ] ;
418- if ( currentSessionCapabilities . error ) {
419- throw new Error ( `Error in driver capabilities: ${ JSON . stringify ( currentSessionCapabilities . error ) } ` ) ;
418+ let currentSessionCapabilities = reportData . session [ args . envelope . testCaseStartedId ] ;
419+ if ( currentSessionCapabilities === undefined || currentSessionCapabilities . error ) {
420+ currentSessionCapabilities = helper . generateCapabilityDetails ( args ) ;
420421 }
421422
422423 const sessionCapabilities = currentSessionCapabilities . capabilities ;
@@ -469,6 +470,14 @@ class TestObservability {
469470 }
470471 }
471472
473+ if ( eventType === 'TestRunFinished' ) {
474+ const hooksList = this . getHooksListForTest ( args ) ;
475+ if ( hooksList && hooksList . length > 0 ) {
476+ testData . hooks = hooksList ;
477+ this . updateTestStatus ( args , testData ) ;
478+ }
479+ }
480+
472481 const uploadData = {
473482 event_type : eventType ,
474483 test_run : testData
@@ -477,6 +486,142 @@ class TestObservability {
477486
478487 }
479488
489+ updateTestStatus ( args , testData ) {
490+ const testCaseStartedId = args . envelope . testCaseStartedId ;
491+ const hookList = hooksMap [ testCaseStartedId ] ;
492+ if ( hookList instanceof Array ) {
493+ for ( const hook of hookList ) {
494+ if ( hook . result === 'failed' ) {
495+ testData . result = hook . result ;
496+ testData . failure = hook . failure_data ;
497+ testData . failure_reason = ( hook . failure_data instanceof Array ) ? hook . failure_data [ 0 ] ?. backtrace . join ( '\n' ) : '' ;
498+ testData . failure_type = hook . failure_type ;
499+
500+ return testData ;
501+ }
502+ }
503+ } ;
504+ }
505+
506+ getHooksListForTest ( args ) {
507+ const testCaseStartedId = args . envelope . testCaseStartedId ;
508+ if ( hooksMap [ testCaseStartedId ] ) {
509+ return hooksMap [ testCaseStartedId ] . map ( hookDetail => hookDetail . uuid ) ;
510+ }
511+
512+ return [ ] ;
513+ }
514+
515+ getHookRunEventData ( args , eventType , hookData , testMetaData , hookType ) {
516+ if ( eventType === 'HookRunFinished' ) {
517+ const finishedAt = new Date ( ) . toISOString ( ) ;
518+ const testCaseStartedId = args . envelope . testCaseStartedId ;
519+ const hookList = hooksMap [ testCaseStartedId ] ;
520+ if ( ! hookList ) {
521+ return ;
522+ }
523+
524+ const hookEventData = hookList . find ( hook => hook . uuid === hookData . id ) ;
525+ if ( ! hookEventData ) {
526+ return ;
527+ }
528+ const result = this . getHookResult ( args ) ;
529+ hookEventData . result = result . status ;
530+ hookEventData . finished_at = finishedAt ;
531+ hookEventData . failure_type = result . failureType ;
532+ hookEventData . failure_data = [ { backtrace : result . failureData } ] ;
533+
534+ return hookEventData ;
535+ }
536+ const hookDetails = args . report . hooks . find ( hookDetail => hookDetail . id === hookData . hookId ) ;
537+ const relativeFilePath = hookDetails ?. sourceReference ?. uri ;
538+ if ( ! relativeFilePath ) {
539+ return ;
540+ } else if ( relativeFilePath . includes ( 'setup_cucumber_runner' ) ) {
541+ return ;
542+ }
543+ const startedAt = new Date ( ) . toISOString ( ) ;
544+ const result = 'pending' ;
545+ const hookTagsList = hookDetails . tagExpression ? hookDetails . tagExpression . split ( ' ' ) . filter ( val => val . includes ( '@' ) ) : null ;
546+
547+ const hookEventData = {
548+ uuid : hookData . id ,
549+ type : 'hook' ,
550+ hook_type : hookType ,
551+ name : hookDetails ?. name || '' ,
552+ body : {
553+ lang : 'NodeJs' ,
554+ code : null
555+ } ,
556+ tags : hookTagsList ,
557+ scope : testMetaData ?. feature ?. name ,
558+ scopes : [ testMetaData ?. feature ?. name || '' ] ,
559+ file_name : relativeFilePath ,
560+ location : relativeFilePath ,
561+ vc_filepath : ( this . _gitMetadata && this . _gitMetadata . root ) ? path . relative ( this . _gitMetadata . root , relativeFilePath ) : null ,
562+ result : result . status ,
563+ started_at : startedAt ,
564+ framework : 'nightwatch'
565+ } ;
566+
567+ return hookEventData ;
568+ }
569+
570+ async sendHook ( args , eventType , testSteps , testStepId , testMetaData ) {
571+ const hookData = testSteps . find ( ( testStep ) => testStep . id === testStepId ) ;
572+ if ( ! hookData . hookId ) {
573+ return ;
574+ }
575+ const testCaseStartedId = args . envelope . testCaseStartedId ;
576+ const hookType = this . getCucumberHookType ( testSteps , hookData ) ;
577+ const hookRunEvent = this . getHookRunEventData ( args , eventType , hookData , testMetaData , hookType ) ;
578+ if ( ! hookRunEvent ) {
579+ return ;
580+ }
581+ if ( eventType === 'HookRunStarted' ) {
582+ if ( hooksMap [ testCaseStartedId ] ) {
583+ hooksMap [ testCaseStartedId ] . push ( hookRunEvent ) ;
584+ } else {
585+ hooksMap [ testCaseStartedId ] = [ hookRunEvent ] ;
586+ }
587+ }
588+ const hookEventUploadData = {
589+ event_type : eventType ,
590+ hook_run : hookRunEvent
591+ } ;
592+ await helper . uploadEventData ( hookEventUploadData ) ;
593+ }
594+
595+ getHookResult ( args ) {
596+ const testCaseStartedId = args . envelope . testCaseStartedId ;
597+ const hookResult = args . report . testStepFinished [ testCaseStartedId ] . testStepResult ;
598+ let failure ;
599+ let failureType ;
600+ if ( hookResult ?. status . toString ( ) . toLowerCase ( ) === 'failed' ) {
601+ failure = ( hookResult ?. exception === undefined ) ? hookResult ?. message : hookResult ?. exception ?. message ;
602+ failureType = ( hookResult ?. exception === undefined ) ? 'UnhandledError' : hookResult ?. message . match ( / A s s e r t / ) ? 'AssertionError' : 'UnhandledError' ;
603+ }
604+
605+ return {
606+ status : hookResult . status . toLowerCase ( ) ,
607+ failureType : failureType || null ,
608+ failureData : ( ! failure ) ? null : [ failure ]
609+ } ;
610+ }
611+
612+ // BEFORE_ALL and AFTER_ALL are not implemented for TO
613+ getCucumberHookType ( testSteps , hookData ) {
614+ let isStep = false ;
615+ for ( const step of testSteps ) {
616+ if ( step . pickleStepId ) {
617+ isStep = true ;
618+ }
619+ if ( hookData . id === step . id ) {
620+ return ( isStep ) ? 'AFTER_EACH' : 'BEFORE_EACH' ;
621+ }
622+ }
623+ }
624+
480625 async appendTestItemLog ( log , testUuid ) {
481626 try {
482627 if ( testUuid ) {
0 commit comments