fix(test): transform js challenges before a test
This commit is contained in:
@ -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 = '') {
|
||||||
|
Reference in New Issue
Block a user