Testing Decorators with Jest in TypeScript
Decorators are a powerful feature in TypeScript that allow you to modify classes, methods, properties, or parameters. Ensuring your decorators function correctly is crucial for maintaining code quality and preventing unexpected behavior. This challenge focuses on writing Jest tests to verify the functionality of a simple decorator.
Problem Description
You are given a decorator factory called logExecutionTime. This factory takes a prefix string as an argument and returns a decorator that logs the execution time of a function to the console. Your task is to write Jest tests to verify that the logExecutionTime decorator works as expected. Specifically, you need to test that:
- The decorator logs a message to the console with the correct prefix and execution time.
- The original function is still executed and its return value is preserved.
- The decorator doesn't modify the original function's signature.
Examples
Example 1:
Input:
- Function: `add(a: number, b: number): number` returning `a + b`
- Prefix: "Adding"
Output:
- Console log: "Adding: 123ms" (where 123ms is the execution time)
- Return value: 5 (the result of `add(2, 3)`)
Explanation: The decorator should log the execution time of the `add` function with the prefix "Adding" and return the original function's result.
Example 2:
Input:
- Function: `greet(name: string): string` returning `Hello, ${name}!`
- Prefix: "Greeting"
Output:
- Console log: "Greeting: 45ms" (where 45ms is the execution time)
- Return value: "Hello, Alice!" (the result of `greet("Alice")`)
Explanation: Similar to Example 1, the decorator should log the execution time with the prefix "Greeting" and return the original function's result.
Example 3: (Edge Case - Very Fast Function)
Input:
- Function: `identity(x: number): number` returning `x`
- Prefix: "Identity"
Output:
- Console log: "Identity: <very small time, e.g., 0.1ms>"
- Return value: 10 (the result of `identity(10)`)
Explanation: Even for very fast functions, the decorator should still log a time (even if it's very small) and return the original function's result.
Constraints
- The execution time should be measured in milliseconds.
- The prefix string provided to the decorator factory should be used verbatim in the console log.
- The decorator should not alter the original function's return type or arguments.
- You are allowed to use
jest.spyOnto mockconsole.logfor assertion purposes. - The time measurement should be reasonably accurate (within a few milliseconds).
Notes
- You'll need to use
jest.useFakeTimers()to control the timing of the execution and make your tests deterministic. Remember tojest.advanceTimersByTime(time)to simulate the passage of time. - Consider using
jest.spyOnto mockconsole.logand assert that the correct message is logged. - Think about how to ensure the original function is still called and returns the correct value.
- The
logExecutionTimedecorator factory and the functions to be decorated are provided below. You only need to write the Jest tests.
function logExecutionTime(prefix: string): <T extends (...args: any[]) => any>(target: T) => T {
return function (target: T) {
const original = target;
return function (...args: any[]) {
let startTime = performance.now();
const result = original.apply(this, args);
let endTime = performance.now();
let executionTime = endTime - startTime;
console.log(`${prefix}: ${executionTime.toFixed(0)}ms`);
return result;
};
};
}