diff --git a/__e2e__/__snapshots__/__e2e__/commands/fetchtask.test.js.md b/__e2e__/__snapshots__/__e2e__/commands/fetchtask.test.js.md new file mode 100644 index 0000000..82b8fff --- /dev/null +++ b/__e2e__/__snapshots__/__e2e__/commands/fetchtask.test.js.md @@ -0,0 +1,209 @@ +# Snapshot report for `__e2e__/commands/fetchtask.test.js` + +The actual snapshot is saved in `fetchtask.test.js.snap`. + +Generated by [AVA](https://ava.li). + +## display completed task with fetchtask key + +> Snapshot 1 + + ` _ _ _ ␊ + | |_ ___ __ _ ___| |__ ___ ___ __| | ___ ␊ + | __/ _ \\/ _` |/ __| '_ \\ / __/ _ \\ / _` |/ _ \\␊ + | || __/ (_| | (__| | | | (_| (_) | (_| | __/␊ + \\__\\___|\\__,_|\\___|_| |_|\\___\\___/ \\__,_|\\___|␊ + ␊ +  Learn to code effectively Powered by MadHacks␊ + ␊ + ␊ + This task is already completed!␊ + ␊ + ␊ + User: testConfig Progress: 6/30␊ + ␊ + ␊ + Now lets focus on variables␊ + Unlike other programming languages, Python has no command for declaring a variable.A variable is created the moment you first assign a value to it.␊ + Also consider these variable naming conventions␊ + ␊ + 1.A variable name must start with a letter or the underscore character␊ + 2.A variable name cannot start with a number␊ + 3.A variable name can only contain alpha-numeric characters and underscores (A-z, 0-9, and _ )␊ + 3.Variable names are case-sensitive (age, Age and AGE are three different variables)␊ + Task 2:-␊ + Consider these variable names:-␊ + variable␊ + sum@␊ + product_of_12␊ + 12_product␊ + Just print out the correct variable names in order␊ + ` + +> Snapshot 2 + + ` _ _ _ ␊ + | |_ ___ __ _ ___| |__ ___ ___ __| | ___ ␊ + | __/ _ \\/ _` |/ __| '_ \\ / __/ _ \\ / _` |/ _ \\␊ + | || __/ (_| | (__| | | | (_| (_) | (_| | __/␊ + \\__\\___|\\__,_|\\___|_| |_|\\___\\___/ \\__,_|\\___|␊ + ␊ +  Learn to code effectively Powered by MadHacks␊ + ␊ + ␊ + This task is already completed!␊ + ␊ + ␊ + User: testConfig Progress: 6/30␊ + ␊ + Great! Now's let's move on to variables. Variables are used to store data values ␊ + Task 2:-␊ + Declare a variable to store the value 18 and print the value.␊ + ` + +## display incomplete task with fetchtask key + +> Snapshot 1 + + ` _ _ _ ␊ + | |_ ___ __ _ ___| |__ ___ ___ __| | ___ ␊ + | __/ _ \\/ _` |/ __| '_ \\ / __/ _ \\ / _` |/ _ \\␊ + | || __/ (_| | (__| | | | (_| (_) | (_| | __/␊ + \\__\\___|\\__,_|\\___|_| |_|\\___\\___/ \\__,_|\\___|␊ + ␊ +  Learn to code effectively Powered by MadHacks␊ + ␊ + ␊ + User: testConfig Progress: 6/30␊ + ␊ + ␊ + Awesome! Let's move on to Loops. ␊ + Loop is an important statement which is used for repetition of the same code as and when required. ␊ + This task will surely test what you have learnt till now from the previous tasks! ␊ + ␊ + Task 6 ␊ + Syntax of for loop: ␊ + for loop_control_variable in range(start, stop, step): ␊ + Loop Body(indented)␊ + Here's your task: ␊ + ␊ + Task- 6 ␊ + Print even numbers from 1 to 10 (including 10) using for loop.␊ + ` + +> Snapshot 2 + + ` _ _ _ ␊ + | |_ ___ __ _ ___| |__ ___ ___ __| | ___ ␊ + | __/ _ \\/ _` |/ __| '_ \\ / __/ _ \\ / _` |/ _ \\␊ + | || __/ (_| | (__| | | | (_| (_) | (_| | __/␊ + \\__\\___|\\__,_|\\___|_| |_|\\___\\___/ \\__,_|\\___|␊ + ␊ +  Learn to code effectively Powered by MadHacks␊ + ␊ + ␊ + User: testConfig Progress: 6/30␊ + ␊ + Awesome! Let's move on to Comparison Operators. They are used to compare two values. They return true or false according to the value of their operands. They are: ==, ===, !=, >, <, >=, <=. Here's your task:␊ + Task 6:-␊ + Use 44 & 29 as your operands. Compare them using the Comparison operators in the same order and print the value which they return.␊ + ` + +## display next task with fetchtask + +> Snapshot 1 + + ` _ _ _ ␊ + | |_ ___ __ _ ___| |__ ___ ___ __| | ___ ␊ + | __/ _ \\/ _` |/ __| '_ \\ / __/ _ \\ / _` |/ _ \\␊ + | || __/ (_| | (__| | | | (_| (_) | (_| | __/␊ + \\__\\___|\\__,_|\\___|_| |_|\\___\\___/ \\__,_|\\___|␊ + ␊ +  Learn to code effectively Powered by MadHacks␊ + ␊ + ␊ + User: testConfig Progress: 6/30␊ + ␊ + ␊ + Awesome! Let's move on to Loops. ␊ + Loop is an important statement which is used for repetition of the same code as and when required. ␊ + This task will surely test what you have learnt till now from the previous tasks! ␊ + ␊ + Task 6 ␊ + Syntax of for loop: ␊ + for loop_control_variable in range(start, stop, step): ␊ + Loop Body(indented)␊ + Here's your task: ␊ + ␊ + Task- 6 ␊ + Print even numbers from 1 to 10 (including 10) using for loop.␊ + ` + +> Snapshot 2 + + ` _ _ _ ␊ + | |_ ___ __ _ ___| |__ ___ ___ __| | ___ ␊ + | __/ _ \\/ _` |/ __| '_ \\ / __/ _ \\ / _` |/ _ \\␊ + | || __/ (_| | (__| | | | (_| (_) | (_| | __/␊ + \\__\\___|\\__,_|\\___|_| |_|\\___\\___/ \\__,_|\\___|␊ + ␊ +  Learn to code effectively Powered by MadHacks␊ + ␊ + ␊ + User: testConfig Progress: 6/30␊ + ␊ + Awesome! Let's move on to Comparison Operators. They are used to compare two values. They return true or false according to the value of their operands. They are: ==, ===, !=, >, <, >=, <=. Here's your task:␊ + Task 6:-␊ + Use 44 & 29 as your operands. Compare them using the Comparison operators in the same order and print the value which they return.␊ + ` + +## incorrect key for fetchtask + +> Snapshot 1 + + ` _ _ _ ␊ + | |_ ___ __ _ ___| |__ ___ ___ __| | ___ ␊ + | __/ _ \\/ _` |/ __| '_ \\ / __/ _ \\ / _` |/ _ \\␊ + | || __/ (_| | (__| | | | (_| (_) | (_| | __/␊ + \\__\\___|\\__,_|\\___|_| |_|\\___\\___/ \\__,_|\\___|␊ + ␊ +  Learn to code effectively Powered by MadHacks␊ + ␊ + ␊ + Make sure that you've grabbed the key correctly!␊ + ␊ + ` + +## no config file for fetchtask + +> Snapshot 1 + + ` _ _ _ ␊ + | |_ ___ __ _ ___| |__ ___ ___ __| | ___ ␊ + | __/ _ \\/ _` |/ __| '_ \\ / __/ _ \\ / _` |/ _ \\␊ + | || __/ (_| | (__| | | | (_| (_) | (_| | __/␊ + \\__\\___|\\__,_|\\___|_| |_|\\___\\___/ \\__,_|\\___|␊ + ␊ +  Learn to code effectively Powered by MadHacks␊ + ␊ + Make sure that you are within the teachcode-solutions directory!␊ + ␊ + cd teachcode-solutions may resolve the issue!␊ + ␊ + ` + +## no more tasks available + +> Snapshot 1 + + ` _ _ _ ␊ + | |_ ___ __ _ ___| |__ ___ ___ __| | ___ ␊ + | __/ _ \\/ _` |/ __| '_ \\ / __/ _ \\ / _` |/ _ \\␊ + | || __/ (_| | (__| | | | (_| (_) | (_| | __/␊ + \\__\\___|\\__,_|\\___|_| |_|\\___\\___/ \\__,_|\\___|␊ + ␊ +  Learn to code effectively Powered by MadHacks␊ + ␊ + ␊ + No more tasks available!␊ + ` diff --git a/__e2e__/__snapshots__/__e2e__/commands/fetchtask.test.js.snap b/__e2e__/__snapshots__/__e2e__/commands/fetchtask.test.js.snap new file mode 100644 index 0000000..31c2ee0 Binary files /dev/null and b/__e2e__/__snapshots__/__e2e__/commands/fetchtask.test.js.snap differ diff --git a/__e2e__/commands/fetchtask.test.js b/__e2e__/commands/fetchtask.test.js new file mode 100644 index 0000000..940f150 --- /dev/null +++ b/__e2e__/commands/fetchtask.test.js @@ -0,0 +1,129 @@ +'use strict'; + +const path = require('path'); +const execa = require('execa'); +const test = require('ava'); +const fs = require('fs'); + +const rootCommand = path.join(process.cwd(), 'bin/index.js'); +const configFilePath = path.join(process.cwd(), 'config.json'); + +const learningTracksInfo = [ + { trackName: 'Python', fileExtension: 'py' }, + { trackName: 'JavaScript', fileExtension: 'js' }, +]; + +const userDefaultConfig = { + learningTrack: '', + userName: 'testConfig', + taskCount: 0, + keys: [], + userSubmittedFiles: [], +}; + +const createUserConfig = ( + trackName, + fileExtension, + keysNumber, + filesNumber, +) => { + let userConfig = userDefaultConfig; + userConfig['learningTrack'] = trackName; + for (let i = 0; i < keysNumber; i++) { + userConfig['keys'].push(`testKey${i + 1}`); + } + for (let i = 0; i < filesNumber; i++) { + userConfig['userSubmittedFiles'].push(`task${i + 1}.${fileExtension}`); + } + userConfig['taskCount'] = filesNumber; + + return userConfig; +}; + +test.serial('no config file for fetchtask', async t => { + if (fs.existsSync(configFilePath)) fs.unlinkSync(configFilePath); + const { stdout } = await execa(rootCommand, ['fetchtask'], { + reject: false, + }); + t.snapshot(stdout); +}); + +test.serial('incorrect key for fetchtask', async t => { + let snap = null; + t.assert(learningTracksInfo.length > 0); + for (let index in learningTracksInfo) { + let { trackName, fileExtension } = learningTracksInfo[index]; + const userConfig = createUserConfig(trackName, fileExtension, 30, 30); + fs.writeFileSync(configFilePath, JSON.stringify(userConfig)); + const { stdout } = await execa( + rootCommand, + ['fetchtask', 'incorrectTestKey'], + { reject: false }, + ); + fs.unlinkSync(configFilePath); + if (snap) { + t.true(snap === stdout); + } else { + snap = stdout; + } + } + t.snapshot(snap); +}); + +test.serial('display completed task with fetchtask key', async t => { + t.assert(learningTracksInfo.length > 0); + for (let index in learningTracksInfo) { + let { trackName, fileExtension } = learningTracksInfo[index]; + let userConfig = createUserConfig(trackName, fileExtension, 6, 5); + fs.writeFileSync(configFilePath, JSON.stringify(userConfig)); + const { stdout } = await execa(rootCommand, ['fetchtask', 'testKey2']); + t.snapshot(stdout); + fs.unlinkSync(configFilePath); + } +}); + +test.serial('display incomplete task with fetchtask key', async t => { + t.assert(learningTracksInfo.length > 0); + for (let index in learningTracksInfo) { + let { trackName, fileExtension } = learningTracksInfo[index]; + let userConfig = createUserConfig(trackName, fileExtension, 6, 5); + fs.writeFileSync(configFilePath, JSON.stringify(userConfig)); + const { stdout } = await execa(rootCommand, ['fetchtask', 'testKey6']); + t.snapshot(stdout); + fs.unlinkSync(configFilePath); + fs.unlinkSync(path.join(process.cwd(), `task6.${fileExtension}`)); + } +}); + +test.serial('no more tasks available', async t => { + let snap = null; + t.assert(learningTracksInfo.length > 0); + for (let index in learningTracksInfo) { + let { trackName, fileExtension } = learningTracksInfo[index]; + const userConfig = createUserConfig(trackName, fileExtension, 30, 30); + fs.writeFileSync(configFilePath, JSON.stringify(userConfig)); + const { stdout } = await execa(rootCommand, ['fetchtask'], { + reject: false, + }); + if (snap) { + t.assert(snap === stdout); + } else { + snap = stdout; + } + fs.unlinkSync(configFilePath); + } + t.snapshot(snap); +}); + +test.serial('display next task with fetchtask', async t => { + t.assert(learningTracksInfo.length > 0); + for (let index in learningTracksInfo) { + let { trackName, fileExtension } = learningTracksInfo[index]; + const userConfig = createUserConfig(trackName, fileExtension, 6, 5); + fs.writeFileSync(configFilePath, JSON.stringify(userConfig)); + const { stdout } = await execa(rootCommand, ['fetchtask']); + t.snapshot(stdout); + fs.unlinkSync(configFilePath); + fs.unlinkSync(path.join(process.cwd(), `task6.${fileExtension}`)); + } +}); diff --git a/src/commands/tasks.js b/src/commands/tasks.js index 477df09..2ac72f4 100644 --- a/src/commands/tasks.js +++ b/src/commands/tasks.js @@ -42,15 +42,11 @@ const fetchTask = async key => { const { learningTrack, userName, - userSubmittedFiles, taskCount, keys, + userSubmittedFiles, } = userConfig; - if (!key) { - key = keys.slice(-1).pop(); - } - if (learningTrack === 'Python') { fileName = `task${taskCount + 1}.py`; exercises = require('../workspace/python/tasks'); @@ -59,11 +55,32 @@ const fetchTask = async key => { exercises = require('../workspace/js/tasks'); } - // Holding reference to keys of all the completed tasks - let previousKeys = keys.slice(0, keys.length - 1); + if (key && !keys.includes(key)) { + console.log(); + console.log( + chalk.red.bold("Make sure that you've grabbed the key correctly!"), + ); + console.log(); + process.exit(1); + } + + // check if no more tasks are available (no key provided) + if (!key && taskCount === exercises.length) { + console.log(); + console.log(chalk.red.bold('No more tasks available!')); + process.exit(1); + } + + // in case no key is provided, make the last key as the key + if (!key) { + key = keys.slice(-1).pop(); + } let taskAlreadyCompleted = []; + // Holding reference to keys of all the completed tasks + let previousKeys = keys.slice(0, taskCount); + previousKeys.some((item, index) => { if (item === key) { taskAlreadyCompleted = [true, index]; @@ -78,21 +95,16 @@ const fetchTask = async key => { console.log(); console.log( chalk.green.bold( - `User: ${userName}${`\t`.repeat(4)}Progress: ${taskCount + 1}/${ - exercises.length - }`, + `User: ${userName}${`\t`.repeat(4)}Progress: ${Math.min( + taskCount + 1, + 30, + )}/${exercises.length}`, ), ); console.log(); console.log(chalk.green(`${exercises[taskAlreadyCompleted[1]].task}`)); console.log(); - process.exit(1); - } - - if (taskCount === exercises.length) { - console.log(); - console.log(chalk.red.bold('No more tasks available!')); - process.exit(1); + return; } if (keys.slice(-1).pop() === key) { @@ -105,9 +117,10 @@ const fetchTask = async key => { console.log(); console.log( chalk.cyan.bold( - `User: ${userName}${`\t`.repeat(6)}Progress: ${taskCount + 1}/${ - exercises.length - }`, + `User: ${userName}${`\t`.repeat(6)}Progress: ${Math.min( + taskCount + 1, + 30, + )}/${exercises.length}`, ), ); // Displaying respective task within the the console screen. @@ -117,12 +130,6 @@ const fetchTask = async key => { let createCmd = process.platform !== 'win32' ? 'touch' : 'notepad'; execSync(`${createCmd} ${fileName}`); - } else { - console.log(); - console.log( - chalk.red.bold("Make sure that you've grabbed the key correctly!"), - ); - console.log(); } };