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:
		
				
					committed by
					
						 Mrugesh Mohapatra
						Mrugesh Mohapatra
					
				
			
			
				
	
			
			
			
						parent
						
							4f1be63055
						
					
				
				
					commit
					fd7a8c0d5e
				
			| @@ -23,7 +23,7 @@ const { | |||||||
|  |  | ||||||
| const { assert, AssertionError } = require('chai'); | const { assert, AssertionError } = require('chai'); | ||||||
| const Mocha = require('mocha'); | const Mocha = require('mocha'); | ||||||
| const { flatten } = require('lodash'); | const { flatten, isEmpty } = require('lodash'); | ||||||
|  |  | ||||||
| const jsdom = require('jsdom'); | const jsdom = require('jsdom'); | ||||||
|  |  | ||||||
| @@ -51,6 +51,7 @@ const { | |||||||
| } = require('../../client/src/templates/Challenges/utils/build'); | } = require('../../client/src/templates/Challenges/utils/build'); | ||||||
|  |  | ||||||
| const { createPoly } = require('../../utils/polyvinyl'); | const { createPoly } = require('../../utils/polyvinyl'); | ||||||
|  | const { sortChallenges } = require('./utils/sort-challenges'); | ||||||
|  |  | ||||||
| const testEvaluator = require('../../client/config/test-evaluator').filename; | const testEvaluator = require('../../client/config/test-evaluator').filename; | ||||||
|  |  | ||||||
| @@ -226,7 +227,9 @@ async function getChallenges(lang) { | |||||||
|         return [...challengeArray, ...flatten(challengesForBlock)]; |         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) { | function validateBlock(challenge) { | ||||||
| @@ -245,7 +248,7 @@ function populateTestsForLang({ lang, challenges, meta }) { | |||||||
|  |  | ||||||
|   describe(`Check challenges (${lang})`, function() { |   describe(`Check challenges (${lang})`, function() { | ||||||
|     this.timeout(5000); |     this.timeout(5000); | ||||||
|     challenges.forEach(challenge => { |     challenges.forEach((challenge, id) => { | ||||||
|       const dashedBlockName = dasherize(challenge.block); |       const dashedBlockName = dasherize(challenge.block); | ||||||
|       describe(challenge.block || 'No block', function() { |       describe(challenge.block || 'No block', function() { | ||||||
|         describe(challenge.title || 'No title', function() { |         describe(challenge.title || 'No title', function() { | ||||||
| @@ -367,6 +370,15 @@ function populateTestsForLang({ lang, challenges, meta }) { | |||||||
|           }); |           }); | ||||||
|  |  | ||||||
|           let { solutions = [] } = challenge; |           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'); |           const noSolution = new RegExp('// solution required'); | ||||||
|           solutions = solutions.filter( |           solutions = solutions.filter( | ||||||
|             solution => !!solution && !noSolution.test(solution) |             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]]; | ||||||
|  |   } | ||||||
|  | }; | ||||||
		Reference in New Issue
	
	Block a user