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 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]]; | ||||
|   } | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user