use-swr-local-mutation.test.tsx
Overview
This file contains a comprehensive suite of unit and integration tests for local mutation behaviors in the SWR React data fetching library. Specifically, it tests how mutations on the local cache interact with data fetching, revalidation, optimistic UI updates, error handling, and concurrency control.
The tests verify the correctness and robustness of the mutate API exposed by useSWR and useSWRConfig. This includes programmatically triggering revalidation, sharing local state, supporting async mutations, deduplication of requests, optimistic updates, rollback behavior on errors, key filtering for mutations, and the interaction between mutation and revalidation.
The file uses React Testing Library with Jest to render components and simulate user interactions, validating UI state transitions.
Detailed Explanations
Key imports
useSWR,useSWRConfig,useSWRInfinite, andmutate(renamed asglobalMutate): Core SWR hooks and mutation API.Testing utilities:
act,screen,fireEvent.Local test utilities (
createResponse,sleep,nextTick,createKey,renderWithConfig,renderWithGlobalCache,executeWithoutBatching): Helpers for rendering, simulating async delays, and creating test keys and responses.
Test Suite: "useSWR - local mutation"
Each it block defines a test case focusing on a specific aspect of local mutation behavior.
Example Test Cases and Concepts
1. Programmatic Revalidation
it('should trigger revalidation programmatically', async () => {
let value = 0, mutate;
const key = createKey();
function Page() {
mutate = useSWRConfig().mutate;
const { data } = useSWR(key, () => value++, { dedupingInterval: 0 });
return <div>data: {data}</div>;
}
renderWithConfig(<Page />);
await screen.findByText('data: 0');
act(() => {
mutate(key);
});
await screen.findByText('data: 1');
});
Purpose: Verify
mutate(key)triggers revalidation (refetch) of the data forkey.Implementation Detail: Uses
dedupingInterval: 0to avoid deduplication blocking refetch.
2. Shared Local State Without Fetcher
const useSharedState = (key, fallbackData) => {
const { data: state, mutate: setState } = useSWR(`${baseKey}--${key}`, { fallbackData });
return [state, setState];
};
Purpose: Demonstrates how
useSWRcan be used as a shared local state container by omitting a fetcher.Usage: Two
useSharedStatehooks manage independent pieces of state (nameandjob), updated synchronously on click.
3. Mutation with Async Promise
await act(() => {
return mutate(key, createResponse(999), false);
});
await screen.findByText('data: 999');
Purpose: Tests support for passing a Promise or async function to
mutateto asynchronously update cache and UI.Parameters:
key: cache key.data: Promise resolving to new data.revalidate:falsemeans no automatic revalidation after mutation.
4. Optimistic UI Updates
await executeWithoutBatching(() =>
mutate(createResponse('baz', { delay: 20 }), {
optimisticData: 'bar'
})
);
Purpose: Tests optimistic updates where UI immediately shows
optimisticDatabefore actual mutation resolves.Options:
optimisticData: Data to show immediately.rollbackOnError: Controls rollback on mutation failure.
5. Rollback on Mutation Failure
try {
await mutate(createResponse(new Error('baz'), { delay: 20 }), {
optimisticData: 'bar'
});
} catch (e) {
expect(e.message).toEqual('baz');
}
Purpose: Validates that on mutation error, UI rolls back to previous data unless
rollbackOnErroris disabled.
6. Key Filtering for Mutation
mutate(
k => typeof k === 'string' && k.startsWith(key),
data => 'value-' + data.replace(key, ''),
false
);
Purpose: Shows how
mutatecan accept a key filter function to mutate multiple keys selectively.Use Case: Bulk update or clear cache entries matching certain criteria.
Important Implementation Details
Deduplication: Many tests use
dedupingIntervalto control request deduplication behavior, ensuring fresh fetches or avoiding redundant requests.Mutation Cancellation: Tests validate ongoing fetches or mutations are canceled or ignored properly when newer mutations occur.
Serialization of Keys: Keys are serialized consistently (e.g., handling
nullinside arrays).Mutation Concurrency: Ensures that only the latest mutation updates the cache and UI, avoiding race conditions.
Mutation Return Value: Mutation returns a Promise resolving to the new cache value or rejects on error.
Referential Stability: The bound
mutatefunction fromuseSWRmaintains referential equality for optimization.Populate Cache Hook: Mutation option
populateCacheallows transforming mutation results before writing to cache.Optimistic Data Variants:
optimisticDatacan be a static value or a function that receives current/ displayed data.Error Handling: Error states in cache are only updated under certain mutation conditions.
How This File Interacts With Other System Parts
SWR Core: Tests cover the
mutateanduseSWRAPIs from the SWR library.React Components: Simulates React components using SWR hooks to verify UI updates in response to mutations.
Cache Layer: Manipulates and verifies the internal SWR cache via
useSWRConfig().mutate.Test Utilities: Uses local utils (
createResponse,sleep,renderWithConfig) to create controlled async behaviors and render components with SWR context.
This test file ensures the correctness and reliability of SWR's local mutation API, critical for applications that require immediate UI feedback and consistent data synchronization.
Usage Examples
Programmatic Revalidation
const { mutate } = useSWRConfig();
mutate(key); // triggers revalidation (refetch)
Optimistic Update with Rollback
mutate(key, fetchNewData(), {
optimisticData: previousData,
rollbackOnError: true
});
Bulk Mutation via Key Filter
mutate(
key => key.startsWith('user:'),
newValue,
false
);
Mermaid Diagram
flowchart TD
A[Tests Suite: useSWR local mutation]
A --> B[Programmatic Revalidation Tests]
A --> C[Shared Local State Tests]
A --> D[Async Mutation Tests]
A --> E[Optimistic Update & Rollback Tests]
A --> F[Key Filter & Bulk Mutation Tests]
A --> G[Error Handling & Race Condition Tests]
A --> H[Mutation Options & Behavior Tests]
D --> D1[Promise-based mutation]
D --> D2[Async function mutation]
E --> E1[OptimisticData static value]
E --> E2[OptimisticData function]
E --> E3[Rollback on error]
F --> F1[Filter by key predicate]
F --> F2[Clear cache with filter]
G --> G1[Cancel in-flight requests]
G --> G2[Ignore outdated mutations]
H --> H1[populateCache transform]
H --> H2[referential equality of mutate]
Summary
This test file validates the local mutation capabilities of SWR, ensuring that mutations update cache and UI correctly, handle async and concurrent updates safely, support optimistic UI patterns with rollback, and offer flexible mutation targeting and transformation options. It is a critical component in guaranteeing SWR's mutation API behaves as expected in complex real-world scenarios.