diff --git a/client/src/client/workers/test-evaluator.js b/client/src/client/workers/test-evaluator.js index f1e3d5f7ec..ed44a8ac96 100644 --- a/client/src/client/workers/test-evaluator.js +++ b/client/src/client/workers/test-evaluator.js @@ -3,12 +3,11 @@ import '@babel/polyfill'; const oldLog = self.console.log.bind(self.console); self.console.log = function proxyConsole(...args) { - self.__logs = [...self.__logs, ...args]; + self.postMessage({ type: 'LOG', data: String(args) }); return oldLog(...args); }; onmessage = async e => { - self.__logs = []; const { script: __test, code } = e.data; /* eslint-disable no-unused-vars */ const assert = chai.assert; @@ -21,14 +20,13 @@ onmessage = async e => { if (typeof testResult === 'function') { await testResult(() => code); } - self.postMessage({ pass: true, logs: self.__logs.map(String) }); + self.postMessage({ pass: true }); } catch (err) { self.postMessage({ err: { message: err.message, stack: err.stack - }, - logs: self.__logs.map(String) + } }); if (!(err instanceof chai.AssertionError)) { console.error(err); diff --git a/client/src/templates/Challenges/redux/execute-challenge-saga.js b/client/src/templates/Challenges/redux/execute-challenge-saga.js index b2e38edc97..8c3b43dbca 100644 --- a/client/src/templates/Challenges/redux/execute-challenge-saga.js +++ b/client/src/templates/Challenges/redux/execute-challenge-saga.js @@ -67,15 +67,29 @@ function* ExecuteChallengeSaga() { } } +function* logToConsole(channel) { + yield takeEvery(channel, function*(args) { + yield put(updateLogs(args)); + }); +} + function* ExecuteJSChallengeSaga() { const files = yield select(challengeFilesSelector); const { code, solution } = yield call(buildJSFromFiles, files); + const consoleProxy = yield channel(); + yield fork(logToConsole, consoleProxy); + const log = args => consoleProxy.put(args); + testWorker.on('LOG', log); + const testResults = yield call(executeTests, { testRunner: testWorker, code, solution }); + + testWorker.remove('LOG', log); + consoleProxy.close(); return testResults; } @@ -86,12 +100,6 @@ function createTestFrame(state, ctx, proxyLogger) { }).then(() => console.log('Frame ready')); } -function* logToConsole(channel) { - yield takeEvery(channel, function*(args) { - yield put(updateLogs(args)); - }); -} - function* ExecuteDOMChallengeSaga() { const state = yield select(); const ctx = yield call(buildFromFiles, state); @@ -166,14 +174,11 @@ function* executeTests({ testRunner, code = '', solution = '' }) { for (const { text, testString } of tests) { const newTest = { text, testString }; try { - const { pass, err, logs = [] } = yield call( + const { pass, err } = yield call( testRunner.execute, { script: solution + '\n' + testString, code }, testTimeout ); - for (const log of logs) { - yield put(updateLogs(log)); - } if (pass) { newTest.pass = true; } else { diff --git a/client/src/templates/Challenges/utils/worker-executor.js b/client/src/templates/Challenges/utils/worker-executor.js index 838beda2d4..e79dc26e18 100644 --- a/client/src/templates/Challenges/utils/worker-executor.js +++ b/client/src/templates/Challenges/utils/worker-executor.js @@ -2,6 +2,7 @@ export default class WorkerExecutor { constructor(workerName) { this.workerName = workerName; this.worker = null; + this.observers = {}; this.execute = this.execute.bind(this); this.killWorker = this.killWorker.bind(this); @@ -36,6 +37,13 @@ export default class WorkerExecutor { // Handle result worker.onmessage = e => { + if (e.data && e.data.type) { + const observers = this.observers[e.data.type] || []; + for (const observer of observers) { + observer(e.data.data); + } + return; + } clearTimeout(timeoutId); resolve(e.data); }; @@ -46,4 +54,18 @@ export default class WorkerExecutor { }; }); } + + on(type, callback) { + const observers = this.observers[type] || []; + observers.push(callback); + this.observers[type] = observers; + } + + remove(type, callback) { + const observers = this.observers[type] || []; + const index = observers.indexOf(callback); + if (index !== -1) { + observers.splice(index, 1); + } + } }