Jest Cache Validation Challenge
As applications grow, caching becomes crucial for performance. However, ensuring that cached data is up-to-date and that the caching mechanism itself is functioning correctly can be challenging. This challenge focuses on building robust cache validation logic within your Jest tests.
Problem Description
You are tasked with creating a Jest test suite that validates the behavior of a hypothetical CacheManager class. This CacheManager simulates a simple in-memory cache with methods for get, set, and invalidate. Your goal is to write tests that cover various scenarios related to cache hits, misses, and the effectiveness of cache invalidation.
Key Requirements:
- Test Cache Hits: Verify that when data is present in the cache and requested, the
getmethod returns the correct data and doesn't trigger a "fetch" operation (which we'll simulate). - Test Cache Misses: Confirm that when data is not present in the cache, the
getmethod returnsundefined(or a similar indicator of a miss) and that a simulated "fetch" operation is triggered. - Test Cache Setting: Ensure that data set using the
setmethod is correctly stored and retrievable. - Test Cache Invalidation: Verify that calling
invalidatefor a specific key removes that key-value pair from the cache, leading to subsequent cache misses. - Test Global Invalidation: Test that a global
invalidateAllmethod clears the entire cache. - Simulate Asynchronous Operations: The
getmethod should be able to handle an optional asynchronous data fetching function.
Expected Behavior:
- A
getcall for a non-existent key should returnundefinedand trigger the provided fetch function. - A
getcall for an existing key should return the cached value and not trigger the fetch function. - A
setcall should store the key-value pair. - An
invalidatecall should remove the specified key. - An
invalidateAllcall should clear all cached items.
Edge Cases to Consider:
- What happens if
invalidateis called for a key that doesn't exist? - What happens if
getis called with an asynchronous fetch function that returns a promise?
Examples
Example 1: Basic Cache Hit
// Hypothetical CacheManager (for conceptual understanding)
class CacheManager<T> {
private cache: Map<string, T> = new Map();
async get(key: string, fetcher?: () => Promise<T>): Promise<T | undefined> {
if (this.cache.has(key)) {
return this.cache.get(key);
}
if (fetcher) {
const data = await fetcher();
this.cache.set(key, data);
return data;
}
return undefined;
}
set(key: string, value: T): void {
this.cache.set(key, value);
}
invalidate(key: string): void {
this.cache.delete(key);
}
invalidateAll(): void {
this.cache.clear();
}
}
// In your test:
const cacheManager = new CacheManager<string>();
await cacheManager.set("user:1", "Alice");
// Call get for "user:1" without a fetcher
const result = await cacheManager.get("user:1");
// Expected result: "Alice"
Example 2: Cache Miss and Fetch
// Using the same CacheManager as above...
const cacheManager = new CacheManager<string>();
const mockFetcher = jest.fn().mockResolvedValue("Bob");
// Call get for "user:2" which is not in the cache, with a fetcher
const result = await cacheManager.get("user:2", mockFetcher);
// Expected result: "Bob"
// Expected behavior: mockFetcher should have been called once.
Example 3: Cache Invalidation
// Using the same CacheManager as above...
const cacheManager = new CacheManager<string>();
await cacheManager.set("user:3", "Charlie");
// Invalidate the key
cacheManager.invalidate("user:3");
// Attempt to get the key again
const result = await cacheManager.get("user:3");
// Expected result: undefined
Constraints
- Your solution should be written in TypeScript.
- You must use Jest for testing.
- You should mock any external dependencies (like a hypothetical API call for fetching data) using
jest.fn(). - Focus on testing the
CacheManager's logic; assume theCacheManagerclass itself is provided and functional. You will be provided with theCacheManagerclass to test against. - Tests should be efficient and avoid unnecessary delays.
Notes
- Consider how you will simulate the asynchronous nature of data fetching.
jest.fn().mockResolvedValue()is a good starting point. - Think about how to assert that a function was or was not called.
jest.toHaveBeenCalled()andjest.notCalled()will be your friends. - Structure your tests logically, perhaps grouping them by the cache operation they are testing (
get,set,invalidate). - The
CacheManagerclass will be provided to you, so you don't need to implement it. You will need to write the Jest tests for it.