import { Stage } from '@serenity-js/core' ; import { AsyncOperationAttempted , AsyncOperationCompleted , AsyncOperationFailed , DomainEvent , SceneFinished , SceneFinishes , SceneStarts } from '@serenity-js/core/lib/events' ; import { CorrelationId , Description , ExecutionSkipped , Outcome , ProblemIndication , Timestamp } from '@serenity-js/core/lib/model' ; import { StageCrewMember } from '@serenity-js/core/lib/stage' ; import { Runner } from 'protractor' ; import { ProtractorReport } from './ProtractorReport' ; private export class ProtractorReporter implements StageCrewMember { private readonly startTime : { [ key ] : Timestamp ; } = { } ; constructor ( private readonly runner , private readonly successThreshold = ExecutionSkipped , private readonly reported = { failedCount : 0 , specResults : [ ] } , private stage ? ) { } assignedTo ( stage ) { return new ProtractorReporter ( this . runner , this . successThreshold , this . reported , stage ) ; } notifyOf ( event ) { if ( event instanceof SceneStarts ) { this . recordStart ( event ) ; } else if ( event instanceof SceneFinishes ) { this . afterEach ( ) ; } else if ( event instanceof SceneFinished && event . outcome . isWorseThan ( this . successThreshold ) ) { this . recordFailure ( event ) ; this . runner . emit ( 'testFail' , { name : event . details . name . value , category : event . details . category . value , } ) ; } else if ( event instanceof SceneFinished && ! event . outcome . isWorseThan ( this . successThreshold ) ) { this . recordSuccess ( event ) ; this . runner . emit ( 'testPass' , { name : event . details . name . value , category : event . details . category . value , } ) ; } } report ( ) { return this . reported ; } private recordFailure ( event ) { const outcome = ( event . outcome as ProblemIndication ) ; this . reported . failedCount ++ ; this . reported . specResults . push ( { description : `${ event . details . category . value } ${ event . details . name . value }` , duration : event . timestamp . diff ( this . startTime [ event . details . toString ( ) ] ) . inMilliseconds ( ) , assertions : [ { passed : false , errorMsg : outcome . error . message , stackTrace : outcome . error . stack , } ] , } ) ; } private recordStart ( event ) { this . startTime [ event . details . toString ( ) ] = event . timestamp ; } private recordSuccess ( event ) { this . reported . specResults . push ( { description : `${ event . details . category . value } ${ event . details . name . value }` , duration : event . timestamp . diff ( this . startTime [ event . details . toString ( ) ] ) . inMilliseconds ( ) , assertions : [ { passed : true , } ] , } ) ; } private afterEach ( ) { if ( ! this . runner . afterEach ) { return Promise . resolve ( ) ; } const id = CorrelationId . create ( ) ; this . stage . announce ( new AsyncOperationAttempted ( new Description ( `[${ this . constructor . name }] Invoking ProtractorRunner.afterEach...` ) , id , this . stage . currentTime ( ) ) ) ; return Promise . resolve ( this . runner . afterEach ( ) as PromiseLike < void > | undefined ) . then ( ( ) => this . stage . announce ( new AsyncOperationCompleted ( new Description ( `[${ this . constructor . name }] ProtractorRunner.afterEach succeeded` ) , id , this . stage . currentTime ( ) ) ) , error => this . stage . announce ( new AsyncOperationFailed ( error , id , this . stage . currentTime ( ) ) ) ) ; } }