From c4d066fd55e3f39b84c4b75f60734c5a533c95d8 Mon Sep 17 00:00:00 2001 From: Salakar Date: Tue, 18 Jul 2017 05:59:28 +0100 Subject: [PATCH] [tests] improved testing framework error/success output --- tests/lib/TestRun.js | 62 ++++++++++++++++-- tests/package.json | 2 +- tests/src/components/Banner.js | 2 +- tests/src/containers/CoreContainer.js | 2 +- tests/src/reducers/testsReducers.js | 3 +- tests/src/screens/Overview.js | 10 +-- tests/src/screens/Suite.js | 18 +++--- tests/src/screens/Test.js | 90 +++++++++++++++++++-------- 8 files changed, 140 insertions(+), 49 deletions(-) diff --git a/tests/lib/TestRun.js b/tests/lib/TestRun.js index 82bd4484..762cf463 100644 --- a/tests/lib/TestRun.js +++ b/tests/lib/TestRun.js @@ -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); diff --git a/tests/package.json b/tests/package.json index b8918e6b..3b717cb7 100644 --- a/tests/package.json +++ b/tests/package.json @@ -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", diff --git a/tests/src/components/Banner.js b/tests/src/components/Banner.js index 229f664f..8f3acaaf 100644 --- a/tests/src/components/Banner.js +++ b/tests/src/components/Banner.js @@ -39,7 +39,7 @@ const styles = StyleSheet.create({ color: '#ffffff', }, warning: { - backgroundColor: '#FFC107', + backgroundColor: '#f57c00', }, error: { backgroundColor: '#f44336', diff --git a/tests/src/containers/CoreContainer.js b/tests/src/containers/CoreContainer.js index 97ae3994..57a786e8 100644 --- a/tests/src/containers/CoreContainer.js +++ b/tests/src/containers/CoreContainer.js @@ -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'); diff --git a/tests/src/reducers/testsReducers.js b/tests/src/reducers/testsReducers.js index cfd6fb07..09d2ae92 100644 --- a/tests/src/reducers/testsReducers.js +++ b/tests/src/reducers/testsReducers.js @@ -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); diff --git a/tests/src/screens/Overview.js b/tests/src/screens/Overview.js index 4ce6a944..4b9c7ccf 100644 --- a/tests/src/screens/Overview.js +++ b/tests/src/screens/Overview.js @@ -14,10 +14,12 @@ class Overview extends React.Component { static navigationOptions = { title: 'Test Suites', headerTintColor: '#ffffff', - headerStyle: { backgroundColor: '#0288d1' }, - headerRight: - - + headerStyle: { backgroundColor: '#1976D2' }, + headerRight: ( + + + + ), }; /** diff --git a/tests/src/screens/Suite.js b/tests/src/screens/Suite.js index 1758a1eb..be46c701 100644 --- a/tests/src/screens/Suite.js +++ b/tests/src/screens/Suite.js @@ -15,14 +15,16 @@ class Suite extends React.Component { return { title, headerTintColor: '#ffffff', - headerStyle: { backgroundColor: '#0288d1' }, - headerRight: - - , + headerStyle: { backgroundColor: '#1976D2' }, + headerRight: ( + + + + ), }; }; diff --git a/tests/src/screens/Test.js b/tests/src/screens/Test.js index d69cb412..851486c2 100644 --- a/tests/src/screens/Test.js +++ b/tests/src/screens/Test.js @@ -13,10 +13,12 @@ class Test extends React.Component { return { title, headerTintColor: '#ffffff', - headerStyle: { backgroundColor: '#0288d1' }, - headerRight: - - , + headerStyle: { backgroundColor: '#1976D2' }, + headerRight: ( + + + + ), }; }; @@ -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 ( {Test.renderBanner({ status, time })} - - + + {testContextName} {description} - - - Test Error + + {message ? + Test Error Message + {message || 'None.'} + : null } + {stackTrace ? + Test Error Stack - {stackTrace || 'None.'} + {stackTrace || 'None.'} + + : null } + + + Test Code Preview - - - Test Code Preview - - - {beautify(removeLastLine(removeFirstLine(func.toString())), { indent_size: 4, break_chained_methods: true })} + {beautify(removeLastLine(removeFirstLine(func.toString())), { + indent_size: 4, + break_chained_methods: true, + })} - - + + ); } @@ -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 {