diff --git a/client/src/templates/Challenges/rechallenge/transformers.js b/client/src/templates/Challenges/rechallenge/transformers.js
index 1618c8ba4f..bb80a89ae0 100644
--- a/client/src/templates/Challenges/rechallenge/transformers.js
+++ b/client/src/templates/Challenges/rechallenge/transformers.js
@@ -59,7 +59,6 @@ function tryTransform(wrap = identity) {
return function transformWrappedPoly(source) {
const result = attempt(wrap, source);
if (isError(result)) {
- console.error(result);
// note(Bouncey): Error thrown here to collapse the build pipeline
// At the minute, it will not bubble up
// We collapse the pipeline so the app doesn't fall over trying
diff --git a/client/src/templates/Challenges/redux/execute-challenge-saga.js b/client/src/templates/Challenges/redux/execute-challenge-saga.js
index a348776b48..0541f86900 100644
--- a/client/src/templates/Challenges/redux/execute-challenge-saga.js
+++ b/client/src/templates/Challenges/redux/execute-challenge-saga.js
@@ -50,7 +50,7 @@ export function* executeChallengeSaga() {
);
yield put(updateTests(tests));
- yield fork(logToConsole, consoleProxy);
+ yield fork(takeEveryLog, consoleProxy);
const proxyLogger = args => consoleProxy.put(args);
const challengeData = yield select(challengeDataSelector);
@@ -59,7 +59,7 @@ export function* executeChallengeSaga() {
const testRunner = yield call(
getTestRunner,
buildData,
- proxyLogger,
+ { proxyLogger },
document
);
const testResults = yield executeTests(testRunner, tests);
@@ -74,19 +74,28 @@ export function* executeChallengeSaga() {
}
}
-function* logToConsole(channel) {
+function* takeEveryLog(channel) {
+ // TODO: move all stringifying and escaping into the reducer so there is a
+ // single place responsible for formatting the logs.
yield takeEvery(channel, function*(args) {
yield put(updateLogs(escape(args)));
});
}
+function* takeEveryConsole(channel) {
+ // TODO: move all stringifying and escaping into the reducer so there is a
+ // single place responsible for formatting the console output.
+ yield takeEvery(channel, function*(args) {
+ yield put(updateConsole(escape(args)));
+ });
+}
+
function* buildChallengeData(challengeData) {
try {
return yield call(buildChallenge, challengeData);
} catch (e) {
- yield put(disableBuildOnError(e));
- // eslint-disable-next-line no-throw-literal
- throw 'Build failed';
+ yield put(disableBuildOnError());
+ throw e;
}
}
@@ -136,30 +145,40 @@ function* previewChallengeSaga() {
return;
}
+ const logProxy = yield channel();
const consoleProxy = yield channel();
+ const proxyLogger = args => logProxy.put(args);
+ const proxyUpdateConsole = args => consoleProxy.put(args);
try {
yield put(initLogs());
- yield fork(logToConsole, consoleProxy);
- const proxyLogger = args => consoleProxy.put(args);
- const challengeData = yield select(challengeDataSelector);
+ yield fork(takeEveryLog, logProxy);
+ yield fork(takeEveryConsole, consoleProxy);
+ const challengeData = yield select(challengeDataSelector);
const buildData = yield buildChallengeData(challengeData);
// evaluate the user code in the preview frame or in the worker
if (challengeHasPreview(challengeData)) {
const document = yield getContext('document');
- yield call(updatePreview, buildData, document, proxyLogger);
+ yield call(updatePreview, buildData, document, {
+ proxyLogger,
+ proxyUpdateConsole
+ });
} else if (isJavaScriptChallenge(challengeData)) {
- const runUserCode = getTestRunner(buildData, proxyLogger);
+ const runUserCode = getTestRunner(buildData, { proxyLogger });
// without a testString the testRunner just evaluates the user's code
yield call(runUserCode, null, 5000);
}
+ } catch (err) {
+ console.log(err);
+ yield put(updateLogs(escape(err)));
+ } finally {
+ // consoleProxy is left open to record any errors triggered by user
+ // input.
+ logProxy.close();
+
// To avoid seeing the default console, initialise and output in one call.
yield all([put(initConsole('')), put(logsToConsole('// console output'))]);
- } catch (err) {
- console.error(err);
- } finally {
- consoleProxy.close();
}
}
diff --git a/client/src/templates/Challenges/redux/index.js b/client/src/templates/Challenges/redux/index.js
index cf9228df0f..dc075108f7 100644
--- a/client/src/templates/Challenges/redux/index.js
+++ b/client/src/templates/Challenges/redux/index.js
@@ -330,9 +330,8 @@ export const reducer = handleActions(
isBuildEnabled: true,
isCodeLocked: false
}),
- [types.disableBuildOnError]: (state, { payload }) => ({
+ [types.disableBuildOnError]: state => ({
...state,
- consoleOut: state.consoleOut + ' \n' + payload,
isBuildEnabled: false
}),
diff --git a/client/src/templates/Challenges/utils/build.js b/client/src/templates/Challenges/utils/build.js
index 10300ad72a..cc2529c18f 100644
--- a/client/src/templates/Challenges/utils/build.js
+++ b/client/src/templates/Challenges/utils/build.js
@@ -85,7 +85,7 @@ const testRunners = {
[challengeTypes.html]: getDOMTestRunner,
[challengeTypes.backend]: getDOMTestRunner
};
-export function getTestRunner(buildData, proxyLogger, document) {
+export function getTestRunner(buildData, { proxyLogger }, document) {
const { challengeType } = buildData;
const testRunner = testRunners[challengeType];
if (testRunner) {
diff --git a/client/src/templates/Challenges/utils/frame.js b/client/src/templates/Challenges/utils/frame.js
index 63349e78d8..a7f5d3cd83 100644
--- a/client/src/templates/Challenges/utils/frame.js
+++ b/client/src/templates/Challenges/utils/frame.js
@@ -11,17 +11,14 @@ const testId = 'fcc-test-frame';
// append to the current challenge url
// this also allows in-page anchors to work properly
// rather than load another instance of the learn
-//
-// if an error occurs during initialization
-// the __err prop will be set
-// This is then picked up in client/frame-runner.js during
-// runTestsInTestFrame below
+
+// window.onerror is added here to catch any errors thrown during the building
+// of the frame.
const createHeader = (id = mainId) => `