diff --git a/packages/learn/src/templates/Challenges/redux/execute-challenge-epic.js b/packages/learn/src/templates/Challenges/redux/execute-challenge-epic.js index 49ce784783..64d2d2085b 100644 --- a/packages/learn/src/templates/Challenges/redux/execute-challenge-epic.js +++ b/packages/learn/src/templates/Challenges/redux/execute-challenge-epic.js @@ -25,6 +25,9 @@ import { challengeTestsSelector, initConsole, updateConsole, + initLogs, + updateLogs, + logsToConsole, checkChallenge, updateTests, disableJSOnError, @@ -72,7 +75,13 @@ function executeChallengeEpic(action$, { getState }, { document }) { filter(Boolean), switchMap(() => { const frameReady = new Subject(); - const frameTests = createTestFramer(document, getState, frameReady); + const proxyLogger = new Subject(); + const frameTests = createTestFramer( + document, + getState, + frameReady, + proxyLogger + ); const challengeResults = frameReady.pipe( pluck('checkChallengePayload'), map(checkChallengePayload => ({ @@ -82,6 +91,7 @@ function executeChallengeEpic(action$, { getState }, { document }) { switchMap(({ checkChallengePayload, tests }) => { const postTests = of( updateConsole('// tests completed'), + logsToConsole('// console output'), checkChallenge(checkChallengePayload) ).pipe(delay(250)); return runTestsInTestFrame(document, tests).pipe( @@ -104,23 +114,24 @@ function executeChallengeEpic(action$, { getState }, { document }) { switchMap(() => { const state = getState(); const { challengeType } = challengeMetaSelector(state); - if (challengeType === backend) { - return buildBackendChallenge(state).pipe( - tap(frameTests), - ignoreElements(), - startWith(initConsole('// running test')), - catchError(err => of(disableJSOnError(err))) - ); - } - return buildFromFiles(state, false).pipe( + const build = + challengeType === backend + ? buildBackendChallenge(state) + : buildFromFiles(state, true); + return build.pipe( tap(frameTests), ignoreElements(), - startWith(initConsole('// running test')), + startWith(initLogs()), + startWith(initConsole('// running tests')), catchError(err => of(disableJSOnError(err))) ); }) ); - return merge(buildAndFrameChallenge, challengeResults); + return merge( + buildAndFrameChallenge, + challengeResults, + proxyLogger.map(updateLogs) + ); }) ); } diff --git a/packages/learn/src/templates/Challenges/redux/index.js b/packages/learn/src/templates/Challenges/redux/index.js index 8703b28250..2318ebab56 100644 --- a/packages/learn/src/templates/Challenges/redux/index.js +++ b/packages/learn/src/templates/Challenges/redux/index.js @@ -48,6 +48,7 @@ export const types = createTypes( 'createQuestion', 'initTests', 'initConsole', + 'initLogs', 'updateConsole', 'updateChallengeMeta', 'updateFile', @@ -55,6 +56,9 @@ export const types = createTypes( 'updateProjectFormValues', 'updateSuccessMessage', 'updateTests', + 'updateLogs', + + 'logsToConsole', 'lockCode', 'unlockCode', @@ -95,15 +99,19 @@ export const initTests = createAction(types.initTests); export const updateTests = createAction(types.updateTests); export const initConsole = createAction(types.initConsole); +export const initLogs = createAction(types.initLogs); export const updateChallengeMeta = createAction(types.updateChallengeMeta); export const updateFile = createAction(types.updateFile); export const updateConsole = createAction(types.updateConsole); +export const updateLogs = createAction(types.updateLogs); export const updateJSEnabled = createAction(types.updateJSEnabled); export const updateProjectFormValues = createAction( types.updateProjectFormValues ); export const updateSuccessMessage = createAction(types.updateSuccessMessage); +export const logsToConsole = createAction(types.logsToConsole); + export const lockCode = createAction(types.lockCode); export const unlockCode = createAction(types.unlockCode); export const disableJSOnError = createAction(types.disableJSOnError); @@ -174,7 +182,22 @@ export const reducer = handleActions( ...state, consoleOut: state.consoleOut + '\n' + payload }), - + [types.initLogs]: state => ({ + ...state, + logsOut: [] + }), + [types.updateLogs]: (state, { payload }) => ({ + ...state, + logsOut: [...state.logsOut, payload] + }), + [types.logsToConsole]: (state, { payload }) => ({ + ...state, + consoleOut: + state.consoleOut + + (state.logsOut.length + ? '\n' + payload + '\n' + state.logsOut.join('\n') + : '') + }), [types.updateChallengeMeta]: (state, { payload }) => ({ ...state, challengeMeta: { ...payload } diff --git a/packages/learn/src/templates/Challenges/utils/frame.js b/packages/learn/src/templates/Challenges/utils/frame.js index 972bce47e8..096324cffe 100644 --- a/packages/learn/src/templates/Challenges/utils/frame.js +++ b/packages/learn/src/templates/Challenges/utils/frame.js @@ -140,11 +140,12 @@ export const createMainFramer = (document, getState, proxyLogger) => writeContentToFrame ); -export const createTestFramer = (document, getState, frameReady) => +export const createTestFramer = (document, getState, frameReady, proxyLogger) => flow( createFrame(document, getState, testId), mountFrame(document), addDepsToDocument, writeTestDepsToDocument(frameReady), + buildProxyConsole(proxyLogger), writeContentToFrame );