This repository has been archived on 2026-09-04. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
swr/packages/core/__tests__/swr.test.ts
T
2026-09-05 04:33:55 +05:30

117 lines
4.0 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "bun:test";
import { createSWR } from "../src/swr";
import type { Key, FetcherOptions } from "../src/types";
describe("SWRCore", () => {
let swr: any;
let fetcher: any;
const key = "test-key";
beforeEach(() => {
fetcher = vi.fn((k: Key, options: FetcherOptions) => Promise.resolve(`data-${k}`));
swr = createSWR({ fetcher, dedupingInterval: 100 });
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
it("fetches data on subscription if not in cache", async () => {
const callback = vi.fn();
swr.subscribe(key, callback);
// Initial fetch is async
vi.runAllTimers();
expect(fetcher).toHaveBeenCalledWith(key, expect.objectContaining({ signal: expect.any(AbortSignal) }));
expect(callback).toHaveBeenCalledWith(`data-${key}`, undefined, false, false);
});
it("deduplicates concurrent fetches", async () => {
swr.revalidate(key);
swr.revalidate(key);
swr.revalidate(key);
expect(fetcher).toHaveBeenCalledTimes(1);
});
it("updates all subscribers on mutation", async () => {
const cb1 = vi.fn();
const cb2 = vi.fn();
swr.subscribe(key, cb1);
swr.subscribe(key, cb2);
await swr.mutate(key, "manual-data");
expect(cb1).toHaveBeenCalledWith("manual-data", undefined, false, false);
expect(cb2).toHaveBeenCalledWith("manual-data", undefined, false, false);
});
it("handles fetcher errors", async () => {
const error = new Error("fetch failed");
fetcher.mockRejectedValue(error);
const callback = vi.fn();
swr.subscribe(key, callback);
vi.runAllTimers();
expect(callback).toHaveBeenCalledWith(undefined, error, false, false);
});
it("respects revalidateOnMount: false", async () => {
swr.updateConfig({ revalidateOnMount: false });
// Put something in cache
await swr.mutate(key, "cached");
fetcher.mockClear();
const callback = vi.fn();
swr.subscribe(key, callback);
vi.runAllTimers();
// Should not have fetched again despite subscription
expect(fetcher).not.toHaveBeenCalled();
});
it("refreshInterval periodically revalidates with per-key fetcher", async () => {
const intervalFetcher = vi.fn((k: Key, options: FetcherOptions) => Promise.resolve(`data-${k}`));
swr.updateConfig({ refreshInterval: 1000 });
const callback = vi.fn();
swr.subscribe(key, callback, intervalFetcher);
// Initial fetch (only run pending timers, not the interval)
vi.runOnlyPendingTimers();
expect(intervalFetcher).toHaveBeenCalledTimes(1);
expect(callback).toHaveBeenCalledWith(`data-${key}`, undefined, false, false);
// After interval passes, should revalidate again
vi.advanceTimersByTime(1000);
expect(intervalFetcher).toHaveBeenCalledTimes(2);
// After another interval, should revalidate again
vi.advanceTimersByTime(1000);
expect(intervalFetcher).toHaveBeenCalledTimes(3);
});
it("revalidate uses stored fetcher when called without fetcher option", async () => {
// Create SWR without global fetcher
const noGlobalFetcherSwr = createSWR({ dedupingInterval: 100 });
const perKeyFetcher = vi.fn((k: Key, options: FetcherOptions) => Promise.resolve(`data-${k}`));
const callback = vi.fn();
noGlobalFetcherSwr.subscribe(key, callback, perKeyFetcher);
// Initial fetch
vi.runOnlyPendingTimers();
expect(perKeyFetcher).toHaveBeenCalledTimes(1);
// Revalidate without passing fetcher - should use stored fetcher
await noGlobalFetcherSwr.revalidate(key);
expect(perKeyFetcher).toHaveBeenCalledTimes(2);
});
});