London | 25-ITP-SEP | Imran Mohamed| Sprint 3 | Coursework/sprint 3 practice tdd#794
London | 25-ITP-SEP | Imran Mohamed| Sprint 3 | Coursework/sprint 3 practice tdd#794i786m wants to merge 14 commits intoCodeYourFuture:mainfrom
Conversation
jennethydyrova
left a comment
There was a problem hiding this comment.
Hi @i786m! Kudos on writing clean and readable functions! You did a good job with the unit tests as well. However, unit tests are designed to catch bugs from unexpected usage, which is why it's important to pass different types of parameters and test various scenarios. Please make your test cases more thorough to ensure your functions handle edge cases properly.
| // 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 if no occurrences of a character", () => { |
There was a problem hiding this comment.
These unit tests are good but they are a bit slim. Can you think of corner and edge cases that your function might encounter? What if, for example, other data types or not all parameters are passed? Thinking about these scenarios will make your function more robust and your tests more thorough.
| expect(getOrdinalNumber(1)).toEqual("1st"); | ||
| }); | ||
|
|
||
| test("should return '2nd' for 2", () => { |
There was a problem hiding this comment.
Same as my previous comment. What if someone passes "3", undefined, or another unexpected value to your function? I understand your assumptions, but users of your functions (both internal within your team and external if you build some sort of API) can pass values you didn't safeguard against, which can break your function.
| @@ -21,12 +21,30 @@ 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 original string if count is 1", () => { | |||
There was a problem hiding this comment.
Same here, the test cases are quite limited. If I call your function with something like repeat("hello", "3") or repeat("hello", null), it will work because of javascript's type coercion, but is that the behavior you want? Writing more test cases with different input types will help you catch any behavior that you didn't intentionally design into your function.
…r get ordinal number
|
I have amended the code & tests based on the comments made , pleases let me know if this is sufficient. |
jennethydyrova
left a comment
There was a problem hiding this comment.
Hi @i786m! Very good job. There are two things I would like you to do before completing this PR.
- Remove console logs.
- Decide between throwing error and returning error string in
repeatfn.
Rest of my comments are optional, just food for thought 🙂
Sprint-3/2-practice-tdd/count.js
Outdated
| if (stringOfCharacters.length === 0) { | ||
| return 0; | ||
| } | ||
| console.log(Array.from(stringOfCharacters)); |
There was a problem hiding this comment.
Can you please remove this console log? This helps to keep PR clean.
There was a problem hiding this comment.
I have removed console log, will ensure future PRs are free from debugging logs
| if (typeof num !== "number" || isNaN(num)) { | ||
| throw new Error("Input must be a number"); | ||
| } | ||
| if (!Number.isFinite(num)){ | ||
| throw new Error("Input must be a finite number"); | ||
| } | ||
| if (!Number.isInteger(num) || num < 0) { | ||
| throw new Error("Input must be a non-negative integer"); | ||
| } |
There was a problem hiding this comment.
This is a good validation but I think this could be simplified because at the end your input should be a Non-negative integer. For example, Number.isFinite() and isNan() have some overlap, can you check in the MDN docs?
I am leaving this as an optional comment, no action needs to be taken to complete this PR but I would like you think if this could be written simpler. You do not need to throw different error for each small case, you can have more general error for anything that is negative non-integer.
There was a problem hiding this comment.
changed code taking overlap in consideration
| if ( arguments.length !== 2) { | ||
| return "Function requires exactly 2 arguments"; | ||
| } | ||
| if (typeof str !== "string") { | ||
| return "First argument must be a string"; | ||
| } | ||
| if (!Number.isInteger(count) || count < 0) { | ||
| return "Second argument must be a non-negative integer"; | ||
| } |
There was a problem hiding this comment.
I see you extensively use throw Error in other functions, is there a reason you want to use just return here?
Small point, no action required to complete this PR but you could improve your error messages to be something like throw Error("Second argument must be a non-negative integer, received: ${count} (${typeof count})") (same for str). It would be a bit easier to debug.
There was a problem hiding this comment.
changed returns to throw errors to match the rest in this sprint
wheresdiasd
left a comment
There was a problem hiding this comment.
It looks good overall, @jennethydyrova comments must be addressed IMO.
My comments are only suggestions to improve the code synthax.
Sprint-3/2-practice-tdd/count.js
Outdated
| @@ -1,5 +1,22 @@ | |||
| function countChar(stringOfCharacters, findCharacter) { | |||
| return 5 | |||
| if (arguments.length !== 2) { | |||
There was a problem hiding this comment.
That looks good, but can we be more specific about which arguments we are expecting? Using " arguments" works, but in my experience is not very common.
Sprint-3/2-practice-tdd/count.js
Outdated
| if (findCharacter.length !== 1) { | ||
| throw new Error("Character to find must be a single character."); | ||
| } | ||
| if (stringOfCharacters.length === 0) { |
There was a problem hiding this comment.
Would that be the same as
(!stringOfCharacters.length) ?
| if (typeof stringOfCharacters !== 'string'){ | ||
| throw new Error("First argument must be a string."); | ||
| } | ||
| if (typeof findCharacter !== "string") { |
There was a problem hiding this comment.
Can we wrap up this condition and the condition above into a single condition ?
Sprint-3/2-practice-tdd/count.js
Outdated
| if (stringOfCharacters.length === 0) { | ||
| return 0; | ||
| } | ||
| return Array.from(stringOfCharacters).filter(char => char === findCharacter).length; |
There was a problem hiding this comment.
Could we use spread operator here ? [...stringOfCharacters] ?
| // 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 if no occurrences of a character", () => { |
| @@ -1,5 +1,39 @@ | |||
| function getOrdinalNumber(num) { | |||
| return "1st"; | |||
| if (arguments.length !== 1) { | |||
There was a problem hiding this comment.
Again, can we be more specific about which arguments we are referring to?
| if (!isFinite(num)) { | ||
| throw new Error("Input must be a finite number"); | ||
| } | ||
| if (!Number.isInteger(num) || num < 0) { |
There was a problem hiding this comment.
Can we wrap all these conditions in one statement ?
| expect(getOrdinalNumber(1)).toEqual("1st"); | ||
| }); | ||
|
|
||
| test("should return '2nd' for 2", () => { |
| function repeat() { | ||
| return "hellohellohello"; | ||
| function repeat(str, count) { | ||
| if ( arguments.length !== 2) { |
There was a problem hiding this comment.
Same about the args here, could we be more specific ?
wheresdiasd
left a comment
There was a problem hiding this comment.
The PR LGTM as you've addressed @jennethydyrova changes, however, I left suggestions to improve code standards, please let me know if you want to discuss any item, we can book a call/pair programming to do it so.
Thanks.
|
Could you please solve conflicts on your branch before I mark it as completed ? |
…n and error handling
…n and error handling in newly files to reflect upstream changes
|
|
||
| test('should have the correct amount of arguments', () => { | ||
| expect(() => repeatStr('hello')).toThrow(new Error("Function requires exactly two arguments: a string and a count. Received 1 arguments")); | ||
| expect(() => repeatStr("hello", 3, 3)).toThrow(new Error("Function requires exactly two arguments: a string and a count. Received 3 arguments")); |
There was a problem hiding this comment.
We don't need to check if the function receives more than 2 arguments.
We need to check whether the arguments are expected or not.
In this case, you have 2 arguments, and your logic works fine. But that wouldn't be accepted in real use cases.
Ideally, you would first check if the function receives both str and count before proceeding to any other steps, and that would be enough.
In the real world, functions can indeed receive more parameters than they expect, but they don't do anything with these parameters.
wheresdiasd
left a comment
There was a problem hiding this comment.
The logic works, but adding a check to see if the function receives more arguments is unrealistic.
|
Removed the test for more than 2 arguments as you've pointed out in your previous comment and I've taken your comments on board |
wheresdiasd
left a comment
There was a problem hiding this comment.
The PR looks good, although I would still avoid the checking arguments.length whenever possible.
Self checklist
Changelist
I have implemented tests, and used tdd to implement the functions set out in the coursework.