setup.ts
1 /** 2 * Vitest setup file for web terminal client tests. 3 * Configures jsdom environment and jest-dom matchers. 4 */ 5 import '@testing-library/jest-dom/vitest'; 6 import { afterAll, afterEach, beforeAll, vi } from 'vitest'; 7 import { cleanup } from '@testing-library/react'; 8 import { server } from './mocks/server'; 9 10 // Start MSW server before all tests 11 beforeAll(() => { 12 server.listen({ onUnhandledRequest: 'warn' }); 13 }); 14 15 // Reset handlers after each test 16 afterEach(() => { 17 server.resetHandlers(); 18 cleanup(); 19 vi.clearAllTimers(); 20 vi.useRealTimers(); 21 }); 22 23 // Stop MSW server after all tests 24 afterAll(() => { 25 server.close(); 26 }); 27 28 // Suppress React 18 act() warnings from userEvent and async state updates. 29 // These are false positives caused by React 18's batching model interacting 30 // with Testing Library — tests pass correctly and behavior is verified. 31 const originalConsoleError = console.error; 32 console.error = (...args: unknown[]) => { 33 if (typeof args[0] === 'string' && args[0].includes('was not wrapped in act')) { 34 return; 35 } 36 originalConsoleError(...args); 37 }; 38 39 // Mock window.matchMedia 40 Object.defineProperty(window, 'matchMedia', { 41 writable: true, 42 value: vi.fn().mockImplementation((query: string) => ({ 43 matches: false, 44 media: query, 45 onchange: null, 46 addListener: vi.fn(), 47 removeListener: vi.fn(), 48 addEventListener: vi.fn(), 49 removeEventListener: vi.fn(), 50 dispatchEvent: vi.fn(), 51 })), 52 }); 53 54 // Mock ResizeObserver 55 global.ResizeObserver = vi.fn().mockImplementation(() => ({ 56 observe: vi.fn(), 57 unobserve: vi.fn(), 58 disconnect: vi.fn(), 59 })); 60 61 // Mock scrollIntoView 62 Element.prototype.scrollIntoView = vi.fn(); 63 64 // Mock URL.createObjectURL and URL.revokeObjectURL (not available in jsdom) 65 let objectUrlCounter = 0; 66 67 URL.createObjectURL = vi.fn(() => `blob:test-url-${++objectUrlCounter}`); 68 URL.revokeObjectURL = vi.fn(); 69 70 // Mock ClipboardItem (not available in jsdom) 71 if (typeof globalThis.ClipboardItem === 'undefined') { 72 globalThis.ClipboardItem = class ClipboardItem { 73 readonly types: string[]; 74 constructor(private items: Record<string, Blob>) { 75 this.types = Object.keys(items); 76 } 77 getType(type: string): Promise<Blob> { 78 const blob = this.items[type]; 79 return blob ? Promise.resolve(blob) : Promise.reject(new Error(`Type ${type} not found`)); 80 } 81 } as unknown as typeof globalThis.ClipboardItem; 82 }