// Vitest setup file import '@testing-library/jest-dom/vitest'; import './prisma/singleton'; import { afterEach, vi } from 'vitest'; import { cleanup } from '@testing-library/react'; import messages from '@/messages/en.json'; import type { PropsWithChildren } from 'react'; class MockPointerEvent extends Event { button: number; ctrlKey: boolean; pointerType: string; constructor(type: string, props: PointerEventInit) { super(type, props); this.button = props.button || 0; this.ctrlKey = props.ctrlKey || false; this.pointerType = props.pointerType || 'mouse'; } } function resolveMessage(namespace: string, key: string) { const root = (messages as Record)[namespace] as | Record | undefined; if (!root) { return undefined; } return key .split('.') .reduce((current, part) => { if (!current || typeof current !== 'object') { return undefined; } return (current as Record)[part]; }, root); } function formatMessage( template: string, values?: Record, ) { const scopedValues = values ?? {}; const withPlurals = template.replace( /\{(\w+),\s*plural,\s*one\s*\{([^{}]*)\}\s*other\s*\{([^{}]*)\}\}/g, (_, name: string, one: string, other: string) => { const rawValue = scopedValues[name]; const numericValue = typeof rawValue === 'number' ? rawValue : Number(rawValue); const branch = numericValue === 1 ? one : other; return branch.replace(/#/g, String(rawValue ?? '')); }, ); return withPlurals.replace(/\{(\w+)\}/g, (_, name: string) => { const value = scopedValues[name]; return value === undefined ? `{${name}}` : String(value); }); } vi.mock('next-intl', () => ({ NextIntlClientProvider: ({ children }: PropsWithChildren) => children, useLocale: () => 'en', useTranslations: (namespace: string) => { return (key: string, values?: Record) => { const message = resolveMessage(namespace, key); if (typeof message !== 'string') { return key; } return formatMessage(message, values); }; }, })); // Mock browser globals for Radix UI if (!globalThis.PointerEvent) { globalThis.PointerEvent = MockPointerEvent as unknown as typeof PointerEvent; } window.scrollTo = vi.fn(); window.HTMLElement.prototype.scrollIntoView = vi.fn(); window.HTMLElement.prototype.hasPointerCapture = vi.fn(); window.HTMLElement.prototype.releasePointerCapture = vi.fn(); // Mock LocalStorage const localStorageMock = (() => { let store: Record = {}; return { getItem: (key: string) => store[key] || null, setItem: (key: string, value: string) => { store[key] = value.toString(); }, clear: () => { store = {}; }, removeItem: (key: string) => { delete store[key]; }, length: Object.keys(store).length, key: (index: number) => Object.keys(store)[index] || null, }; })(); Object.defineProperty(window, 'localStorage', { value: localStorageMock }); Object.defineProperty(window, 'sessionStorage', { value: localStorageMock }); // RTL auto-cleanup needs globals; unmount explicitly so Radix portals don't leak between tests. afterEach(cleanup);