Hone logo
Hone
Problems

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:

  1. Test Cache Hits: Verify that when data is present in the cache and requested, the get method returns the correct data and doesn't trigger a "fetch" operation (which we'll simulate).
  2. Test Cache Misses: Confirm that when data is not present in the cache, the get method returns undefined (or a similar indicator of a miss) and that a simulated "fetch" operation is triggered.
  3. Test Cache Setting: Ensure that data set using the set method is correctly stored and retrievable.
  4. Test Cache Invalidation: Verify that calling invalidate for a specific key removes that key-value pair from the cache, leading to subsequent cache misses.
  5. Test Global Invalidation: Test that a global invalidateAll method clears the entire cache.
  6. Simulate Asynchronous Operations: The get method should be able to handle an optional asynchronous data fetching function.

Expected Behavior:

  • A get call for a non-existent key should return undefined and trigger the provided fetch function.
  • A get call for an existing key should return the cached value and not trigger the fetch function.
  • A set call should store the key-value pair.
  • An invalidate call should remove the specified key.
  • An invalidateAll call should clear all cached items.

Edge Cases to Consider:

  • What happens if invalidate is called for a key that doesn't exist?
  • What happens if get is 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 the CacheManager class itself is provided and functional. You will be provided with the CacheManager class 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() and jest.notCalled() will be your friends.
  • Structure your tests logically, perhaps grouping them by the cache operation they are testing (get, set, invalidate).
  • The CacheManager class will be provided to you, so you don't need to implement it. You will need to write the Jest tests for it.
Loading editor...
typescript