89 lines
2.5 KiB
TypeScript
89 lines
2.5 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
import { renderHook, act } from "@testing-library/react";
|
|
import { useConfigItem } from "../useConfigItem";
|
|
|
|
describe("useConfigItem", () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("loads data and sets loading state", async () => {
|
|
const fetchFn = vi.fn().mockResolvedValue("hello");
|
|
const saveFn = vi.fn().mockResolvedValue(undefined);
|
|
|
|
const { result } = renderHook(() => useConfigItem<string, string>({ fetchFn, saveFn }));
|
|
|
|
expect(result.current.loading).toBe(true);
|
|
await act(async () => {
|
|
await Promise.resolve();
|
|
});
|
|
|
|
expect(fetchFn).toHaveBeenCalled();
|
|
expect(result.current.data).toBe("hello");
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
it("sets error if fetch rejects", async () => {
|
|
const fetchFn = vi.fn().mockRejectedValue(new Error("nope"));
|
|
const saveFn = vi.fn().mockResolvedValue(undefined);
|
|
|
|
const { result } = renderHook(() => useConfigItem<string, string>({ fetchFn, saveFn }));
|
|
|
|
await act(async () => {
|
|
await Promise.resolve();
|
|
});
|
|
|
|
expect(result.current.error).toBe("nope");
|
|
expect(result.current.loading).toBe(false);
|
|
});
|
|
|
|
it("save updates data when mergeOnSave is provided", async () => {
|
|
const fetchFn = vi.fn().mockResolvedValue({ value: 1 });
|
|
const saveFn = vi.fn().mockResolvedValue(undefined);
|
|
|
|
const { result } = renderHook(() =>
|
|
useConfigItem<{ value: number }, { delta: number }>({
|
|
fetchFn,
|
|
saveFn,
|
|
mergeOnSave: (prev, update) =>
|
|
prev ? { ...prev, value: prev.value + update.delta } : prev,
|
|
})
|
|
);
|
|
|
|
await act(async () => {
|
|
await Promise.resolve();
|
|
});
|
|
|
|
expect(result.current.data).toEqual({ value: 1 });
|
|
|
|
await act(async () => {
|
|
await result.current.save({ delta: 2 });
|
|
});
|
|
|
|
expect(saveFn).toHaveBeenCalledWith({ delta: 2 });
|
|
expect(result.current.data).toEqual({ value: 3 });
|
|
});
|
|
|
|
it("saveError is set when save fails", async () => {
|
|
const fetchFn = vi.fn().mockResolvedValue("ok");
|
|
const saveFn = vi.fn().mockRejectedValue(new Error("save failed"));
|
|
|
|
const { result } = renderHook(() => useConfigItem<string, string>({ fetchFn, saveFn }));
|
|
|
|
await act(async () => {
|
|
await Promise.resolve();
|
|
});
|
|
|
|
await act(async () => {
|
|
await expect(result.current.save("test")).rejects.toThrow("save failed");
|
|
});
|
|
|
|
expect(result.current.saveError).toBe("save failed");
|
|
});
|
|
});
|