import 'reflect-metadata' ; import * as util from 'util' ; import { AICombinedReportDataConverter , AICrawler , BaselineEvaluation , BaselineFileUpdater , BaselineOptions , BaselineOptionsBuilder , CombinedScanResult , CrawlerParametersBuilder , CrawlerRunOptions , ScanArguments , } from 'accessibility-insights-scan' ; import { IMock , It , Mock , MockBehavior , Times } from 'typemoq' ; import { LocalFileServer } from '../local-file-server' ; import { Logger } from '../logger/logger' ; import { AllProgressReporter } from '../progress-reporter/all-progress-reporter' ; import { PromiseUtils } from '../utils/promise-utils' ; import { Scanner } from './scanner' ; import { ConsolidatedReportGenerator } from '../report/consolidated-report-generator' ; import { AxeInfo } from '../axe/axe-info' ; import { CrawlArgumentHandler } from './crawl-argument-handler' ; import { CombinedReportParameters } from 'accessibility-insights-report' ; import { TaskConfig } from '../task-config' ; describe ( Scanner , ( ) => { let aiCrawlerMock ; let reportGeneratorMock ; let progressReporterMock ; let localFileServerMock ; let promiseUtilsMock ; let axeInfoMock ; let combinedReportConverterMock ; let processStub ; let exitMock ; let loggerMock ; let crawlArgumentHandlerMock ; let taskConfigMock ; let crawlerParametersBuilder ; let baselineOptionsBuilderMock ; let baselineFileUpdaterMock ; let scanner ; let combinedScanResult ; let scanArguments ; const scanTimeoutMsec = 100000 ; beforeEach ( ( ) => { aiCrawlerMock = Mock . ofType < AICrawler > ( ) ; reportGeneratorMock = Mock . ofType ( ConsolidatedReportGenerator ) ; progressReporterMock = Mock . ofType ( AllProgressReporter ) ; localFileServerMock = Mock . ofType ( LocalFileServer , MockBehavior . Strict ) ; promiseUtilsMock = Mock . ofType ( PromiseUtils ) ; axeInfoMock = Mock . ofType < AxeInfo > ( ) ; combinedReportConverterMock = Mock . ofType < AICombinedReportDataConverter > ( ) ; exitMock = Mock . ofType < ( _ : number ) => void > ( ) ; processStub = { exit : exitMock . object , } as typeof process ; loggerMock = Mock . ofType ( Logger ) ; crawlArgumentHandlerMock = Mock . ofType < CrawlArgumentHandler > ( ) ; taskConfigMock = Mock . ofType < TaskConfig > ( ) ; crawlerParametersBuilder = Mock . ofType < CrawlerParametersBuilder > ( ) ; baselineOptionsBuilderMock = Mock . ofType < BaselineOptionsBuilder > ( null , MockBehavior . Strict ) ; baselineFileUpdaterMock = Mock . ofType < BaselineFileUpdater > ( ) ; scanner = new Scanner ( aiCrawlerMock . object , reportGeneratorMock . object , progressReporterMock . object , localFileServerMock . object , promiseUtilsMock . object , axeInfoMock . object , combinedReportConverterMock . object , processStub , loggerMock . object , crawlArgumentHandlerMock . object , taskConfigMock . object , crawlerParametersBuilder . object , baselineOptionsBuilderMock . object , baselineFileUpdaterMock . object ) ; combinedScanResult = { scanMetadata : { baseUrl : 'baseUrl' , } , } ; scanArguments = { url : 'url' , chromePath : 'chrome' , axeSourcePath : 'axe' , } as ScanArguments ; } ) ; describe ( 'scan' , ( ) => { it ( 'performs expected steps in happy path with remote url' , async ( ) => { setupMocksForSuccessfulScan ( ) ; setupWaitForPromisetoReturnOriginalPromise ( ) ; await scanner . scan ( ) ; verifyMocks ( ) ; } ) ; it ( 'performs expected steps in happy path with local url (starts file server)' , async ( ) => { scanArguments . url = '' ; localFileServerMock . setup ( ( m ) => m . start ( ) ) . returns ( ( _ ) => Promise . resolve ( 'localhost' ) ) ; setupMocksForSuccessfulScan ( ) ; setupWaitForPromisetoReturnOriginalPromise ( ) ; await scanner . scan ( ) ; verifyMocks ( ) ; localFileServerMock . verify ( ( m ) => m . start ( ) , Times . once ( ) ) ; } ) ; it ( 'passes BaselineEvaluation to ProgressReporter' , async ( ) => { setupMocksForSuccessfulScan ( { } as BaselineEvaluation ) ; setupWaitForPromisetoReturnOriginalPromise ( ) ; await scanner . scan ( ) ; verifyMocks ( ) ; } ) ; it ( 'reports error when timeout occurs' , async ( ) => { const errorMessage = `Scan timed out after ${ scanTimeoutMsec / 1000 } seconds` ; localFileServerMock . setup ( ( m ) => m . stop ( ) ) . verifiable ( Times . once ( ) ) ; loggerMock . setup ( ( lm ) => lm . logError ( errorMessage ) ) . verifiable ( Times . once ( ) ) ; exitMock . setup ( ( em ) => em ( 1 ) ) . verifiable ( Times . once ( ) ) ; taskConfigMock . setup ( ( m ) => m . getScanTimeout ( ) ) . returns ( ( _ ) => scanTimeoutMsec ) . verifiable ( Times . once ( ) ) ; setupWaitForPromiseToReturnTimeoutPromise ( ) ; await scanner . scan ( ) ; verifyMocks ( ) ; } ) ; it ( 'should trackException on error' , async ( ) => { const errorMessage = 'some err' ; const error = new Error ( errorMessage ) ; taskConfigMock . setup ( ( m ) => m . getScanTimeout ( ) ) . returns ( ( _ ) => scanTimeoutMsec ) ; progressReporterMock . setup ( ( m ) => m . start ( ) ) . throws ( error ) ; loggerMock . setup ( ( lm ) => lm . trackExceptionAny ( error , `An error occurred while scanning website page undefined` ) ) . verifiable ( Times . once ( ) ) ; loggerMock . setup ( ( lm ) => lm . logInfo ( `Accessibility scanning of URL undefined completed` ) ) . verifiable ( Times . once ( ) ) ; progressReporterMock . setup ( ( p ) => p . failRun ( util . inspect ( error ) ) ) . verifiable ( Times . once ( ) ) ; localFileServerMock . setup ( ( m ) => m . stop ( ) ) . verifiable ( Times . once ( ) ) ; setupWaitForPromisetoReturnOriginalPromise ( ) ; await scanner . scan ( ) ; verifyMocks ( ) ; } ) ; function setupMocksForSuccessfulScan ( baselineEvaluation ? ) { taskConfigMock . setup ( ( m ) => m . getScanTimeout ( ) ) . returns ( ( _ ) => scanTimeoutMsec ) . verifiable ( Times . once ( ) ) ; taskConfigMock . setup ( ( m ) => m . getUrl ( ) ) . returns ( ( _ ) => scanArguments . url ) . verifiable ( Times . once ( ) ) ; progressReporterMock . setup ( ( p ) => p . start ( ) ) . verifiable ( Times . once ( ) ) ; crawlArgumentHandlerMock . setup ( ( m ) => m . processScanArguments ( It . isAny ( ) ) ) . returns ( ( _ ) => scanArguments ) . verifiable ( Times . once ( ) ) ; loggerMock . setup ( ( lm ) => lm . logInfo ( `Starting accessibility scanning of URL ${ scanArguments . url }` ) ) . verifiable ( Times . once ( ) ) ; loggerMock . setup ( ( lm ) => lm . logInfo ( `Chrome app executable: ${ scanArguments . chromePath ?? 'system default' }` ) ) . verifiable ( Times . once ( ) ) ; const crawlerParams = { baseUrl : scanArguments . url , } ; const baselineOptions = { } as BaselineOptions ; crawlerParametersBuilder . setup ( ( m ) => m . build ( scanArguments ) ) . returns ( ( _ ) => crawlerParams ) . verifiable ( Times . once ( ) ) ; baselineOptionsBuilderMock . setup ( ( m ) => m . build ( scanArguments ) ) . returns ( ( ) => baselineOptions ) . verifiable ( Times . once ( ) ) ; baselineFileUpdaterMock . setup ( ( m ) => m . updateBaseline ( scanArguments , baselineEvaluation ) ) . returns ( ( ) => Promise . resolve ( ) ) . verifiable ( Times . once ( ) ) ; combinedScanResult . baselineEvaluation = baselineEvaluation ; aiCrawlerMock . setup ( ( m ) => m . crawl ( crawlerParams , baselineOptions ) ) . returns ( async ( ) => { return Promise . resolve ( combinedScanResult ) ; } ) . verifiable ( Times . once ( ) ) ; const combinedReportData = { } as CombinedReportParameters ; axeInfoMock . setup ( ( m ) => m . version ) . returns ( ( _ ) => 'version' ) ; combinedReportConverterMock . setup ( ( m ) => m . convertCrawlingResults ( It . isAny ( ) , It . isAny ( ) ) ) . returns ( ( _ ) => combinedReportData ) . verifiable ( Times . once ( ) ) ; reportGeneratorMock . setup ( ( rgm ) => rgm . generateReport ( combinedReportData ) ) . verifiable ( Times . once ( ) ) ; loggerMock . setup ( ( lm ) => lm . logInfo ( `Accessibility scanning of URL ${ scanArguments . url } completed` ) ) . verifiable ( Times . once ( ) ) ; progressReporterMock . setup ( ( p ) => p . completeRun ( combinedReportData , baselineEvaluation ) ) . verifiable ( Times . once ( ) ) ; localFileServerMock . setup ( ( lfs ) => lfs . stop ( ) ) . verifiable ( ) ; } function setupWaitForPromisetoReturnOriginalPromise ( ) { promiseUtilsMock . setup ( ( s ) => s . waitFor ( It . isAny ( ) , scanTimeoutMsec , It . isAny ( ) ) ) . returns ( async ( scanPromiseObj ) => { return scanPromiseObj ; } ) . verifiable ( Times . once ( ) ) ; } function setupWaitForPromiseToReturnTimeoutPromise ( ) { promiseUtilsMock . setup ( ( s ) => s . waitFor ( It . isAny ( ) , scanTimeoutMsec , It . isAny ( ) ) ) . returns ( async ( _ , __ , timeoutCb ) => { return timeoutCb ( ) ; } ) . verifiable ( Times . once ( ) ) ; } } ) ; function verifyMocks ( ) { progressReporterMock . verifyAll ( ) ; crawlArgumentHandlerMock . verifyAll ( ) ; loggerMock . verifyAll ( ) ; aiCrawlerMock . verifyAll ( ) ; axeInfoMock . verifyAll ( ) ; combinedReportConverterMock . verifyAll ( ) ; reportGeneratorMock . verifyAll ( ) ; localFileServerMock . verifyAll ( ) ; promiseUtilsMock . verifyAll ( ) ; baselineOptionsBuilderMock . verifyAll ( ) ; baselineFileUpdaterMock . verifyAll ( ) ; } } ) ;