fix: remove state dependency from frame creation
This commit is contained in:
@ -34,10 +34,7 @@ import {
|
|||||||
runTestInTestFrame
|
runTestInTestFrame
|
||||||
} from '../utils/frame.js';
|
} from '../utils/frame.js';
|
||||||
|
|
||||||
const testWorker = createWorker('test-evaluator');
|
export function* executeChallengeSaga() {
|
||||||
const testTimeout = 5000;
|
|
||||||
|
|
||||||
function* ExecuteChallengeSaga() {
|
|
||||||
const consoleProxy = yield channel();
|
const consoleProxy = yield channel();
|
||||||
try {
|
try {
|
||||||
const { js, bonfire, backend } = challengeTypes;
|
const { js, bonfire, backend } = challengeTypes;
|
||||||
@ -46,6 +43,7 @@ function* ExecuteChallengeSaga() {
|
|||||||
yield put(initLogs());
|
yield put(initLogs());
|
||||||
yield put(initConsole('// running tests'));
|
yield put(initConsole('// running tests'));
|
||||||
yield fork(logToConsole, consoleProxy);
|
yield fork(logToConsole, consoleProxy);
|
||||||
|
const proxyLogger = args => consoleProxy.put(args);
|
||||||
|
|
||||||
const state = yield select();
|
const state = yield select();
|
||||||
|
|
||||||
@ -53,13 +51,13 @@ function* ExecuteChallengeSaga() {
|
|||||||
switch (challengeType) {
|
switch (challengeType) {
|
||||||
case js:
|
case js:
|
||||||
case bonfire:
|
case bonfire:
|
||||||
testResults = yield ExecuteJSChallengeSaga(state, consoleProxy);
|
testResults = yield executeJSChallengeSaga(state, proxyLogger);
|
||||||
break;
|
break;
|
||||||
case backend:
|
case backend:
|
||||||
testResults = yield ExecuteBackendChallengeSaga(state, consoleProxy);
|
testResults = yield executeBackendChallengeSaga(state, proxyLogger);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
testResults = yield ExecuteDOMChallengeSaga(state, consoleProxy);
|
testResults = yield executeDOMChallengeSaga(state, proxyLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield put(updateTests(testResults));
|
yield put(updateTests(testResults));
|
||||||
@ -78,72 +76,59 @@ function* logToConsole(channel) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function* ExecuteJSChallengeSaga(state, proxyLogger) {
|
function* executeJSChallengeSaga(state, proxyLogger) {
|
||||||
const { build, sources } = yield call(buildJSChallenge, state);
|
const { build, sources } = yield call(buildJSChallenge, state);
|
||||||
const code = sources && 'index' in sources ? sources['index'] : '';
|
const code = sources && 'index' in sources ? sources['index'] : '';
|
||||||
|
|
||||||
const log = args => proxyLogger.put(args);
|
const testWorker = createWorker('test-evaluator');
|
||||||
testWorker.on('LOG', log);
|
testWorker.on('LOG', proxyLogger);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return yield call(executeTests, (testString, testTimeout) =>
|
return yield call(executeTests, async(testString, testTimeout) => {
|
||||||
testWorker
|
try {
|
||||||
.execute(
|
return await testWorker.execute(
|
||||||
{ script: build + '\n' + testString, code, sources },
|
{ script: build + '\n' + testString, code, sources },
|
||||||
testTimeout
|
testTimeout
|
||||||
)
|
);
|
||||||
.then(result => {
|
} finally {
|
||||||
testWorker.killWorker();
|
testWorker.killWorker();
|
||||||
return result;
|
}
|
||||||
})
|
});
|
||||||
);
|
|
||||||
} finally {
|
} finally {
|
||||||
testWorker.remove('LOG', log);
|
testWorker.remove('LOG', proxyLogger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTestFrame(state, ctx, proxyLogger) {
|
function createTestFrame(ctx, proxyLogger) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve =>
|
||||||
const frameTest = createTestFramer(document, state, resolve, proxyLogger);
|
createTestFramer(document, resolve, proxyLogger)(ctx)
|
||||||
frameTest(ctx);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function* ExecuteDOMChallengeSaga(state, proxyLogger) {
|
function* executeDOMChallengeSaga(state, proxyLogger) {
|
||||||
const ctx = yield call(buildDOMChallenge, state);
|
const ctx = yield call(buildDOMChallenge, state);
|
||||||
|
yield call(createTestFrame, ctx, proxyLogger);
|
||||||
yield call(createTestFrame, state, ctx, proxyLogger);
|
|
||||||
// wait for a code execution on a "ready" event in jQuery challenges
|
// wait for a code execution on a "ready" event in jQuery challenges
|
||||||
yield delay(100);
|
yield delay(100);
|
||||||
|
|
||||||
return yield call(executeTests, (testString, testTimeout) =>
|
return yield call(executeTests, (testString, testTimeout) =>
|
||||||
Promise.race([
|
runTestInTestFrame(document, testString, testTimeout)
|
||||||
runTestInTestFrame(document, testString),
|
|
||||||
new Promise((_, reject) =>
|
|
||||||
setTimeout(() => reject('timeout'), testTimeout)
|
|
||||||
)
|
|
||||||
])
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use a web worker
|
// TODO: use a web worker
|
||||||
function* ExecuteBackendChallengeSaga(state, proxyLogger) {
|
function* executeBackendChallengeSaga(state, proxyLogger) {
|
||||||
const ctx = yield call(buildBackendChallenge, state);
|
const ctx = yield call(buildBackendChallenge, state);
|
||||||
|
yield call(createTestFrame, ctx, proxyLogger);
|
||||||
yield call(createTestFrame, state, ctx, proxyLogger);
|
|
||||||
|
|
||||||
return yield call(executeTests, (testString, testTimeout) =>
|
return yield call(executeTests, (testString, testTimeout) =>
|
||||||
Promise.race([
|
runTestInTestFrame(document, testString, testTimeout)
|
||||||
runTestInTestFrame(document, testString),
|
|
||||||
new Promise((_, reject) =>
|
|
||||||
setTimeout(() => reject('timeout'), testTimeout)
|
|
||||||
)
|
|
||||||
])
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function* executeTests(testRunner) {
|
function* executeTests(testRunner) {
|
||||||
const tests = yield select(challengeTestsSelector);
|
const tests = yield select(challengeTestsSelector);
|
||||||
|
const testTimeout = 5000;
|
||||||
const testResults = [];
|
const testResults = [];
|
||||||
for (const { text, testString } of tests) {
|
for (const { text, testString } of tests) {
|
||||||
const newTest = { text, testString };
|
const newTest = { text, testString };
|
||||||
@ -180,8 +165,8 @@ function* updateMainSaga() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const state = yield select();
|
const state = yield select();
|
||||||
const frameMain = yield call(createMainFramer, document, state);
|
|
||||||
const ctx = yield call(buildDOMChallenge, state);
|
const ctx = yield call(buildDOMChallenge, state);
|
||||||
|
const frameMain = yield call(createMainFramer, document);
|
||||||
yield call(frameMain, ctx);
|
yield call(frameMain, ctx);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -190,7 +175,7 @@ function* updateMainSaga() {
|
|||||||
|
|
||||||
export function createExecuteChallengeSaga(types) {
|
export function createExecuteChallengeSaga(types) {
|
||||||
return [
|
return [
|
||||||
takeLatest(types.executeChallenge, ExecuteChallengeSaga),
|
takeLatest(types.executeChallenge, executeChallengeSaga),
|
||||||
takeLatest(
|
takeLatest(
|
||||||
[
|
[
|
||||||
types.updateFile,
|
types.updateFile,
|
||||||
|
@ -3,8 +3,6 @@ import { configure, shallow, mount } from 'enzyme';
|
|||||||
import Adapter16 from 'enzyme-adapter-react-16';
|
import Adapter16 from 'enzyme-adapter-react-16';
|
||||||
import { setConfig } from 'react-hot-loader';
|
import { setConfig } from 'react-hot-loader';
|
||||||
|
|
||||||
import { isJSEnabledSelector } from '../redux';
|
|
||||||
|
|
||||||
// we use two different frames to make them all essentially pure functions
|
// we use two different frames to make them all essentially pure functions
|
||||||
// main iframe is responsible rendering the preview and is where we proxy the
|
// main iframe is responsible rendering the preview and is where we proxy the
|
||||||
// console.log
|
// console.log
|
||||||
@ -33,23 +31,24 @@ const createHeader = (id = mainId) => `
|
|||||||
</script>
|
</script>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const runTestInTestFrame = async function(document, test) {
|
export const runTestInTestFrame = async function(document, test, timeout) {
|
||||||
const { contentDocument: frame } = document.getElementById(testId);
|
const { contentDocument: frame } = document.getElementById(testId);
|
||||||
// Enable Stateless Functional Component. Otherwise, enzyme-adapter-react-16
|
// Enable Stateless Functional Component. Otherwise, enzyme-adapter-react-16
|
||||||
// does not work correctly.
|
// does not work correctly.
|
||||||
setConfig({ pureSFC: true });
|
setConfig({ pureSFC: true });
|
||||||
const result = await frame.__runTest(test);
|
try {
|
||||||
setConfig({ pureSFC: false });
|
return await Promise.race([
|
||||||
return result;
|
new Promise((_, reject) => setTimeout(() => reject('timeout'), timeout)),
|
||||||
|
frame.__runTest(test)
|
||||||
|
]);
|
||||||
|
} finally {
|
||||||
|
setConfig({ pureSFC: false });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const createFrame = (document, state, id) => ctx => {
|
const createFrame = (document, id) => ctx => {
|
||||||
const isJSEnabled = isJSEnabledSelector(state);
|
|
||||||
const frame = document.createElement('iframe');
|
const frame = document.createElement('iframe');
|
||||||
frame.id = id;
|
frame.id = id;
|
||||||
if (!isJSEnabled) {
|
|
||||||
frame.sandbox = 'allow-same-origin';
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
...ctx,
|
...ctx,
|
||||||
element: frame
|
element: frame
|
||||||
@ -77,7 +76,7 @@ const mountFrame = document => ({ element, ...rest }) => {
|
|||||||
const buildProxyConsole = proxyLogger => ctx => {
|
const buildProxyConsole = proxyLogger => ctx => {
|
||||||
const oldLog = ctx.window.console.log.bind(ctx.window.console);
|
const oldLog = ctx.window.console.log.bind(ctx.window.console);
|
||||||
ctx.window.console.log = function proxyConsole(...args) {
|
ctx.window.console.log = function proxyConsole(...args) {
|
||||||
proxyLogger.put(args);
|
proxyLogger(args);
|
||||||
return oldLog(...args);
|
return oldLog(...args);
|
||||||
};
|
};
|
||||||
return ctx;
|
return ctx;
|
||||||
@ -111,16 +110,16 @@ const writeContentToFrame = ctx => {
|
|||||||
return ctx;
|
return ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createMainFramer = (document, state) =>
|
export const createMainFramer = document =>
|
||||||
flow(
|
flow(
|
||||||
createFrame(document, state, mainId),
|
createFrame(document, mainId),
|
||||||
mountFrame(document),
|
mountFrame(document),
|
||||||
writeContentToFrame
|
writeContentToFrame
|
||||||
);
|
);
|
||||||
|
|
||||||
export const createTestFramer = (document, state, frameReady, proxyConsole) =>
|
export const createTestFramer = (document, frameReady, proxyConsole) =>
|
||||||
flow(
|
flow(
|
||||||
createFrame(document, state, testId),
|
createFrame(document, testId),
|
||||||
mountFrame(document),
|
mountFrame(document),
|
||||||
writeTestDepsToDocument(frameReady),
|
writeTestDepsToDocument(frameReady),
|
||||||
buildProxyConsole(proxyConsole),
|
buildProxyConsole(proxyConsole),
|
||||||
|
Reference in New Issue
Block a user