setup.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /**
  2. * Test setup file for Vitest.
  3. * Configures testing environment, mocks, and MSW server.
  4. */
  5. import '@testing-library/jest-dom';
  6. import { afterAll, afterEach, beforeAll, vi } from 'vitest';
  7. import { cleanup } from '@testing-library/react';
  8. import { server } from './mocks/server';
  9. // Initialize i18n for tests (suppresses react-i18next warnings)
  10. import '../i18n';
  11. // Setup MSW server
  12. beforeAll(() =>
  13. server.listen({
  14. // Bypass unhandled requests silently (don't warn, just let them through)
  15. // Handlers use wildcard (*) prefix to match any origin
  16. onUnhandledRequest: 'bypass',
  17. })
  18. );
  19. afterEach(() => {
  20. cleanup();
  21. server.resetHandlers();
  22. });
  23. afterAll(() => server.close());
  24. // Mock window.matchMedia for responsive components
  25. // Uses a plain function (not vi.fn) so vi.restoreAllMocks() in tests can't wipe it
  26. Object.defineProperty(window, 'matchMedia', {
  27. writable: true,
  28. value: (query: string) => ({
  29. matches: false,
  30. media: query,
  31. onchange: null,
  32. addListener: () => {},
  33. removeListener: () => {},
  34. addEventListener: () => {},
  35. removeEventListener: () => {},
  36. dispatchEvent: () => true,
  37. }),
  38. });
  39. // Mock ResizeObserver
  40. class ResizeObserverMock {
  41. observe = vi.fn();
  42. unobserve = vi.fn();
  43. disconnect = vi.fn();
  44. }
  45. vi.stubGlobal('ResizeObserver', ResizeObserverMock);
  46. // Mock IntersectionObserver
  47. class IntersectionObserverMock {
  48. observe = vi.fn();
  49. unobserve = vi.fn();
  50. disconnect = vi.fn();
  51. root = null;
  52. rootMargin = '';
  53. thresholds = [];
  54. }
  55. vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);
  56. // Mock WebSocket
  57. class MockWebSocket {
  58. static readonly CONNECTING = 0;
  59. static readonly OPEN = 1;
  60. static readonly CLOSING = 2;
  61. static readonly CLOSED = 3;
  62. readyState = MockWebSocket.OPEN;
  63. onopen: ((event: Event) => void) | null = null;
  64. onclose: ((event: CloseEvent) => void) | null = null;
  65. onmessage: ((event: MessageEvent) => void) | null = null;
  66. onerror: ((event: Event) => void) | null = null;
  67. url: string;
  68. constructor(url: string) {
  69. this.url = url;
  70. setTimeout(() => this.onopen?.(new Event('open')), 0);
  71. }
  72. send = vi.fn();
  73. close = vi.fn();
  74. }
  75. vi.stubGlobal('WebSocket', MockWebSocket);
  76. // Mock scrollTo
  77. window.scrollTo = vi.fn();
  78. // Mock localStorage
  79. const localStorageMock = {
  80. getItem: vi.fn(),
  81. setItem: vi.fn(),
  82. removeItem: vi.fn(),
  83. clear: vi.fn(),
  84. };
  85. Object.defineProperty(window, 'localStorage', { value: localStorageMock });
  86. // Suppress console output during tests (reduces noise)
  87. // Remove these lines if you need to debug test output
  88. vi.spyOn(console, 'log').mockImplementation(() => {});
  89. vi.spyOn(console, 'warn').mockImplementation(() => {});
  90. vi.spyOn(console, 'error').mockImplementation(() => {});