import '@testing-library/jest-dom'; import { vi, beforeEach, afterEach, beforeAll } from 'vitest'; import React from 'react'; import i18n from '@/i18n'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { render, renderHook } from '@testing-library/react'; // ── Global QueryClient for tests ────────────────────────────────────────── // Many tests use hooks from @tanstack/react-query without explicitly wrapping // in a QueryClientProvider. We monkey-patch render/renderHook to automatically // wrap with the provider. function getTestQueryClient() { return new QueryClient({ defaultOptions: { queries: { retry: false, staleTime: 0, gcTime: 0 }, mutations: { retry: false }, }, }); } const originalRender = render; const originalRenderHook = renderHook; // Override global render to auto-wrap with QueryClientProvider (globalThis as any).render = (ui: React.ReactElement, options?: any) => { const client = getTestQueryClient(); const wrapped = React.createElement(QueryClientProvider, { client }, ui); return originalRender(wrapped, options); }; // Override global renderHook to auto-wrap with QueryClientProvider (globalThis as any).renderHook = (hook: any, options?: any) => { const client = getTestQueryClient(); const wrapper = ({ children }: { children: React.ReactNode }) => React.createElement(QueryClientProvider, { client }, children); return originalRenderHook(hook, { wrapper, ...options }); }; // Mock matchMedia for jsdom Object.defineProperty(window, 'matchMedia', { writable: true, value: vi.fn().mockImplementation((query: string) => ({ matches: false, media: query, onchange: null, addListener: vi.fn(), removeListener: vi.fn(), addEventListener: vi.fn(), removeEventListener: vi.fn(), dispatchEvent: vi.fn(), })), }); // Mock IntersectionObserver class MockIntersectionObserver { observe = vi.fn(); unobserve = vi.fn(); disconnect = vi.fn(); takeRecords = vi.fn(); root = null; rootMargin = ''; thresholds = []; } Object.defineProperty(window, 'IntersectionObserver', { writable: true, configurable: true, value: MockIntersectionObserver, }); // Mock ResizeObserver class MockResizeObserver { observe = vi.fn(); unobserve = vi.fn(); disconnect = vi.fn(); } Object.defineProperty(window, 'ResizeObserver', { writable: true, configurable: true, value: MockResizeObserver, }); // Mock EventSource for jsdom class MockEventSource { constructor(url: string) { this.url = url; this.readyState = 0; } url: string; readyState: number; onopen: any = null; onmessage: any = null; onerror: any = null; addEventListener = vi.fn(); removeEventListener = vi.fn(); close = vi.fn(); } Object.defineProperty(window, 'EventSource', { writable: true, configurable: true, value: MockEventSource }); // Mock scrollTo window.scrollTo = vi.fn() as any; // Initialize i18n before all tests beforeAll(async () => { await i18n.changeLanguage('de'); }); // Clean up after each test afterEach(() => { vi.clearAllMocks(); localStorage.clear(); }); beforeEach(() => { localStorage.clear(); });