From 352026df277c005c08b7c515c11406ae32db0ed9 Mon Sep 17 00:00:00 2001 From: sembauke Date: Fri, 10 May 2024 13:28:01 +0200 Subject: [PATCH] feat: make test faster by not parsing the entire curriculum --- e2e/fixtures/js-ads-projects.json | 646 ++++++++++++++++++++++++++++++ e2e/projects.spec.ts | 20 +- 2 files changed, 653 insertions(+), 13 deletions(-) create mode 100644 e2e/fixtures/js-ads-projects.json diff --git a/e2e/fixtures/js-ads-projects.json b/e2e/fixtures/js-ads-projects.json new file mode 100644 index 00000000000000..0996b75c039bf9 --- /dev/null +++ b/e2e/fixtures/js-ads-projects.json @@ -0,0 +1,646 @@ +{ + "javascript-algorithms-and-data-structures-projects": { + "meta": { + "name": "JavaScript Algorithms and Data Structures Projects", + "isUpcomingChange": false, + "dashedName": "javascript-algorithms-and-data-structures-projects", + "helpCategory": "JavaScript", + "order": 9, + "time": "50 hours", + "template": "", + "required": [], + "superBlock": "javascript-algorithms-and-data-structures", + "challengeOrder": [ + { + "id": "aaa48de84e1ecc7c742e1124", + "title": "Palindrome Checker" + }, + { + "id": "a7f4d8f2483413a6ce226cac", + "title": "Roman Numeral Converter" + }, + { + "id": "56533eb9ac21ba0edf2244e2", + "title": "Caesars Cipher" + }, + { + "id": "aff0395860f5d3034dc0bfc9", + "title": "Telephone Number Validator" + }, + { + "id": "aa2e6f85cab2ab736c9a9b24", + "title": "Cash Register" + } + ] + }, + "challenges": [ + { + "id": "56533eb9ac21ba0edf2244e2", + "title": "Caesars Cipher", + "challengeType": 5, + "forumTopicId": 16003, + "dashedName": "caesars-cipher", + "challengeFiles": [ + { + "head": "", + "tail": "", + "id": "", + "editableRegionBoundaries": [], + "history": ["script.js"], + "name": "script", + "ext": "js", + "path": "script.js", + "fileKey": "scriptjs", + "contents": "function rot13(str) {\n return str;\n}\n\nrot13(\"SERR PBQR PNZC\");", + "error": null, + "seed": "function rot13(str) {\n return str;\n}\n\nrot13(\"SERR PBQR PNZC\");" + } + ], + "solutions": [ + [ + { + "head": "", + "tail": "", + "id": "", + "history": ["script.js"], + "name": "script", + "ext": "js", + "path": "script.js", + "fileKey": "scriptjs", + "contents": "var lookup = {\n 'A': 'N','B': 'O','C': 'P','D': 'Q',\n 'E': 'R','F': 'S','G': 'T','H': 'U',\n 'I': 'V','J': 'W','K': 'X','L': 'Y',\n 'M': 'Z','N': 'A','O': 'B','P': 'C',\n 'Q': 'D','R': 'E','S': 'F','T': 'G',\n 'U': 'H','V': 'I','W': 'J','X': 'K',\n 'Y': 'L','Z': 'M'\n};\n\nfunction rot13(encodedStr) {\n var codeArr = encodedStr.split(\"\"); // String to Array\n var decodedArr = []; // Your Result goes here\n // Only change code below this line\n\n decodedArr = codeArr.map(function(letter) {\n if(lookup.hasOwnProperty(letter)) {\n letter = lookup[letter];\n }\n return letter;\n });\n\n // Only change code above this line\n return decodedArr.join(\"\"); // Array to String\n}", + "error": null, + "seed": "var lookup = {\n 'A': 'N','B': 'O','C': 'P','D': 'Q',\n 'E': 'R','F': 'S','G': 'T','H': 'U',\n 'I': 'V','J': 'W','K': 'X','L': 'Y',\n 'M': 'Z','N': 'A','O': 'B','P': 'C',\n 'Q': 'D','R': 'E','S': 'F','T': 'G',\n 'U': 'H','V': 'I','W': 'J','X': 'K',\n 'Y': 'L','Z': 'M'\n};\n\nfunction rot13(encodedStr) {\n var codeArr = encodedStr.split(\"\"); // String to Array\n var decodedArr = []; // Your Result goes here\n // Only change code below this line\n\n decodedArr = codeArr.map(function(letter) {\n if(lookup.hasOwnProperty(letter)) {\n letter = lookup[letter];\n }\n return letter;\n });\n\n // Only change code above this line\n return decodedArr.join(\"\"); // Array to String\n}" + } + ] + ], + "assignments": [], + "tests": [ + { + "text": "

rot13(\"SERR PBQR PNZC\") should decode to the string FREE CODE CAMP

", + "testString": "assert(rot13('SERR PBQR PNZC') === 'FREE CODE CAMP');" + }, + { + "text": "

rot13(\"SERR CVMMN!\") should decode to the string FREE PIZZA!

", + "testString": "assert(rot13('SERR CVMMN!') === 'FREE PIZZA!');" + }, + { + "text": "

rot13(\"SERR YBIR?\") should decode to the string FREE LOVE?

", + "testString": "assert(rot13('SERR YBIR?') === 'FREE LOVE?');" + }, + { + "text": "

rot13(\"GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.\") should decode to the string THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.

", + "testString": "assert(\n rot13('GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.') ===\n 'THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.'\n);" + } + ], + "description": "
\n

One of the simplest and most widely known ciphers is a Caesar cipher, also known as a shift cipher. In a shift cipher the meanings of the letters are shifted by some set amount.

\n

A common modern use is the ROT13 cipher, where the values of the letters are shifted by 13 places. Thus A ↔ N, B ↔ O and so on.

\n

Write a function which takes a ROT13 encoded string as input and returns a decoded string.

\n

All letters will be uppercase. Do not transform any non-alphabetic character (i.e. spaces, punctuation), but do pass them on.

\n
", + "translationPending": false, + "block": "javascript-algorithms-and-data-structures-projects", + "hasEditableBoundaries": false, + "order": 9, + "superOrder": 19, + "certification": "javascript-algorithms-and-data-structures", + "superBlock": "javascript-algorithms-and-data-structures", + "challengeOrder": 2, + "required": [], + "template": "", + "time": "50 hours", + "helpCategory": "JavaScript", + "usesMultifileEditor": false, + "disableLoopProtectTests": false, + "disableLoopProtectPreview": false + }, + { + "id": "aa2e6f85cab2ab736c9a9b24", + "title": "Cash Register", + "challengeType": 5, + "forumTopicId": 16012, + "dashedName": "cash-register", + "challengeFiles": [ + { + "head": "", + "tail": "", + "id": "", + "editableRegionBoundaries": [], + "history": ["script.js"], + "name": "script", + "ext": "js", + "path": "script.js", + "fileKey": "scriptjs", + "contents": "function checkCashRegister(price, cash, cid) {\n let change;\n return change;\n}\n\ncheckCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]);", + "error": null, + "seed": "function checkCashRegister(price, cash, cid) {\n let change;\n return change;\n}\n\ncheckCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]);" + } + ], + "solutions": [ + [ + { + "head": "", + "tail": "", + "id": "", + "history": ["script.js"], + "name": "script", + "ext": "js", + "path": "script.js", + "fileKey": "scriptjs", + "contents": "const denom = [\n { name: \"ONE HUNDRED\", val: 100 },\n { name: \"TWENTY\", val: 20 },\n { name: \"TEN\", val: 10 },\n { name: \"FIVE\", val: 5 },\n { name: \"ONE\", val: 1 },\n { name: \"QUARTER\", val: 0.25 },\n { name: \"DIME\", val: 0.1 },\n { name: \"NICKEL\", val: 0.05 },\n { name: \"PENNY\", val: 0.01 },\n];\n\nfunction checkCashRegister(price, cash, cid) {\n const output = { status: null, change: [] };\n let change = cash - price;\n const register = cid.reduce(\n function (acc, curr) {\n acc.total += curr[1];\n acc[curr[0]] = curr[1];\n return acc;\n },\n { total: 0 }\n );\n if (register.total === change) {\n output.status = \"CLOSED\";\n output.change = cid;\n return output;\n }\n if (register.total < change) {\n output.status = \"INSUFFICIENT_FUNDS\";\n return output;\n }\n const change_arr = denom.reduce(function (acc, curr) {\n let value = 0;\n while (register[curr.name] > 0 && change >= curr.val) {\n change -= curr.val;\n register[curr.name] -= curr.val;\n value += curr.val;\n change = Math.round(change * 100) / 100;\n }\n if (value > 0) {\n acc.push([curr.name, value]);\n }\n return acc;\n }, []);\n if (change_arr.length < 1 || change > 0) {\n output.status = \"INSUFFICIENT_FUNDS\";\n return output;\n }\n output.status = \"OPEN\";\n output.change = change_arr;\n return output;\n}", + "error": null, + "seed": "const denom = [\n { name: \"ONE HUNDRED\", val: 100 },\n { name: \"TWENTY\", val: 20 },\n { name: \"TEN\", val: 10 },\n { name: \"FIVE\", val: 5 },\n { name: \"ONE\", val: 1 },\n { name: \"QUARTER\", val: 0.25 },\n { name: \"DIME\", val: 0.1 },\n { name: \"NICKEL\", val: 0.05 },\n { name: \"PENNY\", val: 0.01 },\n];\n\nfunction checkCashRegister(price, cash, cid) {\n const output = { status: null, change: [] };\n let change = cash - price;\n const register = cid.reduce(\n function (acc, curr) {\n acc.total += curr[1];\n acc[curr[0]] = curr[1];\n return acc;\n },\n { total: 0 }\n );\n if (register.total === change) {\n output.status = \"CLOSED\";\n output.change = cid;\n return output;\n }\n if (register.total < change) {\n output.status = \"INSUFFICIENT_FUNDS\";\n return output;\n }\n const change_arr = denom.reduce(function (acc, curr) {\n let value = 0;\n while (register[curr.name] > 0 && change >= curr.val) {\n change -= curr.val;\n register[curr.name] -= curr.val;\n value += curr.val;\n change = Math.round(change * 100) / 100;\n }\n if (value > 0) {\n acc.push([curr.name, value]);\n }\n return acc;\n }, []);\n if (change_arr.length < 1 || change > 0) {\n output.status = \"INSUFFICIENT_FUNDS\";\n return output;\n }\n output.status = \"OPEN\";\n output.change = change_arr;\n return output;\n}" + } + ] + ], + "assignments": [], + "tests": [ + { + "text": "

checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]) should return an object.

", + "testString": "assert.deepEqual(\n Object.prototype.toString.call(\n checkCashRegister(19.5, 20, [\n ['PENNY', 1.01],\n ['NICKEL', 2.05],\n ['DIME', 3.1],\n ['QUARTER', 4.25],\n ['ONE', 90],\n ['FIVE', 55],\n ['TEN', 20],\n ['TWENTY', 60],\n ['ONE HUNDRED', 100]\n ])\n ),\n '[object Object]'\n);" + }, + { + "text": "

checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]) should return {status: \"OPEN\", change: [[\"QUARTER\", 0.5]]}.

", + "testString": "assert.deepEqual(\n checkCashRegister(19.5, 20, [\n ['PENNY', 1.01],\n ['NICKEL', 2.05],\n ['DIME', 3.1],\n ['QUARTER', 4.25],\n ['ONE', 90],\n ['FIVE', 55],\n ['TEN', 20],\n ['TWENTY', 60],\n ['ONE HUNDRED', 100]\n ]),\n { status: 'OPEN', change: [['QUARTER', 0.5]] }\n);" + }, + { + "text": "

checkCashRegister(3.26, 100, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]) should return {status: \"OPEN\", change: [[\"TWENTY\", 60], [\"TEN\", 20], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.5], [\"DIME\", 0.2], [\"PENNY\", 0.04]]}.

", + "testString": "assert.deepEqual(\n checkCashRegister(3.26, 100, [\n ['PENNY', 1.01],\n ['NICKEL', 2.05],\n ['DIME', 3.1],\n ['QUARTER', 4.25],\n ['ONE', 90],\n ['FIVE', 55],\n ['TEN', 20],\n ['TWENTY', 60],\n ['ONE HUNDRED', 100]\n ]),\n {\n status: 'OPEN',\n change: [\n ['TWENTY', 60],\n ['TEN', 20],\n ['FIVE', 15],\n ['ONE', 1],\n ['QUARTER', 0.5],\n ['DIME', 0.2],\n ['PENNY', 0.04]\n ]\n }\n);" + }, + { + "text": "

checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return {status: \"INSUFFICIENT_FUNDS\", change: []}.

", + "testString": "assert.deepEqual(\n checkCashRegister(19.5, 20, [\n ['PENNY', 0.01],\n ['NICKEL', 0],\n ['DIME', 0],\n ['QUARTER', 0],\n ['ONE', 0],\n ['FIVE', 0],\n ['TEN', 0],\n ['TWENTY', 0],\n ['ONE HUNDRED', 0]\n ]),\n { status: 'INSUFFICIENT_FUNDS', change: [] }\n);" + }, + { + "text": "

checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return {status: \"INSUFFICIENT_FUNDS\", change: []}.

", + "testString": "assert.deepEqual(\n checkCashRegister(19.5, 20, [\n ['PENNY', 0.01],\n ['NICKEL', 0],\n ['DIME', 0],\n ['QUARTER', 0],\n ['ONE', 1],\n ['FIVE', 0],\n ['TEN', 0],\n ['TWENTY', 0],\n ['ONE HUNDRED', 0]\n ]),\n { status: 'INSUFFICIENT_FUNDS', change: [] }\n);" + }, + { + "text": "

checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]) should return {status: \"CLOSED\", change: [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]}.

", + "testString": "assert.deepEqual(\n checkCashRegister(19.5, 20, [\n ['PENNY', 0.5],\n ['NICKEL', 0],\n ['DIME', 0],\n ['QUARTER', 0],\n ['ONE', 0],\n ['FIVE', 0],\n ['TEN', 0],\n ['TWENTY', 0],\n ['ONE HUNDRED', 0]\n ]),\n {\n status: 'CLOSED',\n change: [\n ['PENNY', 0.5],\n ['NICKEL', 0],\n ['DIME', 0],\n ['QUARTER', 0],\n ['ONE', 0],\n ['FIVE', 0],\n ['TEN', 0],\n ['TWENTY', 0],\n ['ONE HUNDRED', 0]\n ]\n }\n);" + } + ], + "description": "
\n

Design a cash register drawer function checkCashRegister() that accepts purchase price as the first argument (price), payment as the second argument (cash), and cash-in-drawer (cid) as the third argument.

\n

cid is a 2D array listing available currency.

\n

The checkCashRegister() function should always return an object with a status key and a change key.

\n

Return {status: \"INSUFFICIENT_FUNDS\", change: []} if cash-in-drawer is less than the change due, or if you cannot return the exact change.

\n

Return {status: \"CLOSED\", change: [...]} with cash-in-drawer as the value for the key change if it is equal to the change due.

\n

Otherwise, return {status: \"OPEN\", change: [...]}, with the change due in coins and bills, sorted in highest to lowest order, as the value of the change key.

\n
Currency UnitAmount
Penny$0.01 (PENNY)
Nickel$0.05 (NICKEL)
Dime$0.1 (DIME)
Quarter$0.25 (QUARTER)
Dollar$1 (ONE)
Five Dollars$5 (FIVE)
Ten Dollars$10 (TEN)
Twenty Dollars$20 (TWENTY)
One-hundred Dollars$100 (ONE HUNDRED)
\n

See below for an example of a cash-in-drawer array:

\n
[\n  [\"PENNY\", 1.01],\n  [\"NICKEL\", 2.05],\n  [\"DIME\", 3.1],\n  [\"QUARTER\", 4.25],\n  [\"ONE\", 90],\n  [\"FIVE\", 55],\n  [\"TEN\", 20],\n  [\"TWENTY\", 60],\n  [\"ONE HUNDRED\", 100]\n]\n
\n
", + "translationPending": false, + "block": "javascript-algorithms-and-data-structures-projects", + "hasEditableBoundaries": false, + "order": 9, + "superOrder": 19, + "certification": "javascript-algorithms-and-data-structures", + "superBlock": "javascript-algorithms-and-data-structures", + "challengeOrder": 4, + "required": [], + "template": "", + "time": "50 hours", + "helpCategory": "JavaScript", + "usesMultifileEditor": false, + "disableLoopProtectTests": false, + "disableLoopProtectPreview": false + }, + { + "id": "aaa48de84e1ecc7c742e1124", + "title": "Palindrome Checker", + "challengeType": 5, + "forumTopicId": 16004, + "dashedName": "palindrome-checker", + "challengeFiles": [ + { + "head": "", + "tail": "", + "id": "", + "editableRegionBoundaries": [], + "history": ["script.js"], + "name": "script", + "ext": "js", + "path": "script.js", + "fileKey": "scriptjs", + "contents": "function palindrome(str) {\n return true;\n}\n\npalindrome(\"eye\");", + "error": null, + "seed": "function palindrome(str) {\n return true;\n}\n\npalindrome(\"eye\");" + } + ], + "solutions": [ + [ + { + "head": "", + "tail": "", + "id": "", + "history": ["script.js"], + "name": "script", + "ext": "js", + "path": "script.js", + "fileKey": "scriptjs", + "contents": "function palindrome(str) {\n var string = str.toLowerCase().split(/[^A-Za-z0-9]/gi).join('');\n var aux = string.split('');\n if (aux.join('') === aux.reverse().join('')){\n return true;\n }\n\n return false;\n}", + "error": null, + "seed": "function palindrome(str) {\n var string = str.toLowerCase().split(/[^A-Za-z0-9]/gi).join('');\n var aux = string.split('');\n if (aux.join('') === aux.reverse().join('')){\n return true;\n }\n\n return false;\n}" + } + ] + ], + "assignments": [], + "tests": [ + { + "text": "

palindrome(\"eye\") should return a boolean.

", + "testString": "assert(typeof palindrome('eye') === 'boolean');" + }, + { + "text": "

palindrome(\"eye\") should return true.

", + "testString": "assert(palindrome('eye') === true);" + }, + { + "text": "

palindrome(\"_eye\") should return true.

", + "testString": "assert(palindrome('_eye') === true);" + }, + { + "text": "

palindrome(\"race car\") should return true.

", + "testString": "assert(palindrome('race car') === true);" + }, + { + "text": "

palindrome(\"not a palindrome\") should return false.

", + "testString": "assert(palindrome('not a palindrome') === false);" + }, + { + "text": "

palindrome(\"A man, a plan, a canal. Panama\") should return true.

", + "testString": "assert(palindrome('A man, a plan, a canal. Panama') === true);" + }, + { + "text": "

palindrome(\"never odd or even\") should return true.

", + "testString": "assert(palindrome('never odd or even') === true);" + }, + { + "text": "

palindrome(\"nope\") should return false.

", + "testString": "assert(palindrome('nope') === false);" + }, + { + "text": "

palindrome(\"almostomla\") should return false.

", + "testString": "assert(palindrome('almostomla') === false);" + }, + { + "text": "

palindrome(\"My age is 0, 0 si ega ym.\") should return true.

", + "testString": "assert(palindrome('My age is 0, 0 si ega ym.') === true);" + }, + { + "text": "

palindrome(\"1 eye for of 1 eye.\") should return false.

", + "testString": "assert(palindrome('1 eye for of 1 eye.') === false);" + }, + { + "text": "

palindrome(\"0_0 (: /-\\ :) 0-0\") should return true.

", + "testString": "assert(palindrome('0_0 (: /- :) 0-0') === true);" + }, + { + "text": "

palindrome(\"five|\\_/|four\") should return false.

", + "testString": "assert(palindrome('five|_/|four') === false);" + } + ], + "description": "
\n

Return true if the given string is a palindrome. Otherwise, return false.

\n

A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation, case, and spacing.

\n

Note: You'll need to remove all non-alphanumeric characters (punctuation, spaces and symbols) and turn everything into the same case (lower or upper case) in order to check for palindromes.

\n

We'll pass strings with varying formats, such as racecar, RaceCar, and race CAR among others.

\n

We'll also pass strings with special symbols, such as 2A3*3a2, 2A3 3a2, and 2_A3*3#A2.

\n
", + "translationPending": false, + "block": "javascript-algorithms-and-data-structures-projects", + "hasEditableBoundaries": false, + "order": 9, + "superOrder": 19, + "certification": "javascript-algorithms-and-data-structures", + "superBlock": "javascript-algorithms-and-data-structures", + "challengeOrder": 0, + "required": [], + "template": "", + "time": "50 hours", + "helpCategory": "JavaScript", + "usesMultifileEditor": false, + "disableLoopProtectTests": false, + "disableLoopProtectPreview": false + }, + { + "id": "a7f4d8f2483413a6ce226cac", + "title": "Roman Numeral Converter", + "challengeType": 5, + "forumTopicId": 16044, + "dashedName": "roman-numeral-converter", + "challengeFiles": [ + { + "head": "", + "tail": "", + "id": "", + "editableRegionBoundaries": [], + "history": ["script.js"], + "name": "script", + "ext": "js", + "path": "script.js", + "fileKey": "scriptjs", + "contents": "function convertToRoman(num) {\n return num;\n}\n\nconvertToRoman(36);", + "error": null, + "seed": "function convertToRoman(num) {\n return num;\n}\n\nconvertToRoman(36);" + } + ], + "solutions": [ + [ + { + "head": "", + "tail": "", + "id": "", + "history": ["script.js"], + "name": "script", + "ext": "js", + "path": "script.js", + "fileKey": "scriptjs", + "contents": "function convertToRoman(num) {\n var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]];\n var res = [];\n ref.forEach(function(p) {\n while (num >= p[1]) {\n res.push(p[0]);\n num -= p[1];\n }\n });\n return res.join('');\n}", + "error": null, + "seed": "function convertToRoman(num) {\n var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]];\n var res = [];\n ref.forEach(function(p) {\n while (num >= p[1]) {\n res.push(p[0]);\n num -= p[1];\n }\n });\n return res.join('');\n}" + } + ] + ], + "assignments": [], + "tests": [ + { + "text": "

convertToRoman(2) should return the string II.

", + "testString": "assert.deepEqual(convertToRoman(2), 'II');" + }, + { + "text": "

convertToRoman(3) should return the string III.

", + "testString": "assert.deepEqual(convertToRoman(3), 'III');" + }, + { + "text": "

convertToRoman(4) should return the string IV.

", + "testString": "assert.deepEqual(convertToRoman(4), 'IV');" + }, + { + "text": "

convertToRoman(5) should return the string V.

", + "testString": "assert.deepEqual(convertToRoman(5), 'V');" + }, + { + "text": "

convertToRoman(9) should return the string IX.

", + "testString": "assert.deepEqual(convertToRoman(9), 'IX');" + }, + { + "text": "

convertToRoman(12) should return the string XII.

", + "testString": "assert.deepEqual(convertToRoman(12), 'XII');" + }, + { + "text": "

convertToRoman(16) should return the string XVI.

", + "testString": "assert.deepEqual(convertToRoman(16), 'XVI');" + }, + { + "text": "

convertToRoman(29) should return the string XXIX.

", + "testString": "assert.deepEqual(convertToRoman(29), 'XXIX');" + }, + { + "text": "

convertToRoman(44) should return the string XLIV.

", + "testString": "assert.deepEqual(convertToRoman(44), 'XLIV');" + }, + { + "text": "

convertToRoman(45) should return the string XLV.

", + "testString": "assert.deepEqual(convertToRoman(45), 'XLV');" + }, + { + "text": "

convertToRoman(68) should return the string LXVIII

", + "testString": "assert.deepEqual(convertToRoman(68), 'LXVIII');" + }, + { + "text": "

convertToRoman(83) should return the string LXXXIII

", + "testString": "assert.deepEqual(convertToRoman(83), 'LXXXIII');" + }, + { + "text": "

convertToRoman(97) should return the string XCVII

", + "testString": "assert.deepEqual(convertToRoman(97), 'XCVII');" + }, + { + "text": "

convertToRoman(99) should return the string XCIX

", + "testString": "assert.deepEqual(convertToRoman(99), 'XCIX');" + }, + { + "text": "

convertToRoman(400) should return the string CD

", + "testString": "assert.deepEqual(convertToRoman(400), 'CD');" + }, + { + "text": "

convertToRoman(500) should return the string D

", + "testString": "assert.deepEqual(convertToRoman(500), 'D');" + }, + { + "text": "

convertToRoman(501) should return the string DI

", + "testString": "assert.deepEqual(convertToRoman(501), 'DI');" + }, + { + "text": "

convertToRoman(649) should return the string DCXLIX

", + "testString": "assert.deepEqual(convertToRoman(649), 'DCXLIX');" + }, + { + "text": "

convertToRoman(798) should return the string DCCXCVIII

", + "testString": "assert.deepEqual(convertToRoman(798), 'DCCXCVIII');" + }, + { + "text": "

convertToRoman(891) should return the string DCCCXCI

", + "testString": "assert.deepEqual(convertToRoman(891), 'DCCCXCI');" + }, + { + "text": "

convertToRoman(1000) should return the string M

", + "testString": "assert.deepEqual(convertToRoman(1000), 'M');" + }, + { + "text": "

convertToRoman(1004) should return the string MIV

", + "testString": "assert.deepEqual(convertToRoman(1004), 'MIV');" + }, + { + "text": "

convertToRoman(1006) should return the string MVI

", + "testString": "assert.deepEqual(convertToRoman(1006), 'MVI');" + }, + { + "text": "

convertToRoman(1023) should return the string MXXIII

", + "testString": "assert.deepEqual(convertToRoman(1023), 'MXXIII');" + }, + { + "text": "

convertToRoman(2014) should return the string MMXIV

", + "testString": "assert.deepEqual(convertToRoman(2014), 'MMXIV');" + }, + { + "text": "

convertToRoman(3999) should return the string MMMCMXCIX

", + "testString": "assert.deepEqual(convertToRoman(3999), 'MMMCMXCIX');" + } + ], + "description": "
\n

Convert the given number into a roman numeral.

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Roman numeralsArabic numerals
M1000
CM900
D500
CD400
C100
XC90
L50
XL40
X10
IX9
V5
IV4
I1
\n

All roman numerals answers should be provided in upper-case.

\n
", + "translationPending": false, + "block": "javascript-algorithms-and-data-structures-projects", + "hasEditableBoundaries": false, + "order": 9, + "superOrder": 19, + "certification": "javascript-algorithms-and-data-structures", + "superBlock": "javascript-algorithms-and-data-structures", + "challengeOrder": 1, + "required": [], + "template": "", + "time": "50 hours", + "helpCategory": "JavaScript", + "usesMultifileEditor": false, + "disableLoopProtectTests": false, + "disableLoopProtectPreview": false + }, + { + "id": "aff0395860f5d3034dc0bfc9", + "title": "Telephone Number Validator", + "challengeType": 5, + "forumTopicId": 16090, + "dashedName": "telephone-number-validator", + "challengeFiles": [ + { + "head": "", + "tail": "", + "id": "", + "editableRegionBoundaries": [], + "history": ["script.js"], + "name": "script", + "ext": "js", + "path": "script.js", + "fileKey": "scriptjs", + "contents": "function telephoneCheck(str) {\n return true;\n}\n\ntelephoneCheck(\"555-555-5555\");", + "error": null, + "seed": "function telephoneCheck(str) {\n return true;\n}\n\ntelephoneCheck(\"555-555-5555\");" + } + ], + "solutions": [ + [ + { + "head": "", + "tail": "", + "id": "", + "history": ["script.js"], + "name": "script", + "ext": "js", + "path": "script.js", + "fileKey": "scriptjs", + "contents": "var re = /^([+]?1[\\s]?)?((?:[(](?:[2-9]1[02-9]|[2-9][02-8][0-9])[)][\\s]?)|(?:(?:[2-9]1[02-9]|[2-9][02-8][0-9])[\\s.-]?)){1}([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2}[\\s.-]?){1}([0-9]{4}){1}$/;\n\nfunction telephoneCheck(str) {\n return re.test(str);\n}\n\ntelephoneCheck(\"555-555-5555\");", + "error": null, + "seed": "var re = /^([+]?1[\\s]?)?((?:[(](?:[2-9]1[02-9]|[2-9][02-8][0-9])[)][\\s]?)|(?:(?:[2-9]1[02-9]|[2-9][02-8][0-9])[\\s.-]?)){1}([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2}[\\s.-]?){1}([0-9]{4}){1}$/;\n\nfunction telephoneCheck(str) {\n return re.test(str);\n}\n\ntelephoneCheck(\"555-555-5555\");" + } + ] + ], + "assignments": [], + "tests": [ + { + "text": "

telephoneCheck(\"555-555-5555\") should return a boolean.

", + "testString": "assert(typeof telephoneCheck('555-555-5555') === 'boolean');" + }, + { + "text": "

telephoneCheck(\"1 555-555-5555\") should return true.

", + "testString": "assert(telephoneCheck('1 555-555-5555') === true);" + }, + { + "text": "

telephoneCheck(\"1 (555) 555-5555\") should return true.

", + "testString": "assert(telephoneCheck('1 (555) 555-5555') === true);" + }, + { + "text": "

telephoneCheck(\"5555555555\") should return true.

", + "testString": "assert(telephoneCheck('5555555555') === true);" + }, + { + "text": "

telephoneCheck(\"555-555-5555\") should return true.

", + "testString": "assert(telephoneCheck('555-555-5555') === true);" + }, + { + "text": "

telephoneCheck(\"(555)555-5555\") should return true.

", + "testString": "assert(telephoneCheck('(555)555-5555') === true);" + }, + { + "text": "

telephoneCheck(\"1(555)555-5555\") should return true.

", + "testString": "assert(telephoneCheck('1(555)555-5555') === true);" + }, + { + "text": "

telephoneCheck(\"555-5555\") should return false.

", + "testString": "assert(telephoneCheck('555-5555') === false);" + }, + { + "text": "

telephoneCheck(\"5555555\") should return false.

", + "testString": "assert(telephoneCheck('5555555') === false);" + }, + { + "text": "

telephoneCheck(\"1 555)555-5555\") should return false.

", + "testString": "assert(telephoneCheck('1 555)555-5555') === false);" + }, + { + "text": "

telephoneCheck(\"1 555 555 5555\") should return true.

", + "testString": "assert(telephoneCheck('1 555 555 5555') === true);" + }, + { + "text": "

telephoneCheck(\"1 456 789 4444\") should return true.

", + "testString": "assert(telephoneCheck('1 456 789 4444') === true);" + }, + { + "text": "

telephoneCheck(\"123**&!!asdf#\") should return false.

", + "testString": "assert(telephoneCheck('123**&!!asdf#') === false);" + }, + { + "text": "

telephoneCheck(\"55555555\") should return false.

", + "testString": "assert(telephoneCheck('55555555') === false);" + }, + { + "text": "

telephoneCheck(\"(6054756961)\") should return false.

", + "testString": "assert(telephoneCheck('(6054756961)') === false);" + }, + { + "text": "

telephoneCheck(\"2 (757) 622-7382\") should return false.

", + "testString": "assert(telephoneCheck('2 (757) 622-7382') === false);" + }, + { + "text": "

telephoneCheck(\"0 (757) 622-7382\") should return false.

", + "testString": "assert(telephoneCheck('0 (757) 622-7382') === false);" + }, + { + "text": "

telephoneCheck(\"-1 (757) 622-7382\") should return false.

", + "testString": "assert(telephoneCheck('-1 (757) 622-7382') === false);" + }, + { + "text": "

telephoneCheck(\"2 757 622-7382\") should return false.

", + "testString": "assert(telephoneCheck('2 757 622-7382') === false);" + }, + { + "text": "

telephoneCheck(\"10 (757) 622-7382\") should return false.

", + "testString": "assert(telephoneCheck('10 (757) 622-7382') === false);" + }, + { + "text": "

telephoneCheck(\"27576227382\") should return false.

", + "testString": "assert(telephoneCheck('27576227382') === false);" + }, + { + "text": "

telephoneCheck(\"(275)76227382\") should return false.

", + "testString": "assert(telephoneCheck('(275)76227382') === false);" + }, + { + "text": "

telephoneCheck(\"2(757)6227382\") should return false.

", + "testString": "assert(telephoneCheck('2(757)6227382') === false);" + }, + { + "text": "

telephoneCheck(\"2(757)622-7382\") should return false.

", + "testString": "assert(telephoneCheck('2(757)622-7382') === false);" + }, + { + "text": "

telephoneCheck(\"555)-555-5555\") should return false.

", + "testString": "assert(telephoneCheck('555)-555-5555') === false);" + }, + { + "text": "

telephoneCheck(\"(555-555-5555\") should return false.

", + "testString": "assert(telephoneCheck('(555-555-5555') === false);" + }, + { + "text": "

telephoneCheck(\"(555)5(55?)-5555\") should return false.

", + "testString": "assert(telephoneCheck('(555)5(55?)-5555') === false);" + }, + { + "text": "

telephoneCheck(\"55 55-55-555-5\") should return false.

", + "testString": "assert(telephoneCheck('55 55-55-555-5') === false);" + }, + { + "text": "

telephoneCheck(\"11 555-555-5555\") should return false.

", + "testString": "assert(telephoneCheck('11 555-555-5555') === false);" + } + ], + "description": "
\n

Return true if the passed string looks like a valid US phone number.

\n

The user may fill out the form field any way they choose as long as it has the format of a valid US number. The following are examples of valid formats for US numbers (refer to the tests below for other variants):

\n
555-555-5555
(555)555-5555
(555) 555-5555
555 555 5555
5555555555
1 555 555 5555
\n

For this challenge you will be presented with a string such as 800-692-7753 or 8oo-six427676;laskdjf. Your job is to validate or reject the US phone number based on any combination of the formats provided above. The area code is required. If the country code is provided, you must confirm that the country code is 1. Return true if the string is a valid US phone number; otherwise return false.

\n
", + "translationPending": false, + "block": "javascript-algorithms-and-data-structures-projects", + "hasEditableBoundaries": false, + "order": 9, + "superOrder": 19, + "certification": "javascript-algorithms-and-data-structures", + "superBlock": "javascript-algorithms-and-data-structures", + "challengeOrder": 3, + "required": [], + "template": "", + "time": "50 hours", + "helpCategory": "JavaScript", + "usesMultifileEditor": false, + "disableLoopProtectTests": false, + "disableLoopProtectPreview": false + } + ] + } +} diff --git a/e2e/projects.spec.ts b/e2e/projects.spec.ts index a793c15e0faa38..9bf0b9b369d276 100644 --- a/e2e/projects.spec.ts +++ b/e2e/projects.spec.ts @@ -1,7 +1,7 @@ import { execSync } from 'child_process'; import { test, expect } from '@playwright/test'; import { SuperBlocks } from '../shared/config/superblocks'; -import curriculum from '../shared/config/curriculum.json'; +import curriculum from './fixtures/js-ads-projects.json'; import { clearEditor, focusEditor, getEditors } from './utils/editor'; import { authedPost } from './utils/request'; @@ -27,14 +27,10 @@ interface Challenge { isPrivate?: boolean; } -interface Curriculum { +interface block { [key: string]: { - blocks: { - [key: string]: { - meta: Meta; - challenges: Challenge[]; - }; - }; + meta: Meta; + challenges: Challenge[]; }; } @@ -95,14 +91,12 @@ test.describe('JavaScript projects can be submitted and then viewed in /settings request }) => { test.setTimeout(60000); - const cur: Curriculum = { ...curriculum }; + const block: block = curriculum; const targetBlock = 'javascript-algorithms-and-data-structures-projects'; - const javaScriptSuperBlock = Object.values(cur).filter( - ({ blocks }) => blocks[targetBlock] - )[0]; + const javaScriptSuperBlock = block[targetBlock]; - const { challenges, meta } = javaScriptSuperBlock?.blocks[targetBlock] || { + const { challenges, meta } = javaScriptSuperBlock || { challenges: [], meta: {} };