Welcome to your second lesson for this course dedicated to practicing Test Driven Development (TDD) utilizing TypeScript and Jest. In this unit, we will continue adding featurs to our calculateDiscount
function. We have 5 more requirements for you to implement!
In this course, emphasis is placed on hands-on practice, where you'll receive requirements through tests, one at a time. Your task is to implement code that makes each test pass, simulating a real-world TDD environment. As the course guide, it's akin to being your pair programmer, providing test-driven prompts to hone your skills as you progress.
As a reminder, the Red-Green-Refactor cycle is central to TDD, guiding your development process:
- Red: Start by writing a failing test to define the next step.
- Green: Implement just enough code to pass the test, focusing on functionality.
- Refactor: Optimize the code for clarity and efficiency without changing its behavior.
- Description: The function should validate that the price is a numeric value and throw an error if a non-numeric input is provided.
- Test Case:
TypeScript
1it('should throw an error for non-numeric price inputs', () => { 2 // Arrange 3 const originalPrice = 'invalid' as any; 4 const discountPercentage = 10; 5 6 // Act, Assert 7 expect(() => calculateDiscount(originalPrice, discountPercentage)).toThrow('Price must be a valid number'); 8});
- Description: The function should validate that the discount percentage is a numeric value and throw an error if a non-numeric input is provided.
- Test Case:
TypeScript
1it('should throw an error for non-numeric discount inputs', () => { 2 // Arrange 3 const originalPrice = 100; 4 const discountPercentage = 'invalid' as any; 5 6 // Act, Assert 7 expect(() => calculateDiscount(originalPrice, discountPercentage)).toThrow('Discount must be a valid number'); 8});
- Description: The function should ensure that very small prices do not fall below a defined minimum value after discounts are applied.
- Test Case:
TypeScript
1it('should handle very small prices correctly', () => { 2 // Arrange 3 const originalPrice = 0.001; 4 const discountPercentage = 1; 5 const expectedDiscountedPrice = 0.01; // Should not go below 0.01 6 7 // Act 8 const result = calculateDiscount(originalPrice, discountPercentage); 9 10 // Assert 11 expect(result).toBe(expectedDiscountedPrice); 12});
- Description: The function should apply a minimum discount percentage of 1% if a lower percentage is provided.
- Test Case:
TypeScript
1it('should apply minimum discount amount when discount is less than minimum', () => { 2 // Arrange 3 const originalPrice = 100; 4 const discountPercentage = 0.1; // 0.1% discount 5 const expectedDiscountedPrice = 99; // Should apply minimum 1% discount 6 7 // Act 8 const result = calculateDiscount(originalPrice, discountPercentage); 9 10 // Assert 11 expect(result).toBe(expectedDiscountedPrice); 12});
- Description: The function should cap the discount at a maximum dollar value of $500, even if the calculated discount would exceed that cap.
- Test Case:
TypeScript
1it('should cap the maximum discount amount at $500', () => { 2 // Arrange 3 const originalPrice = 2500; 4 const discountPercentage = 30; // Would normally be $750 off 5 const expectedDiscountedPrice = 2000; // Should only apply $500 maximum discount 6 7 // Act 8 const result = calculateDiscount(originalPrice, discountPercentage); 9 10 // Assert 11 expect(result).toBe(expectedDiscountedPrice); 12});
In this section, you practiced implementing and testing advanced requirements for the calculateDiscount function. These included handling invalid, non-numeric inputs; managing very small prices to ensure minimum price thresholds are met; and applying specific discount constraints, such as enforcing a minimum discount percentage and capping the maximum allowable discount amount.
As you proceed with the practice exercises, keep the Red-Green-Refactor cycle in mind to guide your process. In this unit:
- Each test prompts you to refine the function's robustness, beginning with the "Red" phase by writing tests for additional edge cases.
- In the "Green" phase, aim to pass each test by incrementally adding necessary logic, such as input validation and boundary enforcement.
- The "Refactor" phase offers the chance to simplify and optimize your code after passing all tests, ensuring that it is not only correct but also clear and maintainable.
These exercises deepen your TDD skills by applying practical constraints and validations, simulating real-world requirements where robustness and reliability are essential.