fix(test): transform js challenges before a test

This commit is contained in:
Valeriy S
2018-11-26 10:47:33 +03:00
committed by Stuart Taylor
parent ac5c1ff1bf
commit 28798dc008

View File

@ -51,23 +51,22 @@ const jQueryScript = fs.readFileSync(
); );
(async function() { (async function() {
const allChallenges = await getChallengesForLang(lang).then(curriculum => ( const allChallenges = await getChallengesForLang(lang).then(curriculum =>
Object.keys(curriculum) Object.keys(curriculum)
.map(key => curriculum[key].blocks) .map(key => curriculum[key].blocks)
.reduce((challengeArray, superBlock) => { .reduce((challengeArray, superBlock) => {
const challengesForBlock = Object.keys(superBlock).map( const challengesForBlock = Object.keys(superBlock).map(
key => superBlock[key].challenges key => superBlock[key].challenges
); );
return [...challengeArray, ...flatten(challengesForBlock)]; return [...challengeArray, ...flatten(challengesForBlock)];
}, []) }, [])
)); );
describe('Check challenges tests', async function() { describe('Check challenges tests', async function() {
this.timeout(5000); this.timeout(5000);
allChallenges.forEach(challenge => { allChallenges.forEach(challenge => {
describe(challenge.title || 'No title', async function() { describe(challenge.title || 'No title', async function() {
it('Common checks', function() { it('Common checks', function() {
const result = validateChallenge(challenge); const result = validateChallenge(challenge);
if (result.error) { if (result.error) {
@ -80,11 +79,12 @@ const jQueryScript = fs.readFileSync(
}); });
const { challengeType } = challenge; const { challengeType } = challenge;
if (challengeType !== challengeTypes.html && if (
challengeType !== challengeTypes.js && challengeType !== challengeTypes.html &&
challengeType !== challengeTypes.bonfire && challengeType !== challengeTypes.js &&
challengeType !== challengeTypes.modern && challengeType !== challengeTypes.bonfire &&
challengeType !== challengeTypes.backend challengeType !== challengeTypes.modern &&
challengeType !== challengeTypes.backend
) { ) {
return; return;
} }
@ -99,9 +99,7 @@ const jQueryScript = fs.readFileSync(
describe('Check tests syntax', function() { describe('Check tests syntax', function() {
tests.forEach(test => { tests.forEach(test => {
it(`Check for: ${test.text}`, function() { it(`Check for: ${test.text}`, function() {
assert.doesNotThrow( assert.doesNotThrow(() => new vm.Script(test.testString));
() => new vm.Script(test.testString)
);
}); });
}); });
}); });
@ -109,7 +107,7 @@ const jQueryScript = fs.readFileSync(
const { files = [], required = [] } = challenge; const { files = [], required = [] } = challenge;
const exts = Array.from(new Set(files.map(({ ext }) => ext))); const exts = Array.from(new Set(files.map(({ ext }) => ext)));
const groupedFiles = exts.reduce((result, ext) => { const groupedFiles = exts.reduce((result, ext) => {
const file = files.filter(file => file.ext === ext ).reduce( const file = files.filter(file => file.ext === ext).reduce(
(result, file) => ({ (result, file) => ({
head: result.head + '\n' + file.head, head: result.head + '\n' + file.head,
contents: result.contents + '\n' + file.contents, contents: result.contents + '\n' + file.contents,
@ -124,8 +122,10 @@ const jQueryScript = fs.readFileSync(
}, {}); }, {});
let evaluateTest; let evaluateTest;
if (challengeType === challengeTypes.modern && if (
(groupedFiles.js || groupedFiles.jsx)) { challengeType === challengeTypes.modern &&
(groupedFiles.js || groupedFiles.jsx)
) {
evaluateTest = evaluateReactReduxTest; evaluateTest = evaluateReactReduxTest;
} else if (groupedFiles.html) { } else if (groupedFiles.html) {
evaluateTest = evaluateHtmlTest; evaluateTest = evaluateHtmlTest;
@ -141,29 +141,30 @@ const jQueryScript = fs.readFileSync(
// suppress errors in the console. // suppress errors in the console.
const oldConsoleError = console.error; const oldConsoleError = console.error;
console.error = () => {}; console.error = () => {};
let fails = ( let fails = (await Promise.all(
await Promise.all(tests.map(async function(test) { tests.map(async function(test) {
try { try {
await evaluateTest({ await evaluateTest({
challengeType, challengeType,
required, required,
files: groupedFiles, files: groupedFiles,
test test
}); });
return false; return false;
} catch (e) { } catch (e) {
return true; return true;
} }
}))).some(v => v); })
)).some(v => v);
console.error = oldConsoleError; console.error = oldConsoleError;
assert(fails, 'Test suit does not fail on the initial contents'); assert(fails, 'Test suit does not fail on the initial contents');
}); });
let { solutions = [] } = challenge; let { solutions = [] } = challenge;
const noSolution = new RegExp('// solution required'); const noSolution = new RegExp('// solution required');
solutions = solutions.filter(solution => ( solutions = solutions.filter(
!!solution && !noSolution.test(solution) solution => !!solution && !noSolution.test(solution)
)); );
if (solutions.length === 0) { if (solutions.length === 0) {
it('Check tests. No solutions'); it('Check tests. No solutions');
@ -192,7 +193,6 @@ const jQueryScript = fs.readFileSync(
}); });
run(); run();
})(); })();
// Fake Deep Equal dependency // Fake Deep Equal dependency
@ -250,13 +250,11 @@ const colors = {
function replaceColorNamesPlugin(style) { function replaceColorNamesPlugin(style) {
visit(style, declarations => { visit(style, declarations => {
declarations declarations.filter(decl => decl.type === 'declaration').forEach(decl => {
.filter(decl => decl.type === 'declaration') if (colors[decl.value]) {
.forEach(decl => { decl.value = colors[decl.value];
if (colors[decl.value]) { }
decl.value = colors[decl.value]; });
}
});
}); });
} }
@ -275,7 +273,6 @@ function replaceColorNames(solution) {
return fragment.children[0].innerHTML; return fragment.children[0].innerHTML;
} }
return solution; return solution;
} }
async function evaluateHtmlTest({ async function evaluateHtmlTest({
@ -285,7 +282,6 @@ async function evaluateHtmlTest({
files, files,
test test
}) { }) {
const { head = '', contents = '', tail = '' } = files.html; const { head = '', contents = '', tail = '' } = files.html;
if (!solution) { if (!solution) {
solution = contents; solution = contents;
@ -324,17 +320,14 @@ A required file can not have both a src and a link: src = ${src}, link = ${link}
const sandbox = { solution, transformSass }; const sandbox = { solution, transformSass };
const context = vm.createContext(sandbox); const context = vm.createContext(sandbox);
vm.runInContext( vm.runInContext('solution = transformSass(solution);', context, {
'solution = transformSass(solution);', timeout: 2000
context, });
{
timeout: 2000
}
);
solution = sandbox.solution; solution = sandbox.solution;
solution = replaceColorNames(solution); solution = replaceColorNames(solution);
const dom = new JSDOM(` const dom = new JSDOM(
`
<!doctype html> <!doctype html>
<html> <html>
${scripts} ${scripts}
@ -342,7 +335,9 @@ A required file can not have both a src and a link: src = ${src}, link = ${link}
${solution} ${solution}
${tail} ${tail}
</html> </html>
`, options); `,
options
);
if (links || challengeType === challengeTypes.modern) { if (links || challengeType === challengeTypes.modern) {
await timeout(1000); await timeout(1000);
@ -352,12 +347,7 @@ A required file can not have both a src and a link: src = ${src}, link = ${link}
await runTestInJsdom(dom, test.testString); await runTestInJsdom(dom, test.testString);
} }
async function evaluateJsTest({ async function evaluateJsTest({ solution, files, test }) {
solution,
files,
test
}) {
const virtualConsole = new jsdom.VirtualConsole(); const virtualConsole = new jsdom.VirtualConsole();
const dom = new JSDOM('', { runScripts: 'dangerously', virtualConsole }); const dom = new JSDOM('', { runScripts: 'dangerously', virtualConsole });
@ -365,29 +355,35 @@ async function evaluateJsTest({
let scriptString = ''; let scriptString = '';
if (!solution) { if (!solution) {
solution = contents; solution = contents;
scriptString = head + '\n' + contents + '\n' + tail + '\n';
try { try {
// eslint-disable-next-line scriptString =
new vm.Script(scriptString); Babel.transform(head, babelOptions).code +
'\n' +
Babel.transform(contents, babelOptions).code +
'\n' +
Babel.transform(tail, babelOptions).code +
'\n';
} catch (e) { } catch (e) {
scriptString = ''; scriptString = '';
} }
} else { } else {
scriptString = head + '\n' + solution + '\n' + tail + '\n'; scriptString =
Babel.transform(head, babelOptions).code +
'\n' +
Babel.transform(solution, babelOptions).code +
'\n' +
Babel.transform(tail, babelOptions).code +
'\n';
} }
dom.window.require = require;
dom.window.code = solution; dom.window.code = solution;
await runTestInJsdom(dom, test.testString, scriptString); await runTestInJsdom(dom, test.testString, scriptString);
} }
async function evaluateReactReduxTest({ async function evaluateReactReduxTest({ solution, files, test }) {
solution, let head = '',
files, tail = '';
test
}) {
let head = '', tail = '';
if (files.js) { if (files.js) {
const { head: headJs = '', tail: tailJs = '' } = files.js; const { head: headJs = '', tail: tailJs = '' } = files.js;
head += headJs + '\n'; head += headJs + '\n';
@ -404,38 +400,50 @@ async function evaluateReactReduxTest({
let scriptString = ''; let scriptString = '';
if (!solution) { if (!solution) {
const contents = (files.js ? files.js.contents || '' : '') + const contents =
(files.js ? files.js.contents || '' : '') +
(files.jsx ? files.jsx.contents || '' : ''); (files.jsx ? files.jsx.contents || '' : '');
solution = contents; solution = contents;
scriptString = head + '\n' + contents + '\n' + tail + '\n';
try { try {
scriptString = Babel.transform(scriptString, babelOptions).code; scriptString =
Babel.transform(head, babelOptions).code +
'\n' +
Babel.transform(contents, babelOptions).code +
'\n' +
Babel.transform(tail, babelOptions).code +
'\n';
} catch (e) { } catch (e) {
scriptString = ''; scriptString = '';
} }
} else { } else {
scriptString = head + '\n' + solution + '\n' + tail + '\n'; scriptString =
scriptString = Babel.transform(scriptString, babelOptions).code; Babel.transform(head, babelOptions).code +
'\n' +
Babel.transform(solution, babelOptions).code +
'\n' +
Babel.transform(tail, babelOptions).code +
'\n';
} }
const code = solution; const code = solution;
const testString = Babel.transform(test.testString, babelOptions).code;
const virtualConsole = new jsdom.VirtualConsole(); const virtualConsole = new jsdom.VirtualConsole();
// Mock DOM document for ReactDOM.render method // Mock DOM document for ReactDOM.render method
const dom = new JSDOM(` const dom = new JSDOM(
`
<!doctype html> <!doctype html>
<html> <html>
<body> <body>
<div id="root"><div id="challenge-node"></div> <div id="root"><div id="challenge-node"></div>
</body> </body>
</html> </html>
`, { `,
runScripts: 'dangerously', {
virtualConsole, runScripts: 'dangerously',
url: 'http://localhost' virtualConsole,
}); url: 'http://localhost'
}
);
const { window } = dom; const { window } = dom;
const document = window.document; const document = window.document;
@ -468,7 +476,7 @@ async function evaluateReactReduxTest({
} }
}; };
await runTestInJsdom(dom, testString, scriptString); await runTestInJsdom(dom, test.testString, scriptString);
} }
async function runTestInJsdom(dom, testString, scriptString = '') { async function runTestInJsdom(dom, testString, scriptString = '') {