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  }