Spying on a Method in Jest: Mocking and Verification
This challenge focuses on using Jest's mocking capabilities to spy on a method within an object. Spying allows you to track how many times a method is called, what arguments it receives, and even replace its implementation with a mock function, all while maintaining the original method's existence. This is crucial for isolating units of code during testing and verifying interactions between components.
Problem Description
You are given a module calculator.ts containing a Calculator class with a calculateDiscountedPrice method. This method takes a price and a discount percentage as input and returns the discounted price. You need to write a Jest test that spies on the calculateDiscountedPrice method of a Calculator instance.
The test should:
- Create an instance of the
Calculatorclass. - Spy on the
calculateDiscountedPricemethod of the instance. - Call a separate method,
applyDiscount, which internally callscalculateDiscountedPrice. - Verify that
calculateDiscountedPricewas called exactly once. - Verify that
calculateDiscountedPricewas called with the correct arguments (price: 100, discount: 10).
Examples
Example 1:
Input: calculator.ts (see below), applyDiscount.ts (see below), and a Jest test file.
Output: A Jest test that passes, verifying the spy on calculateDiscountedPrice.
Explanation: The test creates a Calculator instance, spies on calculateDiscountedPrice, calls applyDiscount, and then asserts that calculateDiscountedPrice was called once with the expected arguments.
Example 2: (Edge Case - No Discount)
Input: calculator.ts (see below), applyDiscount.ts (see below), and a Jest test file.
Output: A Jest test that passes, verifying the spy on calculateDiscountedPrice.
Explanation: Even if the discount is 0, the spy should still be called once with the correct arguments.
Constraints
- The solution must be written in TypeScript.
- The solution must use Jest's
spyOnfunction. - The solution must verify both the call count and the arguments passed to the spied method.
- The solution must not modify the original
calculateDiscountedPricemethod's implementation unless explicitly required for the test setup.
Notes
- Consider using
mockImplementationif you need to control the return value of the spied method during the test. However, for this problem, simply verifying the call is sufficient. - Pay close attention to the order of operations: create the instance, spy on the method, call the method that uses the spied method, and then verify the spy.
- The
applyDiscountmethod is provided to encapsulate the call tocalculateDiscountedPrice, making the test more focused on spying.
Files to be provided (for context - you don't need to create these, just understand their purpose):
calculator.ts:
export class Calculator {
calculateDiscountedPrice(price: number, discount: number): number {
return price - (price * discount / 100);
}
}
applyDiscount.ts:
import { Calculator } from './calculator';
export function applyDiscount(calculator: Calculator, price: number, discount: number): number {
return calculator.calculateDiscountedPrice(price, discount);
}