- queryKeys: add mutation-safety test for batch(), key hierarchy tests (list/batch/detail keys rooted in their parent base keys), and unique-key test for different detail IDs - BaseQueryStore: add initial-state test (data undefined, isError false before any fetch resolves) - BatchFontStore: add FontResponseError type assertion on malformed response, null error assertion on success, and setIds([]) disables query and returns empty fonts without triggering a fetch
108 lines
4.3 KiB
TypeScript
108 lines
4.3 KiB
TypeScript
import { queryClient } from '$shared/api/queryClient';
|
|
import { fontKeys } from '$shared/api/queryKeys';
|
|
import {
|
|
beforeEach,
|
|
describe,
|
|
expect,
|
|
it,
|
|
vi,
|
|
} from 'vitest';
|
|
import * as api from '../../api/proxy/proxyFonts';
|
|
import {
|
|
FontNetworkError,
|
|
FontResponseError,
|
|
} from '../../lib/errors/errors';
|
|
import { BatchFontStore } from './batchFontStore.svelte';
|
|
|
|
describe('BatchFontStore', () => {
|
|
beforeEach(() => {
|
|
queryClient.clear();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('Fetch Behavior', () => {
|
|
it('should skip fetch when initialized with empty IDs', async () => {
|
|
const spy = vi.spyOn(api, 'fetchFontsByIds');
|
|
const store = new BatchFontStore([]);
|
|
expect(spy).not.toHaveBeenCalled();
|
|
expect(store.fonts).toEqual([]);
|
|
});
|
|
|
|
it('should fetch and seed cache for valid IDs', async () => {
|
|
const fonts = [{ id: 'a', name: 'A' }] as any[];
|
|
vi.spyOn(api, 'fetchFontsByIds').mockResolvedValue(fonts);
|
|
const store = new BatchFontStore(['a']);
|
|
await vi.waitFor(() => expect(store.fonts).toEqual(fonts), { timeout: 1000 });
|
|
expect(queryClient.getQueryData(fontKeys.detail('a'))).toEqual(fonts[0]);
|
|
});
|
|
});
|
|
|
|
describe('Loading States', () => {
|
|
it('should transition through loading state', async () => {
|
|
vi.spyOn(api, 'fetchFontsByIds').mockImplementation(() =>
|
|
new Promise(r => setTimeout(() => r([{ id: 'a' }] as any), 50))
|
|
);
|
|
const store = new BatchFontStore(['a']);
|
|
expect(store.isLoading).toBe(true);
|
|
await vi.waitFor(() => expect(store.isLoading).toBe(false), { timeout: 1000 });
|
|
});
|
|
});
|
|
|
|
describe('Error Handling', () => {
|
|
it('should wrap network failures in FontNetworkError', async () => {
|
|
vi.spyOn(api, 'fetchFontsByIds').mockRejectedValue(new Error('Network fail'));
|
|
const store = new BatchFontStore(['a']);
|
|
await vi.waitFor(() => expect(store.isError).toBe(true), { timeout: 1000 });
|
|
expect(store.error).toBeInstanceOf(FontNetworkError);
|
|
});
|
|
|
|
it('should handle malformed API responses with FontResponseError', async () => {
|
|
// Mocking a malformed response that the store should validate
|
|
vi.spyOn(api, 'fetchFontsByIds').mockResolvedValue(null as any);
|
|
const store = new BatchFontStore(['a']);
|
|
await vi.waitFor(() => expect(store.isError).toBe(true), { timeout: 1000 });
|
|
expect(store.error).toBeInstanceOf(FontResponseError);
|
|
});
|
|
|
|
it('should have null error in success state', async () => {
|
|
const fonts = [{ id: 'a' }] as any[];
|
|
vi.spyOn(api, 'fetchFontsByIds').mockResolvedValue(fonts);
|
|
const store = new BatchFontStore(['a']);
|
|
await vi.waitFor(() => expect(store.fonts).toEqual(fonts), { timeout: 1000 });
|
|
expect(store.error).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('Disable Behavior', () => {
|
|
it('should return empty fonts and not fetch when setIds is called with empty array', async () => {
|
|
const fonts1 = [{ id: 'a' }] as any[];
|
|
const spy = vi.spyOn(api, 'fetchFontsByIds').mockResolvedValueOnce(fonts1);
|
|
|
|
const store = new BatchFontStore(['a']);
|
|
await vi.waitFor(() => expect(store.fonts).toEqual(fonts1), { timeout: 1000 });
|
|
|
|
spy.mockClear();
|
|
store.setIds([]);
|
|
|
|
await vi.waitFor(() => expect(store.fonts).toEqual([]), { timeout: 1000 });
|
|
expect(spy).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('Reactivity', () => {
|
|
it('should refetch when setIds is called', async () => {
|
|
const fonts1 = [{ id: 'a' }] as any[];
|
|
const fonts2 = [{ id: 'b' }] as any[];
|
|
vi.spyOn(api, 'fetchFontsByIds')
|
|
.mockResolvedValueOnce(fonts1)
|
|
.mockResolvedValueOnce(fonts2);
|
|
|
|
const store = new BatchFontStore(['a']);
|
|
await vi.waitFor(() => expect(store.fonts).toEqual(fonts1), { timeout: 1000 });
|
|
|
|
store.setIds(['b']);
|
|
await vi.waitFor(() => expect(store.fonts).toEqual(fonts2), { timeout: 1000 });
|
|
});
|
|
});
|
|
});
|