use-swr-revalidate.test.tsx
Overview
This file contains a comprehensive suite of unit tests for verifying the revalidation behavior of the useSWR React hook from the SWR library. Revalidation in SWR refers to the process of fetching fresh data and updating the cache and UI accordingly.
The tests focus on various scenarios involving the mutate function (used to trigger revalidation), concurrent requests, race conditions, deduplication intervals, and internal state flags such as isValidating. The goal is to ensure that the SWR hook behaves correctly under different usage patterns related to manual and automatic data revalidation.
Detailed Explanation
Imports and Utilities
@testing-library/react: Provides utilities for rendering components and simulating user interactions.useState from React: Used in some test components to simulate component state changes.
useSWRanduseSWRConfigfromswr: The hook under test and the global SWR configuration context.Utility functions imported from
./utils:createResponse: Creates a Promise that resolves with a value after an optional delay.sleep: Pauses execution for a given time.nextTick /
waitForNextTick: Utilities to wait for next JavaScript event loop tick.createKey: Generates unique cache keys for SWR.renderWithConfig: Renders components wrapped with any necessary SWR configuration.
Test Suites and Tests
The file defines a Jest test suite named 'useSWR - revalidate' containing multiple tests.
Test 1: Rerender after triggering revalidation
it('should rerender after triggering revalidation', async () => { ... })
Purpose: Verify that calling
mutate()triggers SWR to re-fetch data and rerender the component with updated data.Implementation Details:
A simple counter
valueincrements each fetch.The component uses
useSWR(key, () => value++).On button click, calls
mutate()which triggers revalidation.
Expected Behavior:
Initial render shows
data: 0.After clicking the button and waiting, UI updates to
data: 1.
Test 2: Revalidate all hooks with the same key
it('should revalidate all the hooks with the same key', async () => { ... })
Purpose: Ensure that multiple
useSWRhooks with the same key share cache and revalidate together.Implementation Details:
Two
useSWRhooks use the same key and fetcher.The first hook exposes
mutate().On mutate, both hooks should update data.
Expected Behavior:
Initially shows
0, 0.After mutation, both update to
1, 1.
Test 3: Handle race conditions in revalidation sequences
it('should respect sequences of revalidation calls (cope with race condition)', async () => { ... })
Purpose: Validate that SWR correctly handles out-of-order or concurrent fetches and maintains the latest data.
Implementation Details:
Two fetches triggered in quick succession with different delays.
The second fetch returns faster with updated data.
Expected Behavior:
Despite the first fetch being slower, UI shows the result of the faster second fetch (
data: 1).
Test 4: isValidating state with concurrent requests
it('should keep isValidating be true when there are two concurrent requests', async () => { ... })
Purpose: Confirm that
isValidatingremainstruewhile any revalidation is in progress.Implementation Details:
Two mutate calls triggered sequentially.
The test verifies
isValidatingtoggles correctly as requests complete.
Expected Behavior:
isValidatingistruewhen at least one revalidation is pending.Turns
falseonly after all requests finish.
Test 5: Revalidation calls respected despite dedupingInterval
it('should respect sequences of revalidation calls although in dedupingInterval', async () => { ... })
Purpose: Ensure
mutate()forces revalidation even if within the deduplication interval.Implementation Details:
Two fetches with delays and a dedupingInterval of 30ms.
The first fetch takes 50ms; the second is immediate.
Expected Behavior:
After both mutations, UI shows the updated count
2.
Test 6: isValidating initially false if config.isPaused is true
it('should set initial isValidating be false when config.isPaused returns true', async () => { ... })
Purpose: Check that when SWR is paused (
isPausedreturnstrue),isValidatingis false initially.Implementation Details:
Passes
isPaused: () => trueconfig touseSWR.
Expected Behavior:
The component shows
falseforisValidating.
Test 7: Key invalidation and deduping cleared by mutate() without mounted hooks
it('should mark the key as invalidated and clear deduping with `mutate`, even if there is no mounted hook', async () => { ... })
Purpose: Verify that calling
mutate()invalidates the key and clears deduplication cache even if no components are mounted using that key.Implementation Details:
Component
Foouses a key with dedupingInterval.Pagetoggles mounting ofFooand triggersmutate(key)when unmounted.
Expected Behavior:
After toggling and mutating, the next mount fetches updated data (
data: 1).
Important Implementation Details and Algorithms
Revalidation via
mutate(): Callingmutate()triggers SWR to re-fetch data and update the cache, which causes components using that key to rerender.Key-based cache sharing: Multiple hooks with the same key share data and revalidation state.
Race condition handling: SWR ensures that the latest fetch result wins, avoiding stale data overwriting fresh data.
Deduplication interval: SWR deduplicates fetch calls within a short interval, but
mutate()bypasses this to force refresh.isValidatingflag: Tracks if revalidation is in progress; remains true if any request is still pending.Pause mechanism: The
isPausedconfig can halt automatic revalidation and setisValidatingto false initially.Key invalidation without mounted hooks: SWR allows mutation of cache keys even if no components are actively using them, supporting background updates.
Interaction with Other Parts of the System
useSWRHook: The primary subject of testing; this file verifies its revalidation logic.useSWRConfig: Used to access global SWR configuration andmutatefunction for cache manipulation../utils: Provides helper functions likecreateKey,createResponse, and testing utilities (renderWithConfig) to facilitate isolated component testing.React Testing Library: Used to render components and simulate user interactions like clicks.
React: Manages component lifecycle and state during tests.
The tests simulate user interactions and asynchronous data fetching to validate SWR’s internal cache and revalidation mechanisms work as intended in a React environment.
Usage Examples
All usage examples are embedded in the tests themselves. For instance, the simplest example to trigger revalidation is:
const key = createKey();
function Page() {
const { data, mutate } = useSWR(key, () => value++);
return <button onClick={() => mutate()}>data: {data}</button>;
}
Clicking the button triggers mutate(), which re-fetches data and rerenders the button with updated content.
Mermaid Diagram: Component Interaction Flowchart
This flowchart illustrates the main interactions in the test file, focusing on how components use useSWR, trigger mutate(), and update UI based on revalidation.
flowchart TD
A[Start: Test Initialization]
B[Render Component with useSWR]
C[Initial fetch triggered by useSWR]
D[Render UI with data]
E[User triggers mutate()]
F[mutate() calls revalidation]
G[Fetcher function executes]
H[Cache updated with new data]
I[Component rerenders with new data]
J[Optional concurrent mutate() calls]
K[isValidating state updates accordingly]
A --> B
B --> C
C --> D
D --> E
E --> F
F --> G
G --> H
H --> I
I --> E
E --> J
J --> K
K --> I
Summary
This test file rigorously verifies the behavior of the useSWR hook's revalidation features under a variety of realistic and edge-case scenarios. It ensures that developers can rely on mutate() to correctly trigger data refreshes, handle concurrency, respect deduplication, and maintain accurate UI and internal state indications (isValidating). The tests also confirm that SWR’s cache and key invalidation mechanisms are robust even when no components are currently mounted.
This file is critical for maintaining the integrity of SWR’s core revalidation functionality and interacts closely with SWR’s caching and hook lifecycle mechanisms.