utils.test.tsx
Overview
This file contains unit tests for utility functions imported from the internal SWR library (swr/_internal). Specifically, it tests the correctness, stability, and behavior of the following utilities:
normalize: A function that standardizes the arguments passed to data fetching hooks.stableHash(aliased ashash): A function that generates a deterministic, stable hash string from arbitrary input values.serialize: A serialization helper used internally bystableHash.mergeConfigs: A function that merges multiple configuration objects, combining properties like middleware and fallbacks.
The tests ensure these utilities behave as expected for various inputs, including edge cases like circular references, complex objects, and special JavaScript values.
The file uses Jest testing framework with the @edge-runtime/jest-environment, indicating the tests are run in an Edge Runtime environment.
Detailed Functionality and Tests
Imported Utilities
The file imports the following from swr/_internal:
Function | Purpose |
|---|---|
| Generates a stable, unique hash string for any input. |
| Serializes input arguments to a string representation. |
| Normalizes the arguments passed to SWR hooks. |
| Deep merges SWR configuration objects. |
Test Suite: Utils
The suite is composed of several test cases verifying different aspects of the utilities.
1. normalize Function Tests
Purpose:normalize takes an array of arguments and returns a tuple [key, fetcher, options], standardizing the inputs for SWR hook calls.
Test Cases:
Only
keyprovided →[key, null, {}]keyandnull(no fetcher) →[key, null, {}]keyand fetcher function →[key, fetcher, {}]keyand options →[key, null, options]key,nullfetcher, and options →[key, null, options]key, fetcher, and options →[key, fetcher, options]
Usage Example:
const [key, fetcher, opts] = normalize(['user/1', fetchUser, { revalidateOnFocus: false }]);
// key = 'user/1'
// fetcher = fetchUser
// opts = { revalidateOnFocus: false }
2. stableHash (aliased as hash) Function Tests
Purpose:stableHash produces a string hash that uniquely identifies the input arguments, handling complex types and ensuring stability across identical inputs.
Test Highlights:
Handles primitive types (
string,number,boolean,null,undefined,NaN,Infinity).Correctly serializes special characters (e.g., quotes).
Supports BigInt, Date objects (using
.toJSON()), RegExp, Symbols.Treats Sets, Maps, and ArrayBuffers with identity checks (same instance → same hash).
Serializes nested objects with consistent key ordering (stable across different key orders).
Detects and handles circular references without errors.
Generates unique hashes for functions and class constructors (non-serializable objects).
Ensures same reference inputs produce identical hashes, different functions produce different hashes.
Combines multiple arguments into a single hash string.
Example:
const keyHash = hash(['user', 1, { active: true }]);
// Produces a stable string uniquely representing these inputs
3. mergeConfigs Function Tests
Purpose:mergeConfigs merges two configuration objects, combining middleware arrays (use) and merging fallback data objects.
Test Cases:
Middleware arrays are concatenated.
Fallback objects are deeply merged (properties combined).
Example:
const configA = { use: [middlewareA], fallback: { user: { name: 'Alice' } } };
const configB = { use: [middlewareB], fallback: { post: { id: 1 } } };
const merged = mergeConfigs(configA, configB);
// merged.use = [middlewareA, middlewareB]
// merged.fallback = { user: { name: 'Alice' }, post: { id: 1 } }
Implementation Details & Algorithms
Stable Hashing Algorithm:
The hashing function uses a custom serialization mechanism to convert a wide variety of JavaScript values into a string form that is:Stable: Same inputs always produce the same output, regardless of property order in objects.
Unique: Different inputs produce different hashes.
Handles Circular References: Prevents infinite loops by tracking encountered objects.
Supports Special Types: Converts dates, regexes, symbols, buffers, sets, maps, and functions into string representations or unique IDs.
Normalization Logic:
The normalization function disambiguates the argument list for SWR hooks, inferring missing parameters and defaulting unset options, enabling flexible API usage.Deep Configuration Merge:
The merge function specially handles arrays and nested objects to combine configurations without overwriting.
Interaction with Other System Components
These utility functions are foundational for the SWR data fetching library's internal workings.
They are used primarily by the SWR React hooks to process hook arguments (
normalize), create cache keys (stableHash), and merge user and default configurations (mergeConfigs).The tests ensure robustness and correctness of these core utilities, impacting data fetching, caching, and revalidation logic across the application.
By verifying these utilities, the file indirectly supports consistent cache key generation and configuration management throughout the SWR-powered data layer.
Visual Diagram
flowchart TD
A[normalize(args)] -->|Returns| B[[key, fetcher, options]]
C[serialize(args)] --> D[serialization string]
D --> E[stableHash(args)]
E --> F[stable, unique hash string]
G[mergeConfigs(configA, configB)] --> H[mergedConfig]
subgraph Utils
A
E
G
C
end
style Utils fill:#f9f,stroke:#333,stroke-width:1px
Summary
utils.test.tsx is a comprehensive test suite that validates crucial internal utility functions of the SWR library. The tested utilities provide:
Argument normalization for flexible API usage.
Stable hashing of diverse JavaScript values for cache key generation.
Deep merging of configuration objects.
These utilities are vital for SWR's correct operation in caching and revalidation, and the tests guarantee their reliability across many edge cases and data types.
Example Usage in Codebase (Hypothetical)
import useSWR from 'swr';
function fetcher(url: string) {
return fetch(url).then(res => res.json());
}
function MyComponent() {
// Internally, `normalize` and `stableHash` are used to handle these arguments:
const { data, error } = useSWR('api/user/1', fetcher, { revalidateOnFocus: false });
if (error) return <div>Error</div>;
if (!data) return <div>Loading...</div>;
return <div>Hello, {data.name}!</div>;
}
Here, normalize parses the arguments, stableHash generates the cache key, and mergeConfigs combines any config from defaults and user inputs.