use-swr-middlewares.test.tsx
Overview
This file contains a comprehensive test suite for verifying the middleware functionality of the useSWR React hook from the SWR library. SWR (stale-while-revalidate) is a popular data fetching library that provides built-in support for caching, revalidation, and request deduplication using React hooks.
The primary focus of this test file is to ensure that the middleware mechanism within useSWR works correctly in various scenarios. Middleware in SWR allows for extending or customizing the behavior of the hook by wrapping the original hook with additional logic (e.g., logging, modifying keys, caching strategies).
The tests cover:
Basic usage of middleware.
Passing original keys and null fetchers to middleware.
Middleware integration via SWR context configuration.
Composing and ordering multiple middleware layers.
Using React hooks inside middleware.
Modifying keys within middleware.
Handling non-serialized keys in middleware.
This file uses React Testing Library (@testing-library/react) to render components and assert on DOM output, along with Jest mocks for tracking middleware effects.
Detailed Explanation of Test Cases and Middleware Usage
Common Utilities Imported
createKey(): generates unique keys for SWR requests.createResponse(): simulates a fetch response.sleep(),nextTick(): timing helpers for async operations.renderWithConfig(): renders React components with optional SWR configuration context.
1. Test: should use middleware
Purpose: Verify middleware function is called with the correct key.
Middleware:
loggerMiddlewarelogs the SWR key passed to it.Usage: Passed via the
useoption inuseSWRhook.Assertions: The key is logged twice (initial render + data ready), and the logged key is correct.
Example:
const loggerMiddleware: Middleware = useSWRNext => (key, fetcher, config) => {
console.log(key)
return useSWRNext(key, fetcher, config)
}
2. Test: should pass original keys to middleware
Purpose: Middleware receives the exact key array when an array key is used.
Key: An array
[key, 1, 2, 3].Middleware: Logs the key.
Assertion: Middleware receives the full array key.
3. Test: should pass null fetcher to middleware
Purpose: Middleware receives
nullas the fetcher function when specified.Scenario:
useSWR(key, null, { use: [middleware] }).Middleware: Logs the fetcher argument.
Assertion: Middleware gets
nullas fetcher.
4. Test: should support 'use' option in context
Purpose: Middleware can be applied globally using SWR context.
Setup: Wrap render with
renderWithConfig(<Page />, { use: [loggerMiddleware] }).Assertion: Middleware receives the key and is called twice.
5. Test: should support extending middleware via context and per-hook config
Purpose: Test multiple middleware layers applied via nested SWR contexts and hook config.
Setup: SWRConfig nesting with middlewares
[2]and[1], and hook config with[0].Middleware: Each logs its id and the key.
Assertion: Logs show correct order of middleware calls: 2, 1, 0 (twice).
6. Test: should use the correct middleware order in 'withMiddleware'
Purpose: Verify middleware order when using the internal
withMiddlewarehelper.Setup: Compose three middlewares with enter/exit logs.
Custom Hook:
customSWRHookwrapsuseSWRwith middleware.Assertion: Logs show correct nested enter/exit call order, demonstrating middleware wrapping order.
7. Test: should support react hooks inside middleware
Purpose: Confirm React hooks (e.g.,
useRef) can be used inside middleware.Middleware:
lazyMiddlewarecaches data in a ref and returns stale data until new data arrives.Scenario: Key changes from
${key}-0to${key}-1asynchronously.Assertion: Data is preserved while fetching new data, then updates correctly.
8. Test: should pass modified keys to the next middleware and useSWR
Purpose: Middleware can modify the key before passing it along.
Middleware: Two key-decorating middlewares wrap the key with symbols.
Assertion: Final key passed to SWR has decorations from both middlewares.
9. Test: should send the non-serialized key to the middleware
Purpose: Middleware receives the original (non-serialized) key.
Middleware: Receives array key, serializes it, and passes stringified key to
useSWRNext.Fetcher: Parses stringified key to access object parameter.
Assertion: Middleware confirms key is array; component renders data based on parsed key.
Important Implementation Details
Middleware Signature:
Middleware in SWR wraps the next hook function like:
const middleware: Middleware = (useSWRNext) => (key, fetcher, config) => { // custom logic here return useSWRNext(key, fetcher, config) }Middleware Composition:
Middleware can be stacked via:
Passing multiple middlewares in the
usearray option ofuseSWR.Providing middleware in the SWR context (
SWRConfig).Combining both context and per-hook middleware, with context middleware executing first.
Key Modifications:
Middlewares can modify the key before passing it to the next middleware or
useSWRNext, allowing features like key decoration or serialization.React Hooks Inside Middleware:
Middleware can safely use React hooks (
useState,useRef, etc.) as middleware is effectively a React hook wrapper.Internal
withMiddlewareUtility:The file tests
withMiddlewarefrom SWR internals, which composes middleware layers into a new hook.
Interaction with Other Modules
useSWRHook:This file tests the core
useSWRhook's middleware functionality, ensuring that middlewares integrate seamlessly with SWR's data fetching lifecycle.SWRConfig:Middleware can be globally configured via
SWRConfigcontext provider, allowing centralized middleware injection.Utilities:
The file imports helper functions from a local
./utilsmodule for key creation, response simulation, async control, and rendering with configuration.React Testing Library:
Utilizes React Testing Library (
@testing-library/react) for rendering components, querying DOM nodes, and waiting for asynchronous UI updates.Jest:
Uses Jest mocks (
jest.fn) to track middleware invocations and verify call parameters.
This file is primarily a test utility and is not directly part of the production runtime but ensures core middleware functionality correctness.
Usage Examples
Below is a distilled example of how middleware is applied and tested:
const loggerMiddleware: Middleware = useSWRNext => (key, fetcher, config) => {
console.log('middleware key:', key)
return useSWRNext(key, fetcher, config)
}
function Page() {
const { data } = useSWR('my-key', () => fetchData(), {
use: [loggerMiddleware]
})
return <div>{data}</div>
}
The test verifies that loggerMiddleware is called with 'my-key' and that the component renders data as expected.
Mermaid Diagram: Middleware Flowchart
This flowchart illustrates the middleware wrapping and execution sequence in useSWR as tested in this file:
flowchart TD
A[useSWR hook call] --> B{Middleware Stack}
B -->|Middleware 1| C1[Logger Middleware]
B -->|Middleware 2| C2[Decorating Key Middleware]
B -->|Middleware n| Cn[Lazy Middleware]
C1 --> D[Modified key / fetcher]
C2 --> D
Cn --> D
D --> E[useSWRNext (original SWR hook)]
E --> F[Data fetching & caching]
F --> G[Return data to component]
Explanation:
The
useSWRhook call is passed through a stack of middleware.Each middleware can inspect/modify the key, fetcher, and config.
Middleware wrap each other in order; the last middleware calls the original
useSWR.The final data result is passed back up through middleware to the React component.
Summary
The use-swr-middlewares.test.tsx file rigorously tests the middleware extension points of the useSWR React hook. It validates middleware parameters, composition order, React hook compatibility, key transformation, and middleware injection via hook options and context providers. The tests ensure that middleware behaves predictably, enabling developers to customize data fetching behavior reliably in SWR-powered applications.