license import jasmineRequire from 'jasmine-core/lib/jasmine-core/jasmine.js' ; import * as jasmine_util from '@tensorflow/tfjs-core/dist/jasmine_util' ; import React , { Component , Fragment } from 'react' ; import { StyleSheet , Text , View , ViewStyle , ScrollView } from 'react-native' ; import * as tf from '@tensorflow/tfjs-core' ; interface TestRunnerProps { backend : string ; } interface FailedTestInfo { suiteName ? : string ; testName : string ; failedExpectations : Array < { message : string ; stack : string ; } > ; message ? : string ; } interface TestRunnerState { passedTests : number ; failedTests : FailedTestInfo [ ] ; totalTests : number ; testsComplete : boolean ; testsStarted : boolean ; backendName ? : string ; } export class TestRunner extends Component < TestRunnerProps , TestRunnerState > { constructor ( props ) { super ( props ) ; this . state = { passedTests : 0 , failedTests : [ ] , totalTests : 0 , testsComplete : false , testsStarted : false , } ; } /**
     * If a getRunner function is present in props, execute it
     * numRun times and report the result and timing info.
     */ async componentDidMount ( ) { const backendName = tf . getBackend ( ) ; this . setState ( { backendName , } ) ; let passedTests = 0 ; const failedTests = [ ] ; function extend ( destination , source ) { for ( const property in source ) { destination [ property ] = source [ property ] ; } return destination ; } const jasmine = jasmineRequire . core ( jasmineRequire ) ; global . jasmine = jasmine ; const env = jasmine . getEnv ( ) ; const jasmineInterface = jasmineRequire . interface ( jasmine , env ) ; extend ( global , jasmineInterface ) ; env . configure ( { random : false , specFilter : ( spec ) => { const name = spec . getFullName ( ) ; if ( name . match ( 'Backend registration' ) ) { return false ; } if ( name . match ( 'isMobile' ) ) { return false ; } if ( name . match ( 'dilation2d' ) ) { return false ; } if ( name . match ( 'method otsu' ) ) { return false ; } return true ; } } ) ; const reactReporter = { jasmineStarted : suiteInfo => { console . warn ( 'starting tests' ) ; console . reportErrorsAsExceptions = false ; this . setState ( { testsStarted : true , totalTests : suiteInfo . totalSpecsDefined , } ) ; } , specDone : result => { if ( result . failedExpectations == null || result . failedExpectations . length === 0 ) { passedTests += 1 ; this . setState ( { passedTests , } ) ; } else if ( result . failedExpectations . length > 0 ) { const failureInfo = { testName : result . fullName , failedExpectations : result . failedExpectations . map ( f => { return { message : f . message , stack : f . stack , } ; } ) , } ; console . log ( 'Test Failure' ) ; console . log ( JSON . stringify ( failureInfo , null , 2 ) ) ; failedTests . push ( failureInfo ) ; this . setState ( { failedTests , } ) ; } } , jasmineDone : ( ) => { console . reportErrorsAsExceptions = true ; this . setState ( { testsComplete : true , failedTests , } ) ; } } ; env . addReporter ( reactReporter ) ; jasmine_util . setTestEnvs ( [ { name : 'test-rn' , backendName : this . props . backend , flags : { 'WEBGL_CPU_FORWARD' : false , 'WEBGL_SIZE_UPLOAD_UNIFORM' : 0 , } } ] ) ; require ( '@tensorflow/tfjs-core/dist/tests' ) ; require ( '@tensorflow/tfjs-react-native/dist/tests' ) ; env . execute ( ) ; } renderTestFailure ( failure , key ) { return < View style = { styles . failedTest } key = { key } > < Text style = { styles . failedTestName } > { failure . testName } < /Text> < Fragment > { failure . failedExpectations . map ( ( expecation , i ) => < Text key = { i } > { expecation . message } < /Text>)} < /Fragment> < /View>; } formatTestFailuresForWebDriver ( failures ) { const TEST_SEPARATOR = '###' ; const TITLE_SEPARATOR = '%%%' ; return failures . map ( ( failure , i ) => { const testName = failure . testName ; const messages = failure . failedExpectations . map ( ( expecation , i ) => expecation . message ) . join ( '\n' ) ; return `${ testName }${ TITLE_SEPARATOR }${ messages }` ; } ) . join ( TEST_SEPARATOR ) ; } render ( ) { const { passedTests , failedTests , totalTests , backendName , testsComplete } = this . state ; return ( < Fragment > < View testID = 'testInfo' accessibilityLabel = 'testInfo' style = { styles . sectionContainer } > < Text style = { styles . sectionTitle } > Info < /Text> < Text testID = 'backendName' accessibilityLabel = 'backendName' > backend = { backendName } < /Text> < Text testID = 'testComplete' accessibilityLabel = 'testComplete' > testsComplete = { String ( testsComplete ) } < /Text> < Text > tf . env ( ) . platformName = { tf . env ( ) . platformName } < /Text> < /View> < View style = { styles . sectionContainer } > < Text style = { styles . sectionTitle } testID = 'passedTests' accessibilityLabel = 'passedTests' > Passed Tests { passedTests } of { totalTests } < /Text> < /View> < View > < Text style = { styles . failureMessages } testID = 'failureMessages' accessibilityLabel = 'failureMessages' > { this . formatTestFailuresForWebDriver ( failedTests ) } < /Text> < /View> < ScrollView contentInsetAdjustmentBehavior = 'automatic' > < View style = { styles . sectionContainer } > < Text style = { styles . sectionTitle } > Failed Tests ( { failedTests . length } ) < /Text> < View testID = 'failedTests' accessibilityLabel = 'failedTests' > { failedTests . map ( ( f , i ) => this . renderTestFailure ( f , i ) ) } < /View> < /View> < /ScrollView> < /Fragment>); } } const container = { display : 'flex' , flexDirection : 'row' , backgroundColor : '#FFFDE7' , padding : 5 , marginBottom : 5 , } ; const containerMounted = { ... container , backgroundColor : '#C8E6C9' , } ; const styles = StyleSheet . create ( { container , containerMounted , failedTest : { backgroundColor : 'white' , margin : 5 , paddingBottom : 10 , borderBottomWidth : 1 , borderBottomColor : '#ccc' , } , failedTestName : { backgroundColor : 'white' , fontWeight : 'bold' , } , failureMessages : { fontSize : 1 , } , sectionContainer : { marginTop : 24 , paddingHorizontal : 12 , paddingBottom : 4 , borderBottomWidth : 1 , borderBottomColor : '#ccc' , } , sectionTitle : { fontSize : 14 , fontWeight : '600' , color : 'black' , marginBottom : 6 , } , } ) ;