From 08c83d6e4ca42cf41d03ae570ad990ef59a397e9 Mon Sep 17 00:00:00 2001 From: Martin Mwaka Date: Sat, 4 Jul 2026 16:09:20 +0100 Subject: [PATCH 1/9] create card-validator.js file --- Sprint-3/4-stretch/card-validator.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Sprint-3/4-stretch/card-validator.js diff --git a/Sprint-3/4-stretch/card-validator.js b/Sprint-3/4-stretch/card-validator.js new file mode 100644 index 0000000000..e69de29bb2 From a043ba8785c1ede90c4bcc16cccaa568d6c8b750 Mon Sep 17 00:00:00 2001 From: Martin Mwaka Date: Sat, 4 Jul 2026 21:46:48 +0100 Subject: [PATCH 2/9] Complete 4-stretch/card-validator.js --- Sprint-3/4-stretch/card-validator.js | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/Sprint-3/4-stretch/card-validator.js b/Sprint-3/4-stretch/card-validator.js index e69de29bb2..d9368d4773 100644 --- a/Sprint-3/4-stretch/card-validator.js +++ b/Sprint-3/4-stretch/card-validator.js @@ -0,0 +1,71 @@ +/* +Here are the rules for a valid number: + +- Number must be 16 digits, all of them must be numbers. +- You must have at least two different digits represented (all of the digits cannot be the same). +- The final digit must be even. +- The sum of all the digits must be greater than 16. + +For example, the following credit card numbers are valid: + +```markdown +9999777788880000 +6666666666661666 +``` + +And the following credit card numbers are invalid: + +```markdown +a92332119c011112 (invalid characters) +4444444444444444 (only one type of number) +1111111111111110 (sum less than 16) +6666666666666661 (odd final number) +``` + +These are the requirements your project needs to fulfill: + +- Make a JavaScript file with a name that describes its contents. +- Create a function with a descriptive name which makes it clear what the function does. The function should take one argument, the credit card number to validate. +- Write at least 2 comments that explain to others what a line of code is meant to do. +- Return a boolean from the function to indicate whether the credit card number is valid. + +Good luck! +*/ + +const validateCard = (card) => { + const cardStr = String(card); + // Must have 16 digits + const has16Digits = cardStr.length === 16; + // Must be all digits + const isAllDigits = /^\d+$/.test(cardStr); + // Must have at least 2 numbers + const hasMoreThanOneDigit = cardStr.length > 1; + // Final digit must be even + const hasEvenFinalDigit = isAllDigits && (Number(cardStr) % 10) % 2 === 0; + // Sum of numbers must be at least 16 + const sumOfNumbers = isAllDigits + ? cardStr.split("").reduce((acc, num) => acc + Number(num), 0) + : 0; + + const hasSumOver15 = sumOfNumbers > 15; + + // Must have more than one type of number + const hasMultipleDistinctDigits = new Set(cardStr.split("")).size > 1; + + return has16Digits && + hasMoreThanOneDigit && + hasEvenFinalDigit && + hasSumOver15 && + hasMultipleDistinctDigits + ? "Valid card" + : "Invalid card"; +}; + +console.log(validateCard(9999777788880000)); // valid +console.log(validateCard(6666666666661666)); // valid +console.log(validateCard("a92332119c011112")); // Invalid +console.log(validateCard(4444444444444444)); // Invalid +console.log(validateCard(1111111111111110)); // Invalid +console.log(validateCard(6666666666666661)); // Invalid + +module.exports = validateCard; From 5bc7e2bc586e67e5dcb310f822dd36932ee7d7c3 Mon Sep 17 00:00:00 2001 From: Martin Mwaka Date: Sat, 4 Jul 2026 22:16:11 +0100 Subject: [PATCH 3/9] Add tests to 4-stretch/card-validator.test.js --- Sprint-3/4-stretch/card-validator.test.js | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Sprint-3/4-stretch/card-validator.test.js diff --git a/Sprint-3/4-stretch/card-validator.test.js b/Sprint-3/4-stretch/card-validator.test.js new file mode 100644 index 0000000000..61f725ae4b --- /dev/null +++ b/Sprint-3/4-stretch/card-validator.test.js @@ -0,0 +1,43 @@ +const validateCard = require("./card-validator"); + +test("should have 16 digits, all numbers", () => { + const cardNumber = 9999777788880000; + const result = validateCard(cardNumber); + expect(result).toBe("Valid card"); +}); + +test("should not have less than 16 digits", () => { + const cardNumber = 99997777; + const result = validateCard(cardNumber); + expect(result).toBe("Invalid card"); +}); + +test("should have at least two different distinct digits", () => { + const cardNumber = 9999777788880000; + const result = validateCard(cardNumber); + expect(result).toBe("Valid card"); +}); + +test("should have even final digit", () => { + const cardNumber = 6666666666661666; + const result = validateCard(cardNumber); + expect(result).toBe("Valid card"); +}); + +test("total sum of numbers should be greater than 15", () => { + const cardNumber = 6666666666661666; + const result = validateCard(cardNumber); + expect(result).toBe("Valid card"); +}); + +test("single repeating digit is invalid", () => { + const cardNumber = 4444444444444444; + const result = validateCard(cardNumber); + expect(result).toBe("Invalid card"); +}); + +test("digits cannot include non numerals", () => { + const cardNumber = "a92332119c011112"; + const result = validateCard(cardNumber); + expect(result).toBe("Invalid card"); +}); From 7cd1603dd8d8d34d890329367eea23e3aa73f1af Mon Sep 17 00:00:00 2001 From: Martin Mwaka Date: Sun, 5 Jul 2026 07:37:28 +0100 Subject: [PATCH 4/9] Complete 4-stretch/find.js --- Sprint-3/4-stretch/find.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sprint-3/4-stretch/find.js b/Sprint-3/4-stretch/find.js index c7e79a2f21..e151d130a4 100644 --- a/Sprint-3/4-stretch/find.js +++ b/Sprint-3/4-stretch/find.js @@ -20,6 +20,10 @@ console.log(find("code your future", "z")); // Pay particular attention to the following: // a) How the index variable updates during the call to find +// [MM] - The index variable increments by one each time the letter (str[index]) at the current index does not match the target letter (char) // b) What is the if statement used to check +// [MM] - The if statement is used to check if the current letter matches the target letter (char). If a match is found (str[index] === char) it will cause an early exit from the while loop at the current index // c) Why is index++ being used? +// [MM] - The index++ increments the index variable by one each time the current letter (str[index]) does not match the target letter (char). It only runs if a match is not found // d) What is the condition index < str.length used for? +// [MM] - The condition index < str.length is used to set the upper bound of the loop (the loop will run while index number is less than str.length) From 012c657a53b56f380fae77522893b20765b89ac0 Mon Sep 17 00:00:00 2001 From: Martin Mwaka Date: Sun, 5 Jul 2026 08:39:03 +0100 Subject: [PATCH 5/9] Write tests for 4-stretch/password-validator.test.js --- Sprint-3/4-stretch/password-validator.test.js | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/Sprint-3/4-stretch/password-validator.test.js b/Sprint-3/4-stretch/password-validator.test.js index 8fa3089d6b..5d49eca93d 100644 --- a/Sprint-3/4-stretch/password-validator.test.js +++ b/Sprint-3/4-stretch/password-validator.test.js @@ -16,11 +16,38 @@ You must breakdown this problem in order to solve it. Find one test case first a */ const isValidPassword = require("./password-validator"); test("password has at least 5 characters", () => { - // Arrange - const password = "12345"; - // Act - const result = isValidPassword(password); - // Assert - expect(result).toEqual(true); -} -); \ No newline at end of file + // Arrange + const password = "12345"; + // Act + const result = isValidPassword(password); + // Assert + expect(result).toEqual(true); +}); + +test("returns true for a valid password", () => { + expect(isValidPassword("Pen5!")).toBe(true); +}); + +test("returns false for a short password", () => { + expect(isValidPassword("Pen!")).toBe(false); +}); + +test("returns false if there is no uppercase English letter", () => { + expect(isValidPassword("pen5!")).toBe(false); +}); + +test("returns false if there is no lowercase English letter", () => { + expect(isValidPassword("PEN5!")).toBe(false); +}); + +test("returns false if there is no number", () => { + expect(isValidPassword("PENf!")).toBe(false); +}); + +test("returns false if there is no symbol", () => { + expect(isValidPassword("Pen5a")).toBe(false); +}); + +test("returns false if password is a previous password", () => { + expect(isValidPassword("HeLlo5.")).toBe(false); +}); From 3e569fa5cd7629eab529fdfbe2cc28ac57f3d117 Mon Sep 17 00:00:00 2001 From: Martin Mwaka Date: Sun, 5 Jul 2026 08:40:59 +0100 Subject: [PATCH 6/9] Complete password-validator.js --- Sprint-3/4-stretch/password-validator.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Sprint-3/4-stretch/password-validator.js b/Sprint-3/4-stretch/password-validator.js index b55d527dba..776cfdf878 100644 --- a/Sprint-3/4-stretch/password-validator.js +++ b/Sprint-3/4-stretch/password-validator.js @@ -1,6 +1,16 @@ function passwordValidator(password) { - return password.length < 5 ? false : true -} + const previousPasswords = ["heLlo5.", "Su1ma#"]; + + const checks = { + minLength: password.length > 4, + hasUpperCase: /[A-Z]/.test(password), + hasLowerCase: /[a-z]/.test(password), + hasNumber: /[0-9]/.test(password), + hasSymbol: /[!#$%.*&]/.test(password), + notPreviousPassword: !previousPasswords.includes(password), + }; + return Object.values(checks).every(Boolean); +} -module.exports = passwordValidator; \ No newline at end of file +module.exports = passwordValidator; From 48629e08200a43be18b9852b1cf68f57d56d97ec Mon Sep 17 00:00:00 2001 From: Martin Mwaka Date: Sun, 5 Jul 2026 08:46:27 +0100 Subject: [PATCH 7/9] Update 4-stretch/password-validator.test.js - all tests pass --- Sprint-3/4-stretch/password-validator.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sprint-3/4-stretch/password-validator.test.js b/Sprint-3/4-stretch/password-validator.test.js index 5d49eca93d..59238a78d7 100644 --- a/Sprint-3/4-stretch/password-validator.test.js +++ b/Sprint-3/4-stretch/password-validator.test.js @@ -17,7 +17,7 @@ You must breakdown this problem in order to solve it. Find one test case first a const isValidPassword = require("./password-validator"); test("password has at least 5 characters", () => { // Arrange - const password = "12345"; + const password = "Pen5!"; // Act const result = isValidPassword(password); // Assert @@ -49,5 +49,5 @@ test("returns false if there is no symbol", () => { }); test("returns false if password is a previous password", () => { - expect(isValidPassword("HeLlo5.")).toBe(false); + expect(isValidPassword("heLlo5.")).toBe(false); }); From 8939f58c40d2c9b705daef68d3a366f54f95dd6f Mon Sep 17 00:00:00 2001 From: Martin Mwaka Date: Fri, 17 Jul 2026 14:28:45 +0100 Subject: [PATCH 8/9] update my answers to find.js --- Sprint-3/4-stretch/find.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Sprint-3/4-stretch/find.js b/Sprint-3/4-stretch/find.js index e151d130a4..968756c8dd 100644 --- a/Sprint-3/4-stretch/find.js +++ b/Sprint-3/4-stretch/find.js @@ -20,10 +20,13 @@ console.log(find("code your future", "z")); // Pay particular attention to the following: // a) How the index variable updates during the call to find -// [MM] - The index variable increments by one each time the letter (str[index]) at the current index does not match the target letter (char) +// The index starts at 0 and increments by one at each iteration as long as the nested if statement is not triggered. In the case of find("code your future", "u"), the if statement is triggered at index 7 because a match is found for letter u at this index. The while loop is exited and the number 7 is returned by the find function. In the case of find("code your future", "z") no match is found by the time the while loop terminates. In this case the find function returns -1 to indicate the letter z was not found in the string + // b) What is the if statement used to check -// [MM] - The if statement is used to check if the current letter matches the target letter (char). If a match is found (str[index] === char) it will cause an early exit from the while loop at the current index +// The if statement is used to check if the current letter in the string (str[index]) matches the target letter (char). If a match is found (str[index] === char) it will cause an early exit from the while loop at the current index which will be returned by the find function + // c) Why is index++ being used? -// [MM] - The index++ increments the index variable by one each time the current letter (str[index]) does not match the target letter (char). It only runs if a match is not found +// index++ is being used because the while loop does not have a built in iterator (like the for loop). Index is initiated at 0 outside the while loop and at each iteration, whenever the if statement is not triggered, index++ adds 1 to the index number + // d) What is the condition index < str.length used for? -// [MM] - The condition index < str.length is used to set the upper bound of the loop (the loop will run while index number is less than str.length) +// The condition index < str.length is used to set the upper bound of the loop (the loop will run while index number is less than str.length and will terminate once index is equal to str.length, causing the while loop to stop. If there is no condition to terminate the while loop it will run infinitely From 87e12473716a23fcdbbae85364c52e4dddd8048b Mon Sep 17 00:00:00 2001 From: Martin Mwaka Date: Fri, 17 Jul 2026 14:35:34 +0100 Subject: [PATCH 9/9] update the return value to boolean in both card-validator.js and card-validator.test.js - all tests pass --- Sprint-3/4-stretch/card-validator.js | 16 ++++++++-------- Sprint-3/4-stretch/card-validator.test.js | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Sprint-3/4-stretch/card-validator.js b/Sprint-3/4-stretch/card-validator.js index d9368d4773..dfb00afd85 100644 --- a/Sprint-3/4-stretch/card-validator.js +++ b/Sprint-3/4-stretch/card-validator.js @@ -57,15 +57,15 @@ const validateCard = (card) => { hasEvenFinalDigit && hasSumOver15 && hasMultipleDistinctDigits - ? "Valid card" - : "Invalid card"; + ? true + : false; }; -console.log(validateCard(9999777788880000)); // valid -console.log(validateCard(6666666666661666)); // valid -console.log(validateCard("a92332119c011112")); // Invalid -console.log(validateCard(4444444444444444)); // Invalid -console.log(validateCard(1111111111111110)); // Invalid -console.log(validateCard(6666666666666661)); // Invalid +console.log(validateCard(9999777788880000)); // true +console.log(validateCard(6666666666661666)); // true +console.log(validateCard("a92332119c011112")); // false +console.log(validateCard(4444444444444444)); // false +console.log(validateCard(1111111111111110)); // false +console.log(validateCard(6666666666666661)); // false module.exports = validateCard; diff --git a/Sprint-3/4-stretch/card-validator.test.js b/Sprint-3/4-stretch/card-validator.test.js index 61f725ae4b..40b0f05c36 100644 --- a/Sprint-3/4-stretch/card-validator.test.js +++ b/Sprint-3/4-stretch/card-validator.test.js @@ -3,41 +3,41 @@ const validateCard = require("./card-validator"); test("should have 16 digits, all numbers", () => { const cardNumber = 9999777788880000; const result = validateCard(cardNumber); - expect(result).toBe("Valid card"); + expect(result).toBe(true); }); test("should not have less than 16 digits", () => { const cardNumber = 99997777; const result = validateCard(cardNumber); - expect(result).toBe("Invalid card"); + expect(result).toBe(false); }); test("should have at least two different distinct digits", () => { const cardNumber = 9999777788880000; const result = validateCard(cardNumber); - expect(result).toBe("Valid card"); + expect(result).toBe(true); }); test("should have even final digit", () => { const cardNumber = 6666666666661666; const result = validateCard(cardNumber); - expect(result).toBe("Valid card"); + expect(result).toBe(true); }); test("total sum of numbers should be greater than 15", () => { const cardNumber = 6666666666661666; const result = validateCard(cardNumber); - expect(result).toBe("Valid card"); + expect(result).toBe(true); }); test("single repeating digit is invalid", () => { const cardNumber = 4444444444444444; const result = validateCard(cardNumber); - expect(result).toBe("Invalid card"); + expect(result).toBe(false); }); test("digits cannot include non numerals", () => { const cardNumber = "a92332119c011112"; const result = validateCard(cardNumber); - expect(result).toBe("Invalid card"); + expect(result).toBe(false); });