refactor: test output -> arrays (#39178)

This commit is contained in:
Oliver Eyton-Williams
2020-07-17 21:03:23 +02:00
committed by GitHub
parent bb019b2b0f
commit 7269894a86
5 changed files with 84 additions and 18 deletions

View File

@ -74,7 +74,7 @@ const propTypes = {
}), }),
initConsole: PropTypes.func.isRequired, initConsole: PropTypes.func.isRequired,
initTests: PropTypes.func.isRequired, initTests: PropTypes.func.isRequired,
output: PropTypes.string, output: PropTypes.arrayOf(PropTypes.string),
pageContext: PropTypes.shape({ pageContext: PropTypes.shape({
challengeMeta: PropTypes.shape({ challengeMeta: PropTypes.shape({
id: PropTypes.string, id: PropTypes.string,

View File

@ -3,18 +3,23 @@ import PropTypes from 'prop-types';
import sanitizeHtml from 'sanitize-html'; import sanitizeHtml from 'sanitize-html';
import './output.css'; import './output.css';
import { isEmpty } from 'lodash';
const propTypes = { const propTypes = {
defaultOutput: PropTypes.string, defaultOutput: PropTypes.string,
output: PropTypes.string output: PropTypes.arrayOf(PropTypes.string)
}; };
class Output extends Component { class Output extends Component {
render() { render() {
const { output, defaultOutput } = this.props; const { output, defaultOutput } = this.props;
const message = sanitizeHtml(output ? output : defaultOutput, { console.log('output', output);
const message = sanitizeHtml(
!isEmpty(output) ? output.join('\n') : defaultOutput,
{
allowedTags: ['b', 'i', 'em', 'strong', 'code', 'wbr'] allowedTags: ['b', 'i', 'em', 'strong', 'code', 'wbr']
}); }
);
return ( return (
<pre <pre
className='output-text' className='output-text'

View File

@ -46,7 +46,7 @@ const propTypes = {
initConsole: PropTypes.func.isRequired, initConsole: PropTypes.func.isRequired,
initTests: PropTypes.func.isRequired, initTests: PropTypes.func.isRequired,
isSignedIn: PropTypes.bool, isSignedIn: PropTypes.bool,
output: PropTypes.string, output: PropTypes.arrayOf(PropTypes.string),
pageContext: PropTypes.shape({ pageContext: PropTypes.shape({
challengeMeta: PropTypes.object challengeMeta: PropTypes.object
}), }),
@ -128,7 +128,7 @@ export class BackEnd extends Component {
}, },
pageContext: { challengeMeta } pageContext: { challengeMeta }
} = this.props; } = this.props;
initConsole(''); initConsole();
initTests(tests); initTests(tests);
updateChallengeMeta({ ...challengeMeta, title, challengeType }); updateChallengeMeta({ ...challengeMeta, title, challengeType });
challengeMounted(challengeMeta.id); challengeMounted(challengeMeta.id);

View File

@ -13,6 +13,7 @@ import { createExecuteChallengeSaga } from './execute-challenge-saga';
import { createCurrentChallengeSaga } from './current-challenge-saga'; import { createCurrentChallengeSaga } from './current-challenge-saga';
import { challengeTypes } from '../../../../utils/challengeTypes'; import { challengeTypes } from '../../../../utils/challengeTypes';
import { completedChallengesSelector } from '../../../redux'; import { completedChallengesSelector } from '../../../redux';
import { isEmpty } from 'lodash';
export const ns = 'challenge'; export const ns = 'challenge';
export const backendNS = 'backendChallenge'; export const backendNS = 'backendChallenge';
@ -30,11 +31,12 @@ const initialState = {
challengeType: -1 challengeType: -1
}, },
challengeTests: [], challengeTests: [],
consoleOut: '', consoleOut: [],
hasCompletedBlock: false, hasCompletedBlock: false,
inAccessibilityMode: false, inAccessibilityMode: false,
isCodeLocked: false, isCodeLocked: false,
isBuildEnabled: true, isBuildEnabled: true,
logsOut: [],
modal: { modal: {
completion: false, completion: false,
help: false, help: false,
@ -241,8 +243,6 @@ export const canFocusEditorSelector = state => state[ns].canFocusEditor;
export const inAccessibilityModeSelector = state => export const inAccessibilityModeSelector = state =>
state[ns].inAccessibilityMode; state[ns].inAccessibilityMode;
const MAX_LOGS_SIZE = 64 * 1024;
export const reducer = handleActions( export const reducer = handleActions(
{ {
[types.createFiles]: (state, { payload }) => ({ [types.createFiles]: (state, { payload }) => ({
@ -275,25 +275,25 @@ export const reducer = handleActions(
[types.initConsole]: (state, { payload }) => ({ [types.initConsole]: (state, { payload }) => ({
...state, ...state,
consoleOut: payload consoleOut: payload ? [payload] : []
}), }),
[types.updateConsole]: (state, { payload }) => ({ [types.updateConsole]: (state, { payload }) => ({
...state, ...state,
consoleOut: state.consoleOut + '\n' + payload consoleOut: state.consoleOut.concat(payload)
}), }),
[types.initLogs]: state => ({ [types.initLogs]: state => ({
...state, ...state,
logsOut: '' logsOut: []
}), }),
[types.updateLogs]: (state, { payload }) => ({ [types.updateLogs]: (state, { payload }) => ({
...state, ...state,
logsOut: (state.logsOut + '\n' + payload).slice(-MAX_LOGS_SIZE) logsOut: state.logsOut.concat(payload)
}), }),
[types.logsToConsole]: (state, { payload }) => ({ [types.logsToConsole]: (state, { payload }) => ({
...state, ...state,
consoleOut: consoleOut: isEmpty(state.logsOut)
state.consoleOut + ? state.consoleOut
(state.logsOut ? '\n' + payload + '\n' + state.logsOut : '') : state.consoleOut.concat(payload, state.logsOut)
}), }),
[types.updateChallengeMeta]: (state, { payload }) => ({ [types.updateChallengeMeta]: (state, { payload }) => ({
...state, ...state,
@ -321,7 +321,7 @@ export const reducer = handleActions(
text, text,
testString testString
})), })),
consoleOut: '' consoleOut: []
}), }),
[types.updateSolutionFormValues]: (state, { payload }) => ({ [types.updateSolutionFormValues]: (state, { payload }) => ({
...state, ...state,

View File

@ -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);
});
});
});