import * as messages from '@cucumber/messages' ; import { EnvelopeListener , ISupportCodeExecutor , ITestStep , IWorld } from './types' ; import makeAttach from './makeAttach' ; import IClock from './IClock' ; import IStopwatch from './IStopwatch' ; import { MakeErrorMessage } from './ErrorMessageGenerator' ; const { millisecondsToDuration , millisecondsSinceEpochToTimestamp } = messages . TimeConversion ; export default abstract class TestStep implements ITestStep { constructor ( public readonly id , public readonly sourceId , public readonly alwaysExecute , protected readonly supportCodeExecutors , private readonly sourceFrames , private readonly clock , private readonly stopwatch , private readonly makeErrorMessage ) { } public abstract toMessage ( ) ; public async execute ( world , testCaseStartedId , listener , previousPassed ) { this . emitTestStepStarted ( testCaseStartedId , listener ) ; if ( this . supportCodeExecutors . length === 0 ) { return this . emitTestStepFinished ( testCaseStartedId , { duration : millisecondsToDuration ( 0 ) , status : messages . TestStepResultStatus . UNDEFINED , } , listener ) ; } if ( this . supportCodeExecutors . length > 1 ) { return this . emitTestStepFinished ( testCaseStartedId , { duration : millisecondsToDuration ( 0 ) , status : messages . TestStepResultStatus . AMBIGUOUS , } , listener ) ; } if ( ! previousPassed && ! this . alwaysExecute ) { return this . emitTestStepFinished ( testCaseStartedId , { duration : millisecondsToDuration ( 0 ) , status : messages . TestStepResultStatus . SKIPPED , } , listener ) ; } const start = this . stopwatch . stopwatchNow ( ) ; try { world . attach = makeAttach ( this . id , testCaseStartedId , listener ) ; world . log = ( text ) => { world . attach ( text , 'text/x.cucumber.log+plain' ) ; } ; const result = await this . supportCodeExecutors [ 0 ] . execute ( world ) ; const finish = this . stopwatch . stopwatchNow ( ) ; const duration = millisecondsToDuration ( finish - start ) ; const status = this . inferStatus ( result ) ; return this . emitTestStepFinished ( testCaseStartedId , { duration , status , } , listener ) ; } catch ( error ) { const finish = this . stopwatch . stopwatchNow ( ) ; const message = this . makeErrorMessage ( error , this . sourceFrames ) ; const duration = millisecondsToDuration ( finish - start ) ; return this . emitTestStepFinished ( testCaseStartedId , { duration , status : messages . TestStepResultStatus . FAILED , message , } , listener ) ; } } protected emitTestStepStarted ( testCaseStartedId , listener ) { listener ( { testStepStarted : { testCaseStartedId : testCaseStartedId , testStepId : this . id , timestamp : millisecondsSinceEpochToTimestamp ( this . clock . clockNow ( ) ) , } , } ) ; } protected emitTestStepFinished ( testCaseStartedId , testStepResult , listener ) { listener ( { testStepFinished : { testCaseStartedId : testCaseStartedId , testStepId : this . id , testStepResult : testStepResult , timestamp : millisecondsSinceEpochToTimestamp ( this . clock . clockNow ( ) ) , } , } ) ; return testStepResult ; } private inferStatus ( result ) { switch ( result ) { case 'pending' : return messages . TestStepResultStatus . PENDING ; case 'skipped' : return messages . TestStepResultStatus . SKIPPED ; default : return messages . TestStepResultStatus . PASSED ; } } }