feat: allow next challenge's seed to be a solution (#39145)
* feat: allow next challenge's seed to be a solution
This commit is contained in:
parent
4f1be63055
commit
fd7a8c0d5e
@ -23,7 +23,7 @@ const {
|
||||
|
||||
const { assert, AssertionError } = require('chai');
|
||||
const Mocha = require('mocha');
|
||||
const { flatten } = require('lodash');
|
||||
const { flatten, isEmpty } = require('lodash');
|
||||
|
||||
const jsdom = require('jsdom');
|
||||
|
||||
@ -51,6 +51,7 @@ const {
|
||||
} = require('../../client/src/templates/Challenges/utils/build');
|
||||
|
||||
const { createPoly } = require('../../utils/polyvinyl');
|
||||
const { sortChallenges } = require('./utils/sort-challenges');
|
||||
|
||||
const testEvaluator = require('../../client/config/test-evaluator').filename;
|
||||
|
||||
@ -226,7 +227,9 @@ async function getChallenges(lang) {
|
||||
return [...challengeArray, ...flatten(challengesForBlock)];
|
||||
}, [])
|
||||
);
|
||||
return challenges;
|
||||
// This matches the order Gatsby uses (via a GraphQL query). Ideally both
|
||||
// should be sourced and sorted using a single query, but we're not there yet.
|
||||
return sortChallenges(challenges);
|
||||
}
|
||||
|
||||
function validateBlock(challenge) {
|
||||
@ -245,7 +248,7 @@ function populateTestsForLang({ lang, challenges, meta }) {
|
||||
|
||||
describe(`Check challenges (${lang})`, function() {
|
||||
this.timeout(5000);
|
||||
challenges.forEach(challenge => {
|
||||
challenges.forEach((challenge, id) => {
|
||||
const dashedBlockName = dasherize(challenge.block);
|
||||
describe(challenge.block || 'No block', function() {
|
||||
describe(challenge.title || 'No title', function() {
|
||||
@ -367,6 +370,15 @@ function populateTestsForLang({ lang, challenges, meta }) {
|
||||
});
|
||||
|
||||
let { solutions = [] } = challenge;
|
||||
// if there are no solutions in the challenge, it's assumed the next
|
||||
// challenge's seed will be a solution to the current challenge.
|
||||
// This is expected to happen in the project based curriculum.
|
||||
if (isEmpty(solutions)) {
|
||||
const nextChallenge = challenges[id + 1];
|
||||
if (nextChallenge) {
|
||||
solutions = [nextChallenge.files[0].contents];
|
||||
}
|
||||
}
|
||||
const noSolution = new RegExp('// solution required');
|
||||
solutions = solutions.filter(
|
||||
solution => !!solution && !noSolution.test(solution)
|
||||
|
5
curriculum/test/utils/sort-challenges.js
Normal file
5
curriculum/test/utils/sort-challenges.js
Normal file
@ -0,0 +1,5 @@
|
||||
const { sortBy } = require('lodash');
|
||||
|
||||
exports.sortChallenges = arr => {
|
||||
return sortBy(arr, ['superOrder', 'order', 'challengeOrder']);
|
||||
};
|
252
curriculum/test/utils/sort-challenges.test.js
Normal file
252
curriculum/test/utils/sort-challenges.test.js
Normal file
@ -0,0 +1,252 @@
|
||||
/* global expect */
|
||||
const { sortChallenges } = require('./sort-challenges');
|
||||
|
||||
const challenges = [
|
||||
{
|
||||
name: 'HTML - project 1 - step 1',
|
||||
superOrder: 1,
|
||||
order: 1,
|
||||
challengeOrder: 1
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 1 - step 2',
|
||||
superOrder: 1,
|
||||
order: 1,
|
||||
challengeOrder: 2
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 1 - step 3',
|
||||
superOrder: 1,
|
||||
order: 1,
|
||||
challengeOrder: 3
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 1 - step 4',
|
||||
superOrder: 1,
|
||||
order: 1,
|
||||
challengeOrder: 4
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 2 - step 1',
|
||||
superOrder: 1,
|
||||
order: 2,
|
||||
challengeOrder: 1
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 2 - step 2',
|
||||
superOrder: 1,
|
||||
order: 2,
|
||||
challengeOrder: 2
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 2 - step 3',
|
||||
superOrder: 1,
|
||||
order: 2,
|
||||
challengeOrder: 3
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 2 - step 4',
|
||||
superOrder: 1,
|
||||
order: 2,
|
||||
challengeOrder: 4
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 3 - step 1',
|
||||
superOrder: 1,
|
||||
order: 3,
|
||||
challengeOrder: 1
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 3 - step 2',
|
||||
superOrder: 1,
|
||||
order: 3,
|
||||
challengeOrder: 2
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 3 - step 3',
|
||||
superOrder: 1,
|
||||
order: 3,
|
||||
challengeOrder: 3
|
||||
},
|
||||
{
|
||||
name: 'HTML - project 3 - step 4',
|
||||
superOrder: 1,
|
||||
order: 3,
|
||||
challengeOrder: 4
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 1 - step 1',
|
||||
superOrder: 2,
|
||||
order: 1,
|
||||
challengeOrder: 1
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 1 - step 2',
|
||||
superOrder: 2,
|
||||
order: 1,
|
||||
challengeOrder: 2
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 1 - step 3',
|
||||
superOrder: 2,
|
||||
order: 1,
|
||||
challengeOrder: 3
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 1 - step 4',
|
||||
superOrder: 2,
|
||||
order: 1,
|
||||
challengeOrder: 4
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 2 - step 1',
|
||||
superOrder: 2,
|
||||
order: 2,
|
||||
challengeOrder: 1
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 2 - step 2',
|
||||
superOrder: 2,
|
||||
order: 2,
|
||||
challengeOrder: 2
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 2 - step 3',
|
||||
superOrder: 2,
|
||||
order: 2,
|
||||
challengeOrder: 3
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 2 - step 4',
|
||||
superOrder: 2,
|
||||
order: 2,
|
||||
challengeOrder: 4
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 3 - step 1',
|
||||
superOrder: 2,
|
||||
order: 3,
|
||||
challengeOrder: 1
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 3 - step 2',
|
||||
superOrder: 2,
|
||||
order: 3,
|
||||
challengeOrder: 2
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 3 - step 3',
|
||||
superOrder: 2,
|
||||
order: 3,
|
||||
challengeOrder: 3
|
||||
},
|
||||
{
|
||||
name: 'CSS - project 3 - step 4',
|
||||
superOrder: 2,
|
||||
order: 3,
|
||||
challengeOrder: 4
|
||||
},
|
||||
{
|
||||
name: 'JS - project 1 - step 1',
|
||||
superOrder: 3,
|
||||
order: 1,
|
||||
challengeOrder: 1
|
||||
},
|
||||
{
|
||||
name: 'JS - project 1 - step 2',
|
||||
superOrder: 3,
|
||||
order: 1,
|
||||
challengeOrder: 2
|
||||
},
|
||||
{
|
||||
name: 'JS - project 1 - step 3',
|
||||
superOrder: 3,
|
||||
order: 1,
|
||||
challengeOrder: 3
|
||||
},
|
||||
{
|
||||
name: 'JS - project 1 - step 4',
|
||||
superOrder: 3,
|
||||
order: 1,
|
||||
challengeOrder: 4
|
||||
},
|
||||
{
|
||||
name: 'JS - project 2 - step 1',
|
||||
superOrder: 3,
|
||||
order: 2,
|
||||
challengeOrder: 1
|
||||
},
|
||||
{
|
||||
name: 'JS - project 2 - step 2',
|
||||
superOrder: 3,
|
||||
order: 2,
|
||||
challengeOrder: 2
|
||||
},
|
||||
{
|
||||
name: 'JS - project 2 - step 3',
|
||||
superOrder: 3,
|
||||
order: 2,
|
||||
challengeOrder: 3
|
||||
},
|
||||
{
|
||||
name: 'JS - project 2 - step 4',
|
||||
superOrder: 3,
|
||||
order: 2,
|
||||
challengeOrder: 4
|
||||
},
|
||||
{
|
||||
name: 'JS - project 3 - step 1',
|
||||
superOrder: 3,
|
||||
order: 3,
|
||||
challengeOrder: 1
|
||||
},
|
||||
{
|
||||
name: 'JS - project 3 - step 2',
|
||||
superOrder: 3,
|
||||
order: 3,
|
||||
challengeOrder: 2
|
||||
},
|
||||
{
|
||||
name: 'JS - project 3 - step 3',
|
||||
superOrder: 3,
|
||||
order: 3,
|
||||
challengeOrder: 3
|
||||
},
|
||||
{
|
||||
name: 'JS - project 3 - step 4',
|
||||
superOrder: 3,
|
||||
order: 3,
|
||||
challengeOrder: 4
|
||||
}
|
||||
];
|
||||
|
||||
describe('sortChallenges', () => {
|
||||
it('sorts challenges by superblock, block and challenge order', () => {
|
||||
const copyOfChallenges = [...challenges];
|
||||
shuffle(copyOfChallenges);
|
||||
const actualChallenges = sortChallenges(copyOfChallenges);
|
||||
|
||||
expect(actualChallenges).toEqual(challenges);
|
||||
});
|
||||
|
||||
it('does not change the original array', () => {
|
||||
const copyOfChallenges = [...challenges];
|
||||
copyOfChallenges[0] = {
|
||||
name: 'JS - project 3 - step 4',
|
||||
superOrder: 3,
|
||||
order: 3,
|
||||
challengeOrder: 4
|
||||
};
|
||||
const actualChallenges = sortChallenges(copyOfChallenges);
|
||||
|
||||
expect(actualChallenges[0]).not.toEqual(copyOfChallenges[0]);
|
||||
});
|
||||
});
|
||||
|
||||
// Use the Fisher–Yates shuffle algorithm to shuffle array
|
||||
const shuffle = arr => {
|
||||
for (let i = arr.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[arr[i], arr[j]] = [arr[j], arr[i]];
|
||||
}
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user