[tests] improved testing framework error/success output
This commit is contained in:
parent
d8fee7f5cb
commit
c4d066fd55
|
@ -6,6 +6,21 @@ const EVENTS = {
|
|||
TEST_STATUS: 'TEST_STATUS',
|
||||
};
|
||||
|
||||
const locationRegex = /\(?http:.*:([0-9]+):([0-9]+)\)?/g;
|
||||
|
||||
function cleanStack(stack, maxLines = 5) {
|
||||
const lines = stack.split('\n').slice(0, maxLines + 1);
|
||||
const out = [];
|
||||
|
||||
for (let i = 0, len = lines.length; i < len; i++) {
|
||||
const srcLine = lines[i].trim();
|
||||
out.push(srcLine.replace(locationRegex, '()'));
|
||||
}
|
||||
|
||||
return out.join('\r\n');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class that encapsulates synchronously running a suite's tests.
|
||||
*/
|
||||
|
@ -212,6 +227,14 @@ class TestRun {
|
|||
}).then(() => true).catch(() => false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param testContext
|
||||
* @param error
|
||||
* @param testStart
|
||||
* @param errorPrefix
|
||||
* @private
|
||||
*/
|
||||
_reportAllTestsAsFailed(testContext, error, testStart, errorPrefix) {
|
||||
testContext.tests.forEach((test) => {
|
||||
this._reportTestError(test, error, Date.now() - testStart, errorPrefix);
|
||||
|
@ -253,6 +276,13 @@ class TestRun {
|
|||
|
||||
if (error) {
|
||||
this._reportTestError(test, error, Date.now() - testStart);
|
||||
console.groupCollapsed(`%c ❌ Test Failed: ${test.description} (${this.testSuite.name})`, 'color: #f44336;');
|
||||
console.log(`Test Description: ${test.description}`);
|
||||
console.log(`Test Time Taken: ${Date.now() - testStart}`);
|
||||
console.log(`Suite Name: ${this.testSuite.name}`);
|
||||
console.log(`Suite Description: ${this.testSuite.description}`);
|
||||
console.log(error);
|
||||
console.groupEnd();
|
||||
} else {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
test.status = RunStatus.OK;
|
||||
|
@ -263,6 +293,13 @@ class TestRun {
|
|||
time: Date.now() - testStart,
|
||||
message: '',
|
||||
});
|
||||
|
||||
console.groupCollapsed(`%c ✅ Test Passed: ${test.description} (${this.testSuite.name})`, 'color: #4CAF50;');
|
||||
console.log(`Test Description: ${test.description}`);
|
||||
console.log(`Test Time Taken: ${Date.now() - testStart}`);
|
||||
console.log(`Suite Name: ${this.testSuite.name}`);
|
||||
console.log(`Suite Description: ${this.testSuite.description}`);
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
// Update suite progress
|
||||
|
@ -279,31 +316,44 @@ class TestRun {
|
|||
|
||||
await this._runHookChain(test, testStart, testContext, 'afterEach', afterEachHooks);
|
||||
}
|
||||
})
|
||||
|
||||
.catch((error) => {
|
||||
}).catch((error) => {
|
||||
this._updateStatus(EVENTS.TEST_SUITE_STATUS, {
|
||||
suiteId: this.testSuite.id,
|
||||
status: RunStatus.ERR,
|
||||
time: Date.now() - this.runStartTime,
|
||||
message: `Test suite failed: ${error.message}`
|
||||
message: `Test suite failed: ${error.message}`,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param test
|
||||
* @param error
|
||||
* @param time
|
||||
* @param errorPrefix
|
||||
* @private
|
||||
*/
|
||||
_reportTestError(test, error, time, errorPrefix = '') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
test.status = RunStatus.ERR;
|
||||
|
||||
this._updateStatus(EVENTS.TEST_STATUS, {
|
||||
testId: test.id,
|
||||
status: RunStatus.ERR,
|
||||
time,
|
||||
message: `${errorPrefix}${error.message ? `${error.name}: ${error.message}` : error}`,
|
||||
stackTrace: error.stack,
|
||||
stackTrace: cleanStack(error.stack),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param func
|
||||
* @param timeOutDuration
|
||||
* @param description
|
||||
* @return {Promise.<*>}
|
||||
* @private
|
||||
*/
|
||||
async _safelyRunFunction(func, timeOutDuration, description) {
|
||||
const syncResultOrPromise = captureThrownErrors(func);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node node_modules/react-native/local-cli/cli.js start",
|
||||
"start": "node node_modules/react-native/local-cli/cli.js start --platforms ios,android",
|
||||
"android:dev": "react-native run-android",
|
||||
"android:prod": "react-native run-android --configuration=release",
|
||||
"ios:dev": "react-native run-ios",
|
||||
|
|
|
@ -39,7 +39,7 @@ const styles = StyleSheet.create({
|
|||
color: '#ffffff',
|
||||
},
|
||||
warning: {
|
||||
backgroundColor: '#FFC107',
|
||||
backgroundColor: '#f57c00',
|
||||
},
|
||||
error: {
|
||||
backgroundColor: '#f44336',
|
||||
|
|
|
@ -22,7 +22,7 @@ class CoreContainer extends React.Component {
|
|||
*/
|
||||
componentDidMount() {
|
||||
if (Platform.OS === 'android') {
|
||||
StatusBar.setBackgroundColor('#0279ba');
|
||||
StatusBar.setBackgroundColor('#1976D2');
|
||||
}
|
||||
if (Platform.OS === 'ios') {
|
||||
StatusBar.setBarStyle('light-content');
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import * as testActions from '../actions/TestActions';
|
||||
import { flatten, unflatten } from 'deeps';
|
||||
import * as testActions from '../actions/TestActions';
|
||||
import { initialState } from '../tests/index';
|
||||
|
||||
const initState = initialState();
|
||||
|
||||
function testsReducers(state = initState.tests, action: Object): State {
|
||||
|
||||
if (action.type === testActions.TEST_SET_STATUS) {
|
||||
const flattened = flatten(state);
|
||||
|
||||
|
|
|
@ -14,10 +14,12 @@ class Overview extends React.Component {
|
|||
static navigationOptions = {
|
||||
title: 'Test Suites',
|
||||
headerTintColor: '#ffffff',
|
||||
headerStyle: { backgroundColor: '#0288d1' },
|
||||
headerRight: <View style={{ marginRight: 8 }}>
|
||||
<OverviewControlButton />
|
||||
</View>
|
||||
headerStyle: { backgroundColor: '#1976D2' },
|
||||
headerRight: (
|
||||
<View style={{ marginRight: 8 }}>
|
||||
<OverviewControlButton />
|
||||
</View>
|
||||
),
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,14 +15,16 @@ class Suite extends React.Component {
|
|||
return {
|
||||
title,
|
||||
headerTintColor: '#ffffff',
|
||||
headerStyle: { backgroundColor: '#0288d1' },
|
||||
headerRight: <View style={{ flexDirection: 'row', marginRight: 8 }}>
|
||||
<TestSuiteControlButton
|
||||
testSuiteId={testSuiteId}
|
||||
onlyShowFailingTests={onlyShowFailingTests}
|
||||
onFilterChange={setParams}
|
||||
/>
|
||||
</View>,
|
||||
headerStyle: { backgroundColor: '#1976D2' },
|
||||
headerRight: (
|
||||
<View style={{ flexDirection: 'row', marginRight: 8 }}>
|
||||
<TestSuiteControlButton
|
||||
testSuiteId={testSuiteId}
|
||||
onlyShowFailingTests={onlyShowFailingTests}
|
||||
onFilterChange={setParams}
|
||||
/>
|
||||
</View>
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -13,10 +13,12 @@ class Test extends React.Component {
|
|||
return {
|
||||
title,
|
||||
headerTintColor: '#ffffff',
|
||||
headerStyle: { backgroundColor: '#0288d1' },
|
||||
headerRight: <View style={{ marginRight: 8 }}>
|
||||
<TestControlButton testId={testId} />
|
||||
</View>,
|
||||
headerStyle: { backgroundColor: '#1976D2' },
|
||||
headerRight: (
|
||||
<View style={{ marginRight: 8 }}>
|
||||
<TestControlButton testId={testId} />
|
||||
</View>
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -52,31 +54,38 @@ class Test extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { test: { stackTrace, description, func, status, time }, testContextName } = this.props;
|
||||
const { test: { stackTrace, message, description, func, status, time }, testContextName } = this.props;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{Test.renderBanner({ status, time })}
|
||||
<View >
|
||||
<ScrollView style={styles.sectionContainer}>
|
||||
<ScrollView >
|
||||
<View style={styles.sectionContainer}>
|
||||
<Text style={styles.heading}>{testContextName}</Text>
|
||||
<Text style={styles.description}>{description}</Text>
|
||||
</ScrollView>
|
||||
<ScrollView style={styles.sectionContainer}>
|
||||
<Text style={styles.heading}>Test Error</Text>
|
||||
</View>
|
||||
{message ? <View style={styles.sectionContainer}>
|
||||
<Text style={styles.headingWarn}>Test Error Message</Text>
|
||||
<Text style={styles.message}>{message || 'None.'}</Text>
|
||||
</View> : null }
|
||||
{stackTrace ? <View style={styles.sectionContainer}>
|
||||
<Text style={styles.headingWarn}>Test Error Stack</Text>
|
||||
<Text style={styles.description}>
|
||||
<Text>{stackTrace || 'None.'}</Text>
|
||||
{stackTrace || 'None.'}
|
||||
</Text>
|
||||
</View> : null }
|
||||
<View style={styles.sectionContainer}>
|
||||
<Text style={styles.heading}>
|
||||
Test Code Preview
|
||||
</Text>
|
||||
</ScrollView>
|
||||
<Text style={styles.heading}>
|
||||
Test Code Preview
|
||||
</Text>
|
||||
<ScrollView style={styles.sectionContainer}>
|
||||
<Text style={styles.description}>
|
||||
{beautify(removeLastLine(removeFirstLine(func.toString())), { indent_size: 4, break_chained_methods: true })}
|
||||
{beautify(removeLastLine(removeFirstLine(func.toString())), {
|
||||
indent_size: 4,
|
||||
break_chained_methods: true,
|
||||
})}
|
||||
</Text>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -87,7 +96,8 @@ Test.propTypes = {
|
|||
status: PropTypes.string,
|
||||
time: PropTypes.number,
|
||||
func: PropTypes.function,
|
||||
stackTrace: PropTypes.function,
|
||||
stackTrace: PropTypes.string,
|
||||
message: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
}).isRequired,
|
||||
|
||||
|
@ -101,29 +111,57 @@ Test.propTypes = {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#ffffff',
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
sectionContainer: {
|
||||
minHeight: 100,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
heading: {
|
||||
padding: 5,
|
||||
backgroundColor: '#0288d1',
|
||||
fontWeight: '600',
|
||||
elevation: 3,
|
||||
backgroundColor: '#2196F3',
|
||||
fontWeight: '400',
|
||||
color: '#ffffff',
|
||||
fontSize: 16,
|
||||
fontSize: 14,
|
||||
},
|
||||
headingWarn: {
|
||||
padding: 5,
|
||||
elevation: 3,
|
||||
backgroundColor: '#FFC107',
|
||||
fontWeight: '400',
|
||||
color: '#212121',
|
||||
fontSize: 14,
|
||||
},
|
||||
description: {
|
||||
padding: 5,
|
||||
fontSize: 14,
|
||||
fontSize: 12,
|
||||
},
|
||||
message: {
|
||||
padding: 5,
|
||||
fontSize: 12,
|
||||
width: '100%',
|
||||
minHeight: 100,
|
||||
},
|
||||
});
|
||||
|
||||
/*
|
||||
.dark-primary-color { background: #1976D2; }
|
||||
.default-primary-color { background: #2196F3; }
|
||||
.light-primary-color { background: #BBDEFB; }
|
||||
.text-primary-color { color: #FFFFFF; }
|
||||
.accent-color { background: #FFC107; }
|
||||
.primary-text-color { color: #212121; }
|
||||
.secondary-text-color { color: #757575; }
|
||||
.divider-color { border-color: #BDBDBD; }
|
||||
|
||||
*/
|
||||
|
||||
function select({ tests, testContexts }, { navigation: { state: { params: { testId } } } }) {
|
||||
const test = tests[testId];
|
||||
let testContext = testContexts[test.testContextId];
|
||||
|
||||
while(testContext.parentContextId && testContexts[testContext.parentContextId].parentContextId) {
|
||||
while (testContext.parentContextId && testContexts[testContext.parentContextId].parentContextId) {
|
||||
testContext = testContexts[testContext.parentContextId];
|
||||
}
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue