1
0

browser.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import { vi } from 'vitest'
  2. // Mock IntersectionObserver
  3. export class MockIntersectionObserver implements IntersectionObserver {
  4. callback: IntersectionObserverCallback
  5. elements: Set<Element> = new Set()
  6. // Required IntersectionObserver properties
  7. readonly root: Element | Document | null = null
  8. readonly rootMargin: string = '0px'
  9. readonly thresholds: ReadonlyArray<number> = [0]
  10. constructor(callback: IntersectionObserverCallback) {
  11. this.callback = callback
  12. }
  13. observe(element: Element) {
  14. this.elements.add(element)
  15. // Immediately trigger as visible for testing
  16. this.callback(
  17. [{ target: element, isIntersecting: true, intersectionRatio: 1 } as IntersectionObserverEntry],
  18. this
  19. )
  20. }
  21. unobserve(element: Element) {
  22. this.elements.delete(element)
  23. }
  24. disconnect() {
  25. this.elements.clear()
  26. }
  27. takeRecords(): IntersectionObserverEntry[] {
  28. return []
  29. }
  30. }
  31. // Mock matchMedia
  32. export function createMockMatchMedia(matches: boolean = false) {
  33. return vi.fn().mockImplementation((query: string) => ({
  34. matches,
  35. media: query,
  36. onchange: null,
  37. addListener: vi.fn(),
  38. removeListener: vi.fn(),
  39. addEventListener: vi.fn(),
  40. removeEventListener: vi.fn(),
  41. dispatchEvent: vi.fn(),
  42. }))
  43. }
  44. // Mock ResizeObserver
  45. export class MockResizeObserver {
  46. callback: ResizeObserverCallback
  47. constructor(callback: ResizeObserverCallback) {
  48. this.callback = callback
  49. }
  50. observe() {}
  51. unobserve() {}
  52. disconnect() {}
  53. }
  54. // Setup all browser mocks
  55. export function setupBrowserMocks() {
  56. vi.stubGlobal('IntersectionObserver', MockIntersectionObserver)
  57. vi.stubGlobal('ResizeObserver', MockResizeObserver)
  58. vi.stubGlobal('matchMedia', createMockMatchMedia())
  59. // Mock canvas context
  60. HTMLCanvasElement.prototype.getContext = vi.fn().mockReturnValue({
  61. fillRect: vi.fn(),
  62. clearRect: vi.fn(),
  63. beginPath: vi.fn(),
  64. moveTo: vi.fn(),
  65. lineTo: vi.fn(),
  66. stroke: vi.fn(),
  67. fill: vi.fn(),
  68. arc: vi.fn(),
  69. drawImage: vi.fn(),
  70. save: vi.fn(),
  71. restore: vi.fn(),
  72. scale: vi.fn(),
  73. translate: vi.fn(),
  74. rotate: vi.fn(),
  75. setTransform: vi.fn(),
  76. getImageData: vi.fn().mockReturnValue({ data: new Uint8ClampedArray(4) }),
  77. putImageData: vi.fn(),
  78. createLinearGradient: vi.fn().mockReturnValue({ addColorStop: vi.fn() }),
  79. createRadialGradient: vi.fn().mockReturnValue({ addColorStop: vi.fn() }),
  80. measureText: vi.fn().mockReturnValue({ width: 0 }),
  81. fillText: vi.fn(),
  82. strokeText: vi.fn(),
  83. })
  84. // Mock localStorage
  85. const localStorageMock = {
  86. store: {} as Record<string, string>,
  87. getItem: vi.fn((key: string) => localStorageMock.store[key] || null),
  88. setItem: vi.fn((key: string, value: string) => { localStorageMock.store[key] = value }),
  89. removeItem: vi.fn((key: string) => { delete localStorageMock.store[key] }),
  90. clear: vi.fn(() => { localStorageMock.store = {} }),
  91. get length() { return Object.keys(localStorageMock.store).length },
  92. key: vi.fn((i: number) => Object.keys(localStorageMock.store)[i] || null),
  93. }
  94. vi.stubGlobal('localStorage', localStorageMock)
  95. return { localStorage: localStorageMock }
  96. }
  97. export function cleanupBrowserMocks() {
  98. vi.unstubAllGlobals()
  99. }