From 29641986abf8c82a7c9ff0c4b7e07ffde451d57d Mon Sep 17 00:00:00 2001 From: Oliver Eyton-Williams Date: Fri, 1 Nov 2019 13:02:23 +0100 Subject: [PATCH] fix: output console.logs as user types (DOM) Any console.logs inside script tags will be written to the fcc console as the user types. DOM challenges only. Also, DRYed out the main and test frame creation. --- .../redux/execute-challenge-saga.js | 19 ++++++++--- .../src/templates/Challenges/utils/build.js | 7 ++-- .../src/templates/Challenges/utils/frame.js | 32 ++++++++++--------- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/client/src/templates/Challenges/redux/execute-challenge-saga.js b/client/src/templates/Challenges/redux/execute-challenge-saga.js index 8b8136adc0..d68a77ca3b 100644 --- a/client/src/templates/Challenges/redux/execute-challenge-saga.js +++ b/client/src/templates/Challenges/redux/execute-challenge-saga.js @@ -1,4 +1,5 @@ import { + all, delay, put, select, @@ -124,20 +125,30 @@ function* previewChallengeSaga() { if (!isBuildEnabled) { return; } - const challengeData = yield select(challengeDataSelector); + + const consoleProxy = yield channel(); try { - yield put(initConsole('')); + yield put(initLogs()); + yield fork(logToConsole, consoleProxy); + const proxyLogger = args => consoleProxy.put(args); + const challengeData = yield select(challengeDataSelector); + // try to build even if there's no preview so build errors will be reported. - const ctx = yield buildChallengeData(challengeData); + const buildData = yield buildChallengeData(challengeData); // then only continue if there is a preview. if (!challengeHasPreview(challengeData)) { return; } const document = yield getContext('document'); - yield call(updatePreview, ctx, document); + yield call(updatePreview, buildData, document, proxyLogger); + // We don't want to see the default console, so we 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/utils/build.js b/client/src/templates/Challenges/utils/build.js index a33f03823e..07d5689df4 100644 --- a/client/src/templates/Challenges/utils/build.js +++ b/client/src/templates/Challenges/utils/build.js @@ -159,10 +159,13 @@ export function buildBackendChallenge({ url }) { }; } -export function updatePreview(buildData, document) { +export async function updatePreview(buildData, document, proxyLogger) { const { challengeType } = buildData; + if (challengeType === challengeTypes.html) { - createMainFramer(document)(buildData); + await new Promise(resolve => + createMainFramer(document, resolve, proxyLogger)(buildData) + ); } else { throw new Error(`Cannot show preview for challenge type ${challengeType}`); } diff --git a/client/src/templates/Challenges/utils/frame.js b/client/src/templates/Challenges/utils/frame.js index fe052b4bf7..63349e78d8 100644 --- a/client/src/templates/Challenges/utils/frame.js +++ b/client/src/templates/Challenges/utils/frame.js @@ -91,13 +91,7 @@ const buildProxyConsole = proxyLogger => ctx => { }; const initTestFrame = frameReady => ctx => { - const contentLoaded = new Promise(resolve => { - if (ctx.document.readyState === 'loading') { - ctx.document.addEventListener('DOMContentLoaded', resolve); - } else { - resolve(); - } - }); + const contentLoaded = new Promise(resolve => waitForFrame(resolve)(ctx)); contentLoaded.then(async () => { const { sources, loadEnzyme } = ctx; // default for classic challenges @@ -111,6 +105,15 @@ const initTestFrame = frameReady => ctx => { return ctx; }; +const waitForFrame = frameReady => ctx => { + if (ctx.document.readyState === 'loading') { + ctx.document.addEventListener('DOMContentLoaded', frameReady); + } else { + frameReady(); + } + return ctx; +}; + function writeToFrame(content, frame) { frame.open(); frame.write(content); @@ -123,18 +126,17 @@ const writeContentToFrame = ctx => { return ctx; }; -export const createMainFramer = document => - flow( - createFrame(document, mainId), - mountFrame(document), - writeContentToFrame - ); +export const createMainFramer = (document, frameReady, proxyConsole) => + createFramer(document, frameReady, proxyConsole, mainId, waitForFrame); export const createTestFramer = (document, frameReady, proxyConsole) => + createFramer(document, frameReady, proxyConsole, testId, initTestFrame); + +const createFramer = (document, frameReady, proxyConsole, id, init) => flow( - createFrame(document, testId), + createFrame(document, id), mountFrame(document), writeContentToFrame, buildProxyConsole(proxyConsole), - initTestFrame(frameReady) + init(frameReady) );