import * as Path from 'path' ; import * as Fs from 'fs-extra' ; import { unpacked , loc } from '@lib/helpers/paths' ; import { ParsedRepository } from '@lib/frameworks/repository' ; import { FrameworkOptions , FrameworkDefaults , Framework , FrameworkReloadOutcome } from '@lib/frameworks/framework' ; import { ISuiteResult , ISuite , Suite } from '@lib/frameworks/suite' ; import { ITest } from '@lib/frameworks/test' ; import { PHPUnitSuite } from '@lib/frameworks/phpunit/suite' ; import { FrameworkValidator } from '@lib/frameworks/validator' ; import { FrameworkSort } from '@lib/frameworks/sort' ; export class PHPUnit extends Framework { public readonly canToggleTests : boolean = true ; static readonly defaults : FrameworkDefaults = { all : { name : 'PHPUnit' , type : 'phpunit' , command : './vendor/bin/phpunit' , path : '' , proprietary : { autoloadPath : '' } } , win32 : { command : 'php vendor/phpunit/phpunit/phpunit' } } ; static readonly sortDefault : FrameworkSort = 'framework' ; public suites ! : Array < PHPUnitSuite > ; /**
     * The class of suite we use for this framework. Overrides the default
     * with a PHPUnit-specific suite class.
     */ protected suiteClass ( ) { return PHPUnitSuite ; } param repository public static async spawnForDirectory ( repository ) { return new Promise ( ( resolve , reject ) => { if ( repository . files . includes ( 'phpunit.xml' ) || repository . files . includes ( 'phpunit.xml.dist' ) ) { resolve ( this . hydrate ( ) ) ; return ; } Fs . access ( Path . join ( repository . path , 'vendor/bin/phpunit' ) , error => { resolve ( error ? false : this . hydrate ( ) ) ; } ) ; } ) ; } /**
     * Prepare this framework for running.
     */ protected async assemble ( ) { super . assemble ( ) ; if ( this . runsInRemote ) { const reporter = process . env . NODE_ENV === 'development' ? Path . resolve ( __dirname , loc ( '../../reporters/phpunit' ) ) : unpacked ( Path . join ( __static , loc ( './reporters/phpunit' ) ) ) ; await Fs . copy ( reporter , this . injectPath ( ) ) ; } } /**
     * Reload this framework's suites and tests.
     */ protected reload ( ) { return new Promise ( ( resolve , reject ) => { this . spawn ( [ '--columns=42' ] . concat ( this . runArgs ( ) ) ) . on ( 'report' , ( { report } ) => { try { Promise . all ( report . map ( ( result ) => { return this . makeSuite ( this . hydrateSuiteResult ( result ) , true ) ; } ) ) . then ( ( ) => { resolve ( 'success' ) ; } ) ; } catch ( error ) { this . stop ( ) ; reject ( 'The PHPUnit package returned unexpected results.' ) ; } } ) . on ( 'success' , ( ) => { resolve ( 'empty' ) ; } ) . on ( 'killed' , ( ) => { resolve ( 'killed' ) ; } ) . on ( 'error' , error => { reject ( error ) ; } ) ; } ) ; } /**
     * The command arguments for running this framework.
     */ protected runArgs ( ) { const root = ( this . runsInRemote ? this . getRemotePath ( ) : this . repositoryPath ) ; const autoload = Path . join ( root , loc ( this . proprietary . autoloadPath || 'vendor/autoload.php' ) ) ; const args = [ '-d' , `lode_bootstrap=${ autoload }` , '--bootstrap' , this . runsInRemote ? Path . join ( this . getRemotePath ( ) , loc ( '.lode/phpunit/bootstrap.php' ) ) : process . env . NODE_ENV === 'development' ? Path . resolve ( __dirname , loc ( '../../reporters/phpunit/bootstrap.php' ) ) : unpacked ( Path . join ( __static , loc ( './reporters/phpunit/bootstrap.php' ) ) ) , '--stderr' , '--color=always' , '--printer' , '\\LodeApp\\PHPUnit\\LodeReporter' ] ; if ( __DEV__ ) { args . push ( '-d' , 'display_errors=on' , '--verbose' ) ; } return args ; } param suites param selectTests protected runSelectiveArgs ( suites , selectTests ) { const args = [ '--filter' ] ; const filters = [ ] ; suites . forEach ( ( suite ) => { const suiteClass = ( suite as PHPUnitSuite ) . getClassName ( ) ; const selected = suite . tests . filter ( ( test ) => selectTests ? test . selected : true ) ; if ( selected . length !== suite . tests . length ) { selected . forEach ( ( test ) => { filters . push ( `${ suiteClass }::${ test . getName ( ) }$` ) ; } ) ; } else { filters . push ( suiteClass ) ; } } ) ; args . push ( `"${ filters . join ( '|' ) }"` ) ; return args . concat ( this . runArgs ( ) ) ; } param suites protected calculateProgressTotalForSuites ( suites ) { return suites . reduce ( ( acc , suite ) => { return acc + ( suite . countChildren ( ) || 1 ) ; } , 0 ) ; } /**
     * Validate PHPUnit specific options.
     */ public static validate ( validator , options ) { const autoload = options . proprietary . autoloadPath ; if ( autoload ) { if ( Path . isAbsolute ( autoload ) || ! validator . isFile ( Path . join ( validator . repositoryPath , autoload ) ) ) { validator . addError ( 'autoloadPath' , 'Please enter a valid file inside the repository directory.' ) ; } } } /**
     * Provide setup instructions for using Lode with PHPUnit.
     */ public static instructions ( ) { return '' ; } param error protected troubleshoot ( error ) { if ( error instanceof Error ) { error = error . toString ( ) ; } if ( ( new RegExp ( 'Cannot open file .*\/bootstrap\.php' , 'gi' ) ) . test ( error ) ) { return 'If your PHPUnit tests run in a remote machine, make sure to toggle that in your framework settings and set the absolute path to the repository inside the remote machine.' ; } return super . troubleshoot ( error ) ; } }