Implementing a waitFor Function for Jest
Jest's built-in waitFor function is crucial for testing asynchronous operations and ensuring that a specific condition is met before proceeding with assertions. This challenge asks you to implement your own version of waitFor to deepen your understanding of asynchronous testing in Jest and TypeScript. A custom waitFor allows for more control and potentially different error handling strategies.
Problem Description
You need to implement a waitFor function that takes a test condition (a function that returns a boolean) and an optional timeout as arguments. The function should repeatedly execute the test condition until it returns true or the timeout is reached. If the timeout is reached, the function should throw an error indicating that the condition was never met.
Key Requirements:
- Asynchronous Execution: The
waitForfunction should handle asynchronous test conditions gracefully. The condition function can return a Promise. - Polling Interval: The function should poll the condition at a reasonable interval (e.g., 50ms) to avoid excessive CPU usage.
- Timeout Handling: The function must throw an error if the condition is not met within the specified timeout. The error message should clearly indicate that the timeout was reached.
- Clear Error Message: The error thrown on timeout should include the condition that was being waited for.
- TypeScript Support: The implementation must be written in TypeScript and properly typed.
Expected Behavior:
- If the condition becomes true before the timeout, the
waitForfunction should resolve (implicitly, by not throwing an error). - If the timeout is reached before the condition becomes true, the
waitForfunction should throw an error. - The function should not block the main thread while waiting.
Edge Cases to Consider:
- Condition function that immediately returns
true. - Condition function that immediately returns
false. - Condition function that throws an error.
- Timeout value of 0 (should throw an error immediately).
- Very short timeout values.
- Condition function that returns a Promise that rejects.
Examples
Example 1:
Input:
const condition = () => new Promise<boolean>((resolve) => setTimeout(() => resolve(true), 100));
const timeout = 200;
waitFor(condition, timeout);
Output: (No error thrown)
Explanation: The condition becomes true within the timeout period.
Example 2:
Input:
const condition = () => new Promise<boolean>((resolve) => setTimeout(() => resolve(false), 100));
const timeout = 50;
waitFor(condition, timeout);
Output: Error: Timeout - Expected condition to be true within 50ms.
Explanation: The condition never becomes true within the timeout period.
Example 3: (Edge Case - Promise Rejection)
Input:
const condition = () => new Promise<boolean>((resolve, reject) => setTimeout(() => reject(new Error("Condition failed")), 100));
const timeout = 200;
waitFor(condition, timeout);
Output: Error: Condition failed
Explanation: The promise rejects, and the error is propagated. The waitFor function should not continue polling after a rejection.
Constraints
- Timeout: The timeout value must be a positive number (in milliseconds). A timeout of 0 should be treated as an immediate timeout.
- Polling Interval: The polling interval should be between 20ms and 100ms.
- Error Handling: The function should handle Promise rejections gracefully, propagating the rejection error.
- TypeScript: The code must be valid TypeScript.
Notes
- Consider using
setTimeoutto implement the polling mechanism. - Think about how to handle Promise rejections within the condition function.
- The
waitForfunction should not return a value directly; it should either resolve implicitly or throw an error. - Focus on clarity and readability in your implementation. Good error messages are important.
- You can use
async/awaitto simplify the asynchronous logic.