diff --git a/client/less/challenge.less b/client/less/challenge.less
index 2302876a9e..ca77c61eb8 100644
--- a/client/less/challenge.less
+++ b/client/less/challenge.less
@@ -117,17 +117,23 @@
color: @gray-light;
}
-.big-error-icon {
+.big-icon {
font-size: 30px;
- color: @brand-danger;
- top:50%;
}
-.big-success-icon {
- font-size: 30px;
+.error-icon {
+ color: @brand-danger;
+ top: 50%;
+}
+
+.success-icon {
color: @brand-primary;
}
+.refresh-icon {
+ color: @alert-info-bg;
+}
+
iframe.iphone {
border: none;
@media(min-width: 992px) {
diff --git a/common/app/routes/challenges/components/Challenge.jsx b/common/app/routes/challenges/components/Challenge.jsx
index 35196a4d70..a1c3ad4b9d 100644
--- a/common/app/routes/challenges/components/Challenge.jsx
+++ b/common/app/routes/challenges/components/Challenge.jsx
@@ -11,13 +11,14 @@ import { challengeSelector } from '../redux/selectors';
const mapStateToProps = createSelector(
challengeSelector,
+ state => state.challengesApp.tests,
state => state.challengesApp.files,
state => state.challengesApp.path,
- ({ challenge, showPreview, mode }, files, path) => ({
- content: files[path] && files[path].contents,
- challenge,
+ ({ challenge, showPreview, mode }, tests, files = {}, path = '') => ({
+ content: files[path] && files[path].contents || '',
showPreview,
- mode
+ mode,
+ tests
})
);
@@ -26,11 +27,8 @@ export class Challenge extends PureComponent {
static propTypes = {
showPreview: PropTypes.bool,
- challenge: PropTypes.object
- };
-
- static defaultProps = {
- challenge: {}
+ content: PropTypes.string,
+ mode: PropTypes.string
};
renderPreview(showPreview) {
@@ -47,13 +45,13 @@ export class Challenge extends PureComponent {
}
render() {
- const { content, challenge, mode, showPreview } = this.props;
+ const { content, mode, showPreview } = this.props;
return (
-
+
state.app.windowHeight,
state => state.app.navHeight,
- (windowHeight, navHeight) => ({ height: windowHeight - navHeight - 20 })
+ state => state.challengesApp.tests,
+ state => state.challengesApp.refresh,
+ (
+ { challenge: { title, description } = {} },
+ windowHeight,
+ navHeight,
+ tests,
+ refresh
+ ) => ({
+ title,
+ description,
+ height: windowHeight - navHeight - 20,
+ tests,
+ refresh
+ })
);
export class SidePanel extends PureComponent {
@@ -24,14 +40,13 @@ export class SidePanel extends PureComponent {
static propTypes = {
description: PropTypes.arrayOf(PropTypes.string),
- height: PropTypes.number
+ height: PropTypes.number,
+ tests: PropTypes.arrayOf(PropTypes.object),
+ title: PropTypes.string,
+ refresh: PropTypes.bool
};
- static defaultProps = {
- description: [ 'Happy Coding!' ]
- };
-
- renderDescription(description, descriptionRegex) {
+ renderDescription(description = [ 'Happy Coding!' ], descriptionRegex) {
return description.map((line, index) => {
if (descriptionRegex.test(line)) {
return (
@@ -50,7 +65,7 @@ export class SidePanel extends PureComponent {
}
render() {
- const { title, description, height } = this.props;
+ const { title, description, height, tests = [], refresh } = this.props;
const style = {
overflowX: 'hidden',
overflowY: 'auto'
@@ -64,7 +79,7 @@ export class SidePanel extends PureComponent {
style={ style }>
- { title }
+ { title || 'Happy Coding!' }
@@ -78,7 +93,9 @@ export class SidePanel extends PureComponent {
-
+
);
}
diff --git a/common/app/routes/challenges/components/Test-Suite.jsx b/common/app/routes/challenges/components/Test-Suite.jsx
index 17e69353f0..9599e3352a 100644
--- a/common/app/routes/challenges/components/Test-Suite.jsx
+++ b/common/app/routes/challenges/components/Test-Suite.jsx
@@ -1,42 +1,23 @@
import React, { PropTypes } from 'react';
+import classnames from 'classnames';
import PureComponent from 'react-pure-render/component';
-
import { Col, Row } from 'react-bootstrap';
-/* eslint-disable max-len, quotes */
-const tests = [{
- err: null,
- text: "assert((function(z){if(z.hasOwnProperty(\"name\") && z.name !== undefined && typeof z.name === \"string\"){return true;}else{return false;}})(myDog), 'message:
myDog
should contain the property
name
and it should be a
string
.');"
- }, {
- err: "message",
- text: "assert((function(z){if(z.hasOwnProperty(\"legs\") && z.legs !== undefined && typeof z.legs === \"number\"){return true;}else{return false;}})(myDog), 'message:
myDog
should contain the property
legs
and it should be a
number
.');"
- }, {
- err: "message",
- text: "assert((function(z){if(z.hasOwnProperty(\"tails\") && z.tails !== undefined && typeof z.tails === \"number\"){return true;}else{return false;}})(myDog), 'message:
myDog
should contain the property
tails
and it should be a
number
.');"
- }, {
- err: "message",
- text: "assert((function(z){if(z.hasOwnProperty(\"friends\") && z.friends !== undefined && Array.isArray(z.friends)){return true;}else{return false;}})(myDog), 'message:
myDog
should contain the property
friends
and it should be an
array
.');"
- }, {
- err: "message",
- text: "assert((function(z){return Object.keys(z).length === 4;})(myDog), 'message:
myDog
should only contain all the given properties.');"
-}];
-/* eslint-enable max-len, quotes */
-
export default class extends PureComponent {
static displayName = 'TestSuite';
static proptTypes = {
- tests: PropTypes.arrayOf(PropTypes.object)
+ tests: PropTypes.arrayOf(PropTypes.object),
+ refresh: PropTypes.bool
};
- static defaultProps = {
- tests: tests
- };
-
- renderTests(tests = []) {
+ renderTests(tests = [], refresh = false) {
return tests.map(({ err, text = '' }, index)=> {
- var iconClass = err ?
- 'ion-close-circled big-error-icon' :
- 'ion-checkmark-circled big-success-icon';
+ const iconClass = classnames({
+ 'big-icon': true,
+ 'ion-close-circled error-icon': !refresh && !err,
+ 'ion-checkmark-circled success-icon': !refresh && err,
+ 'ion-refresh refresh-icon': refresh
+ });
return (
);
@@ -56,12 +35,12 @@ export default class extends PureComponent {
}
render() {
- const { tests } = this.props;
+ const { tests, refresh } = this.props;
return (
- { this.renderTests(tests) }
+ { this.renderTests(tests, refresh) }
);
}
diff --git a/common/app/routes/challenges/redux/reducer.js b/common/app/routes/challenges/redux/reducer.js
index e58113dc1c..cd73838df1 100644
--- a/common/app/routes/challenges/redux/reducer.js
+++ b/common/app/routes/challenges/redux/reducer.js
@@ -3,7 +3,7 @@ import { createPoly } from '../../../../utils/polyvinyl';
import types from './types';
import { BONFIRE, HTML, JS } from '../../../utils/challengeTypes';
-import { buildSeed, getPath } from '../utils';
+import { buildSeed, createTests, getPath } from '../utils';
const initialState = {
challenge: '',
@@ -22,8 +22,10 @@ const mainReducer = handleActions(
}),
[types.updateCurrentChallenge]: (state, { payload: challenge }) => ({
...state,
+ refresh: true,
challenge: challenge.dashedName,
- path: getPath(challenge)
+ path: getPath(challenge),
+ tests: createTests(challenge)
}),
// map
diff --git a/common/app/routes/challenges/utils.js b/common/app/routes/challenges/utils.js
index 9959f48455..bde8590743 100644
--- a/common/app/routes/challenges/utils.js
+++ b/common/app/routes/challenges/utils.js
@@ -1,5 +1,5 @@
import { compose } from 'redux';
-import { HTML, JS } from '../../utils/challengeTypes';
+import { BONFIRE, HTML, JS } from '../../utils/challengeTypes';
export function encodeScriptTags(value) {
return value
@@ -41,10 +41,17 @@ export function buildSeed({ challengeSeed = [] } = {}) {
const pathsMap = {
[HTML]: 'main.html',
- [JS]: 'main.js'
+ [JS]: 'main.js',
+ [BONFIRE]: 'main.js'
};
export function getPath({ challengeType }) {
return pathsMap[challengeType] || 'main';
}
+export function createTests({ tests = [] }) {
+ return tests
+ .map(test => ({
+ text: test.split('message: ').pop().replace(/\'\);/g, '')
+ }));
+}