fix: allow log in testString, restrict test errors

Console logs from testString get reported and test errors are sent to
the dev console (JS).

challenge building is only attempted if there is a build function to do
so.

Various functions have been renamed to better reflect what they do.
This commit is contained in:
Oliver Eyton-Williams
2019-11-19 12:46:48 +01:00
committed by mrugesh
parent 9194b7731b
commit febba792e7
4 changed files with 32 additions and 22 deletions

View File

@ -38,7 +38,7 @@ const __utils = (() => {
self.postMessage(data); self.postMessage(data);
} }
function logToBoth(err) { function log(err) {
if (!(err instanceof chai.AssertionError)) { if (!(err instanceof chai.AssertionError)) {
// report to both the browser and the fcc consoles, discarding the // report to both the browser and the fcc consoles, discarding the
// stack trace via toString as it only useful to debug the site, not a // stack trace via toString as it only useful to debug the site, not a
@ -47,14 +47,14 @@ const __utils = (() => {
} }
} }
const toggleLogging = on => { const toggleProxyLogger = on => {
self.console.log = on ? proxyLog : () => {}; self.console.log = on ? proxyLog : oldLog;
}; };
return { return {
postResult, postResult,
logToBoth, log,
toggleLogging toggleProxyLogger
}; };
})(); })();
@ -66,7 +66,8 @@ self.onmessage = async e => {
// Fake Deep Equal dependency // Fake Deep Equal dependency
const DeepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b); const DeepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);
__utils.toggleLogging(e.data.firstTest); // User code errors should be reported, but only once:
__utils.toggleProxyLogger(e.data.firstTest);
/* eslint-enable no-unused-vars */ /* eslint-enable no-unused-vars */
try { try {
let testResult; let testResult;
@ -84,7 +85,7 @@ self.onmessage = async e => {
throw err; throw err;
} }
// log build errors // log build errors
__utils.logToBoth(err); __utils.log(err);
// the tests may not require working code, so they are evaluated even if // the tests may not require working code, so they are evaluated even if
// the user code does not get executed. // the user code does not get executed.
testResult = eval(e.data.testString); testResult = eval(e.data.testString);
@ -97,10 +98,11 @@ self.onmessage = async e => {
pass: true pass: true
}); });
} catch (err) { } catch (err) {
// report errors that happened during testing, so the user learns of // Errors from testing go to the browser console only.
// execution errors and not just build errors. __utils.toggleProxyLogger(false);
__utils.toggleLogging(true); // Report execution errors in case user code has errors that are only
__utils.logToBoth(err); // uncovered during testing.
__utils.log(err);
// postResult flushes the logs and must be called after logging is finished. // postResult flushes the logs and must be called after logging is finished.
__utils.postResult({ __utils.postResult({
err: { err: {

View File

@ -26,6 +26,7 @@ import {
import { import {
buildChallenge, buildChallenge,
canBuildChallenge,
getTestRunner, getTestRunner,
challengeHasPreview, challengeHasPreview,
updatePreview, updatePreview,
@ -153,15 +154,17 @@ function* previewChallengeSaga() {
yield fork(takeEveryConsole, logProxy); yield fork(takeEveryConsole, logProxy);
const challengeData = yield select(challengeDataSelector); const challengeData = yield select(challengeDataSelector);
const buildData = yield buildChallengeData(challengeData); if (canBuildChallenge(challengeData)) {
// evaluate the user code in the preview frame or in the worker const buildData = yield buildChallengeData(challengeData);
if (challengeHasPreview(challengeData)) { // evaluate the user code in the preview frame or in the worker
const document = yield getContext('document'); if (challengeHasPreview(challengeData)) {
yield call(updatePreview, buildData, document, proxyLogger); const document = yield getContext('document');
} else if (isJavaScriptChallenge(challengeData)) { yield call(updatePreview, buildData, document, proxyLogger);
const runUserCode = getTestRunner(buildData, { proxyLogger }); } else if (isJavaScriptChallenge(challengeData)) {
// without a testString the testRunner just evaluates the user's code const runUserCode = getTestRunner(buildData, { proxyLogger });
yield call(runUserCode, null, 5000); // without a testString the testRunner just evaluates the user's code
yield call(runUserCode, null, 5000);
}
} }
} catch (err) { } catch (err) {
console.log(err); console.log(err);

View File

@ -71,6 +71,11 @@ const buildFunctions = {
[challengeTypes.backEndProject]: buildBackendChallenge [challengeTypes.backEndProject]: buildBackendChallenge
}; };
export function canBuildChallenge(challengeData) {
const { challengeType } = challengeData;
return buildFunctions.hasOwnProperty(challengeType);
}
export async function buildChallenge(challengeData) { export async function buildChallenge(challengeData) {
const { challengeType } = challengeData; const { challengeType } = challengeData;
let build = buildFunctions[challengeType]; let build = buildFunctions[challengeType];

View File

@ -104,8 +104,8 @@ const initTestFrame = frameReady => ctx => {
const initMainFrame = (frameReady, proxyLogger) => ctx => { const initMainFrame = (frameReady, proxyLogger) => ctx => {
waitForFrame(ctx).then(() => { waitForFrame(ctx).then(() => {
// Overwriting the onerror added by createHeader to catch any errors thrown // Overwriting the onerror added by createHeader to catch any errors thrown
// after the frame is ready. It has to be overwritten, as proxyUpdateConsole // after the frame is ready. It has to be overwritten, as proxyLogger cannot
// cannot be added as part of createHeader. // be added as part of createHeader.
ctx.window.onerror = function(msg) { ctx.window.onerror = function(msg) {
console.log(msg); console.log(msg);
if (proxyLogger) { if (proxyLogger) {