diff --git a/client/src/templates/Challenges/classic/Show.js b/client/src/templates/Challenges/classic/Show.js index 259b192bef..4f8f152a42 100644 --- a/client/src/templates/Challenges/classic/Show.js +++ b/client/src/templates/Challenges/classic/Show.js @@ -74,7 +74,7 @@ const propTypes = { }), initConsole: PropTypes.func.isRequired, initTests: PropTypes.func.isRequired, - output: PropTypes.string, + output: PropTypes.arrayOf(PropTypes.string), pageContext: PropTypes.shape({ challengeMeta: PropTypes.shape({ id: PropTypes.string, diff --git a/client/src/templates/Challenges/components/Output.js b/client/src/templates/Challenges/components/Output.js index 8600a4c21f..8f3aba840d 100644 --- a/client/src/templates/Challenges/components/Output.js +++ b/client/src/templates/Challenges/components/Output.js @@ -3,18 +3,23 @@ import PropTypes from 'prop-types'; import sanitizeHtml from 'sanitize-html'; import './output.css'; +import { isEmpty } from 'lodash'; const propTypes = { defaultOutput: PropTypes.string, - output: PropTypes.string + output: PropTypes.arrayOf(PropTypes.string) }; class Output extends Component { render() { const { output, defaultOutput } = this.props; - const message = sanitizeHtml(output ? output : defaultOutput, { - allowedTags: ['b', 'i', 'em', 'strong', 'code', 'wbr'] - }); + console.log('output', output); + const message = sanitizeHtml( + !isEmpty(output) ? output.join('\n') : defaultOutput, + { + allowedTags: ['b', 'i', 'em', 'strong', 'code', 'wbr'] + } + ); return (
state[ns].canFocusEditor; export const inAccessibilityModeSelector = state => state[ns].inAccessibilityMode; -const MAX_LOGS_SIZE = 64 * 1024; - export const reducer = handleActions( { [types.createFiles]: (state, { payload }) => ({ @@ -275,25 +275,25 @@ export const reducer = handleActions( [types.initConsole]: (state, { payload }) => ({ ...state, - consoleOut: payload + consoleOut: payload ? [payload] : [] }), [types.updateConsole]: (state, { payload }) => ({ ...state, - consoleOut: state.consoleOut + '\n' + payload + consoleOut: state.consoleOut.concat(payload) }), [types.initLogs]: state => ({ ...state, - logsOut: '' + logsOut: [] }), [types.updateLogs]: (state, { payload }) => ({ ...state, - logsOut: (state.logsOut + '\n' + payload).slice(-MAX_LOGS_SIZE) + logsOut: state.logsOut.concat(payload) }), [types.logsToConsole]: (state, { payload }) => ({ ...state, - consoleOut: - state.consoleOut + - (state.logsOut ? '\n' + payload + '\n' + state.logsOut : '') + consoleOut: isEmpty(state.logsOut) + ? state.consoleOut + : state.consoleOut.concat(payload, state.logsOut) }), [types.updateChallengeMeta]: (state, { payload }) => ({ ...state, @@ -321,7 +321,7 @@ export const reducer = handleActions( text, testString })), - consoleOut: '' + consoleOut: [] }), [types.updateSolutionFormValues]: (state, { payload }) => ({ ...state, diff --git a/cypress/integration/learn/challenges/output.js b/cypress/integration/learn/challenges/output.js new file mode 100644 index 0000000000..03fb0934ca --- /dev/null +++ b/cypress/integration/learn/challenges/output.js @@ -0,0 +1,61 @@ +/* global cy */ + +const selectors = { + defaultOutput: '.output-text', + hotkeys: '.default-layout > div', + runTestsButton: 'button:contains("Run the Tests")' +}; + +const locations = { + index: + '/learn/responsive-web-design/basic-html-and-html5/' + + 'say-hello-to-html-elements' +}; + +const defaultOutput = ` +/** +* Your test output will go here. +*/`; + +const runningOutput = '// running tests'; +const finishedOutput = '// tests completed'; + +describe('Classic challenge', function() { + it('renders', () => { + cy.visit(locations.index); + + cy.title().should( + 'eq', + 'Learn Basic HTML and HTML5: Say Hello to HTML Elements |' + + ' freeCodeCamp.org' + ); + }); + + it('renders the default output text', () => { + cy.visit(locations.index); + cy.get(selectors.defaultOutput).contains(defaultOutput); + }); + + it('shows test output when the tests are run', () => { + cy.visit(locations.index); + cy.get(selectors.runTestsButton) + .click() + .then(() => { + cy.get(selectors.defaultOutput) + .contains(runningOutput) + .contains(finishedOutput); + }); + }); + + it('shows test output when the tests are triggered by the keyboard', () => { + cy.visit(locations.index); + cy.get(selectors.hotkeys) + .focus() + .type('{ctrl}{enter}') + .then(() => { + cy.get(selectors.defaultOutput) + .contains(runningOutput) + .contains(finishedOutput); + }); + }); +});