import React, {Component} from 'react'; import { AppRegistry, StyleSheet, Text, View, Platform, ScrollView, ListView, Image, TouchableOpacity, Dimensions, RecyclerViewBackedScrollView, } from 'react-native'; import AnimateNumber from '../animate-text.js' import Assert from './assert.js' import RNTEST from '../index.js' export default class Reporter extends Component { constructor(props:any) { super(props) this.tests = { common : [] } this.state = { listHeight : 0 } this.testGroups = ['summary','common'] this.ds = null this.updateDataSource() } componentWillUpdate(nextProps, nextState) { this.updateDataSource() } render() { let tests = RNTEST.TestContext.getTests() let passed = 0 let executed = 0 let count = 0 for(let i in tests) { if(tests[i].status !== 'skipped') count++ if(tests[i].status !== 'waiting' && tests[i].status !== 'skipped') executed++ passed += tests[i].status === 'pass' ? 1 : 0 } let percent = passed / count let color = `rgb(${Math.floor((1-percent) *255)},${Math.floor(percent *192)}, 0)` return ( <View style={{flex : 1}}> <View style={{margin : 20}} onLayout={(e) => { this.setState({ headerHeight : e.nativeEvent.layout.height, listHeight : Dimensions.get('window').height - e.nativeEvent.layout.height }) }}> <Text>{`${executed} tests executed`}</Text> <Text>{`${passed} test cases passed`}</Text> <Text>{`${count} test cases`}</Text> <View style={{flexDirection : 'row', alignSelf : 'center', alignItems : 'flex-end'}}> <AnimateNumber style={{ color, fontSize : 100, textAlign : 'right' }} value={Math.floor(passed / count*100)} countBy={1}/> <Text style={{color, fontSize : 30, textAlign : 'left'}} >{`%`}</Text> </View> </View> <ListView style={[styles.container]} dataSource={this.ds} renderRow={this.renderTest.bind(this)} renderScrollComponent={props => <RecyclerViewBackedScrollView {...props} />} renderSectionHeader={(data, id) => { return ( <View style={styles.sectionHeader}> <Text style={styles.sectionText}>{id}</Text> </View> ) }} /> </View>) } renderTest(t, group) { let pass = true let foundActions = false let tests = RNTEST.TestContext.getTests() if(Array.isArray(t.result) && !t.expired) { t.result = t.result.map((r) => { if(r.type.name === 'Assert' || r.type.name === 'Info') { foundActions = true let comp = r.props.comparer ? r.props.comparer(r.props.expect, r.props.actual) : (r.props.actual === r.props.expect) pass = pass && comp } return React.cloneElement(r, {desc : r.key}) }) } if(tests[t.sn].running) t.status = 'running' else if(tests[t.sn].executed) { t.status = foundActions ? (pass ? 'pass' : 'fail') : 'skipped' t.status = t.expired ? 'timeout' : t.status } else t.status = 'waiting' return ( <View key={'rn-test-' + t.desc} style={{ borderBottomWidth : 1.5, borderColor : '#DDD', }}> <View key={t.desc} style={{ alignItems : 'center', flexDirection : 'row' }}> <Text style={[styles.badge, {flex : 1, borderWidth : 0, textAlign : 'left'}]}>{t.desc}</Text> <Text style={[styles.badge, this.getBadge(t.status)]}>{t.status}</Text> </View> <View key={t.desc + '-result'} style={{backgroundColor : '#F4F4F4'}}> {t.expand ? t.result : (t.status === 'pass' ? null : t.result)} </View> </View>) } updateDataSource() { this.tests = { common : [] } this.testGroups = ['common'] RNTEST.TestContext.getTests().forEach((t) => { if(t.group) { if(!this.tests[t.group]) { this.testGroups.push(t.group) this.tests[t.group] = [] } this.tests[t.group].push(t) } else this.tests.common.push(t) }) let listDataSource = new ListView.DataSource({ rowHasChanged : (r1, r2) => r1 !== r2, sectionHeaderHasChanged: (s1, s2) => s1 !== s2 }) this.ds = listDataSource.cloneWithRowsAndSections(this.tests, this.testGroups) } getBadge(status: 'waiting' | 'running' | 'pass' | 'fail' | 'timeout') { return styles[status] } } const styles = StyleSheet.create({ container: { flex: 1, }, badge : { margin : 16, padding : 4, borderRadius : 4, borderWidth : 2, textAlign : 'center' }, skipped: { borderColor : '#AAAAAA', color : '#AAAAAA' }, sectionHeader : { padding : 16, backgroundColor : '#F4F4F4', }, waiting: { borderColor : '#AAAAAA', color : '#AAAAAA' }, pass: { borderColor : '#00a825', color : '#00a825' }, running: { borderColor : '#e3c423', color : '#e3c423' }, fail: { borderColor : '#ff0d0d', color : '#ff0d0d' }, timeout: { borderColor : '#ff0d0d', color : '#ff0d0d' } });