Skip to content
15 changes: 14 additions & 1 deletion Sprint-3/2-practice-tdd/count.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
function countChar(stringOfCharacters, findCharacter) {
return 5
let counter = 0;
let index = stringOfCharacters.indexOf(findCharacter);
while (index !== -1) {
counter++;

index = stringOfCharacters.indexOf(findCharacter, index + 1);
}
return counter;
}

module.exports = countChar;
function assertFunction(currentOutput, targetOutput) {
console.assert(
currentOutput === targetOutput,
`expect ${currentOutput} to equal ${targetOutput}`
);
}
31 changes: 31 additions & 0 deletions Sprint-3/2-practice-tdd/count.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,34 @@ test("should count multiple occurrences of a character", () => {
// And a character char that does not exist within the case-sensitive str,
// When the function is called with these inputs,
// Then it should return 0, indicating that no occurrences of the char were found in the case-sensitive str.
test("should return 0 occurrences of b characters ", () => {
const str = "Ahmad Hmedan";
const char = "b";
const count = countChar(str, char);
expect(count).toEqual(0);
});

test("should return 1 occurrence of A characters", () => {
const str = "Ahmad Hmedan";
const char = "A";
const count = countChar(str, char);
expect(count).toEqual(1);
});
test("should return 2 occurrence of m characters", () => {
const str = "Ahmad Hmedan";
const char = "m";
const count = countChar(str, char);
expect(count).toEqual(2);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test description usually describe a general case, like the one on line 13. And then for each case we can test multiple samples that belong to that case.

A specific description like this "should return 0 occurrences of b characters" could confuse the the person implementing the function into thinking "what is so special about checking 0 occurrences of 'b' in a string?"

test("should return occurrence of any characters in empty string", () => {
const str = "";
const char = "@";
const count = countChar(str, char);
expect(count).toEqual(0);
});
test("should return 1 occurrence of @ characters in empty string", () => {
const str = "Ahmadhm@gamil.com";
const char = "@";
const count = countChar(str, char);
expect(count).toEqual(1);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • The test description does not quite match the test.
  • Could consider also generalise this test or combine it with others.

18 changes: 17 additions & 1 deletion Sprint-3/2-practice-tdd/get-ordinal-number.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
function getOrdinalNumber(num) {
return "1st";
if (num <= 0) return "Invalid Input";
if (num % 100 === 11) return `${num}th`; // check the last two digit if it exception 11, 12 or 13
if (num % 100 === 12) return `${num}th`;
if (num % 100 === 13) return `${num}th`;
const remainder = num % 10;
switch (remainder) {
case 1:
return `${num}st`;

case 2:
return `${num}nd`;
case 3:
return `${num}rd`;

default:
return `${num}th`;
}
}

module.exports = getOrdinalNumber;
48 changes: 48 additions & 0 deletions Sprint-3/2-practice-tdd/get-ordinal-number.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,51 @@ const getOrdinalNumber = require("./get-ordinal-number");
test("should return '1st' for 1", () => {
expect(getOrdinalNumber(1)).toEqual("1st");
});
// Case 2: Identify the ordinal number for 22
// When the number is 22,
// Then the function should return 22nd"
test("should return '22nd' for 22", () => {
expect(getOrdinalNumber(22)).toEqual("22nd");
});
// Case 3: Identify the ordinal number for 73
// When the number is 73,
// Then the function should return 73rd"

test("should return '73rd' for 73", () => {
expect(getOrdinalNumber(73)).toEqual("73rd");
});

// Case 4: Identify the ordinal number for 99
// When the number is 99,
// Then the function should return 99th"

test("should return '99th' for 99", () => {
expect(getOrdinalNumber(99)).toEqual("99th");
});

// Case 5: Identify the ordinal number for number ends with 11,12, or 13
// When the number is 111,
// Then the function should return 111th"
// When the number is 212,
// Then the function should return 212th"
// When the number is 413,
// Then the function should return 413th"

test("should return '111th' for 111", () => {
expect(getOrdinalNumber(111)).toEqual("111th");
});
test("should return '212th' for 212", () => {
expect(getOrdinalNumber(212)).toEqual("212th");
});
test("should return '413th' for 413", () => {
expect(getOrdinalNumber(413)).toEqual("413th");
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To ensure thorough testing, we need broad scenarios that cover all possible cases.
Listing individual values, however, can quickly lead to an unmanageable number of test cases.
Instead of writing tests for individual numbers, consider grouping all possible input values into meaningful categories.
Then, select representative samples from each category to test. This approach improves coverage and makes our tests easier to maintain.

For example, we can prepare a test for numbers 2, 22, 132, etc. as

test("append 'nd' to numbers ending in 2, except those ending in 12", () => {
    expect( getOrdinalNumber(2) ).toEqual("2nd");
    expect( getOrdinalNumber(22) ).toEqual("22nd");
    expect( getOrdinalNumber(132) ).toEqual("132nd");
});


//case 6
// when is the number is 0 or negative number
test("should throw Invalid Input for negative numbers", () => {
expect(getOrdinalNumber(-5)).toEqual("Invalid Input");
});
test("should throw Invalid Input for 0", () => {
expect(getOrdinalNumber(0)).toEqual("Invalid Input");
});
23 changes: 21 additions & 2 deletions Sprint-3/2-practice-tdd/repeat.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
function repeat() {
return "hellohellohello";
function repeat(myString, repeatNumber) {
if (repeatNumber < 0) return "Invalid Input must be a positive number";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would the caller distinguish the result of the following two function calls?

  1. repeat("Invalid Input must be a positive number", 1)
  2. repeat("", -1)

Both function calls return the same value.

//if (repeatNumber < 0) throw new Error("Repeat count must be a positive number");
// if I use this instead return how I can test it with jest??
return myString.repeat(repeatNumber);
}

module.exports = repeat;

// Note:
// When I wrote this code, I didn’t know there was already a built-in method for this.
// Please review this implementation as well.
//if (repeatNumber < 0) throw new Error("Repeat count must be a positive number"); if I use this instead return how I can test it with jest??

// function repeat(myString, repeatNumber) {
// if (repeatNumber < 0) return "Invalid Input must be a positive number";
// let str = "";
// for (let i = 0; i < repeatNumber; i++) {
// str += myString;
// }
// return str;
// }
Comment on lines +14 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works too.

While knowing how to use built-in functions can improve productivity and performance, it is equally important to know how to implement such a function without relying on any built-in function.


//if (repeatNumber < 0) throw new Error("Repeat count must be a positive number");
31 changes: 31 additions & 0 deletions Sprint-3/2-practice-tdd/repeat.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,43 @@ test("should repeat the string count times", () => {
// When the repeat function is called with these inputs,
// Then it should return the original str without repetition, ensuring that a count of 1 results in no repetition.

test("should return the string", () => {
const str = "CYF";
const count = 1;
const repeatedStr = repeat(str, count);
expect(repeatedStr).toEqual("CYF");
});

// case: Handle Count of 0:
// Given a target string str and a count equal to 0,
// When the repeat function is called with these inputs,
// Then it should return an empty string, ensuring that a count of 0 results in an empty output.

test("should return empty when the count is 0", () => {
const str = "CYF";
const count = 0;
const repeatedStr = repeat(str, count);
expect(repeatedStr).toEqual("");
});
// case: Negative Count:
// Given a target string str and a negative integer count,
// When the repeat function is called with these inputs,
// Then it should throw an error or return an appropriate error message, as negative counts are not valid.
test("should return empty when the count is negative", () => {
const str = "CYF";
const count = -2;
const repeatedStr = repeat(str, count);
expect(repeatedStr).toEqual("Invalid Input must be a positive number");
});
Comment on lines 46 to 51
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you modified repeat() to throw an error when count is negative, and you wanted to test if the function can throw an error as expected, you can use .toThrow(). You can find out more about how to use .toThrow() here: https://jestjs.io/docs/expect#tothrowerror (Note: Pay close attention to the syntax of the example)

test("should repeat the string five times when the count is 5", () => {
const str = "CYF";
const count = 5;
const repeatedStr = repeat(str, count);
expect(repeatedStr).toEqual("CYFCYFCYFCYFCYF");
});
test("should return an empty string when the str is empty whatever was count equal", () => {
const str = "";
const count = 10;
const repeatedStr = repeat(str, count);
expect(repeatedStr).toEqual("");
});