import debugFactory from 'debug' ; import { NetworkRecordingTestObserver } from './NetworkRecordingTestObserver' ; import { Timing } from './Timing' ; import { Test } from './testTypes' ; import { Step } from '../Step' ; import { StructuredError } from '../../utils/StructuredError' ; import { ResponseTiming } from '../Settings' ; import NetworkRecorder from '../../network/Recorder' ; import { expect } from '@flood/element-report' ; const debug = debugFactory ( 'element:grid:timing' ) ; export class TimingObserver extends NetworkRecordingTestObserver { private passed = 0 ; private failed = 0 ; private timing : Timing = new Timing ( ) ; memberof async before ( test ) { return this . next . before ( test ) ; } public async after ( test ) { return this . next . after ( test ) ; } async beforeStep ( test , step ) { debug ( 'beforeStep' ) ; this . timing . reset ( ) ; this . passed = 0 ; this . failed = 0 ; this . timing . start ( 'beforeStep' ) ; const name = step . name ; const reporter = test . reporter ; await this . next . beforeStep ( test , step ) ; reporter . reset ( name ) ; this . timing . end ( 'beforeStep' ) ; this . timing . start ( 'step' ) ; debug ( `Before step: ${ name }` ) ; } async afterStep ( test , step ) { this . timing . end ( 'step' ) ; this . timing . start ( 'afterStep' ) ; await this . syncNetworkRecorder ( ) ; debug ( `After step: ${ step . name }` ) ; await this . next . afterStep ( test , step ) ; await this . reportResult ( test , step ) ; this . timing . end ( 'afterStep' ) ; } async onStepPassed ( test , step ) { this . passed ++ ; return this . next . onStepPassed ( test , step ) ; } async onStepError ( test , step , err ) { this . failed ++ ; return this . next . onStepError ( test , step , err ) ; } async beforeStepAction ( test , step , action ) { await this . timing . measureThinkTime ( 'step' , async ( ) => { debug ( `Before action: '${ action }()' waiting on networkRecorder sync` ) ; await this . syncNetworkRecorder ( ) ; await this . next . beforeStepAction ( test , step , action ) ; } ) ; } async afterStepAction ( test , step , action ) { await this . timing . measureThinkTime ( 'step' , async ( ) => { debug ( `After action: ${ action }` ) ; await this . next . afterStepAction ( test , step , action ) ; } ) ; } async onStepSkipped ( test , step ) { debug ( `Skipped step: ${ step . name }` ) ; return this . next . onStepSkipped ( test , step ) ; } async onStepUnexecuted ( test , step ) { debug ( `Skipped step: ${ step . name }` ) ; return this . next . onStepUnexecuted ( test , step ) ; } private async reportResult ( test , step ) { if ( test . runningBrowser === null ) { debug ( 'reportResult: no running browser' ) ; return ; } const reporter = test . reporter ; const name = step . name ; expect ( name == reporter . stepName , 'reporting this step' ) ; await this . syncNetworkRecorder ( ) ; const { networkRecorder } = this . ctx ; if ( networkRecorder ) { debug ( `Report Result: ${ name }` ) ; const responseCode = String ( networkRecorder . documentResponseCode || 0 ) ; const documentResponseTime = this . getResponseTimeMeasurement ( test . settings . responseTimeMeasurement , networkRecorder ) ; const documentLatency = networkRecorder . latencyForType ( 'Document' ) ; test . reporter . responseCode = responseCode ; reporter . addMeasurement ( 'throughput' , networkRecorder . networkThroughput ( ) , name ) ; reporter . addMeasurement ( 'response_time' , documentResponseTime , name ) ; reporter . addMeasurement ( 'latency' , documentLatency , name ) ; } reporter . addMeasurement ( 'transaction_rate' , 1 , name ) ; reporter . addMeasurement ( 'passed' , this . passed , name ) ; reporter . addMeasurement ( 'failed' , this . failed , name ) ; await reporter . flushMeasurements ( ) ; } async getMeasurementTime ( responseTiming , fromNow ? ) { await this . syncNetworkRecorder ( ) ; const { networkRecorder } = this . ctx ; return this . getResponseTimeMeasurement ( responseTiming , networkRecorder , fromNow ) ; } getResponseTimeMeasurement ( responseTimeMeasurement , networkRecorder , fromNow ? ) { switch ( responseTimeMeasurement ) { case 'page' : return networkRecorder . responseTimeForType ( 'Document' ) ; case 'network' : return networkRecorder . meanResponseTime ( ) ; case 'step' : { const value = this . timing . getDurationWithoutThinkTimeForSegment ( 'step' , fromNow ) ; const thinkTime = this . timing . getThinkTimeForSegment ( 'step' ) ; debug ( `Step Timing: thinking=${ thinkTime } ms, interaction: ${ value } ms` ) ; return value ; } case 'stepWithThinkTime' : { const value = this . timing . getDurationForSegment ( 'step' ) ; const thinkTime = this . timing . getThinkTimeForSegment ( 'step' ) ; debug ( `Step Timing: thinking=${ thinkTime } ms, step: ${ value } ms` ) ; return value ; } default : return 0 ; } } }