import React from 'react' import { act, render } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import BackgroundPattern from './BackgroundPattern' import DotCloudIcon from './DotCloudIcon' const context = { arc: vi.fn(), beginPath: vi.fn(), clearRect: vi.fn(), closePath: vi.fn(), drawImage: vi.fn(), ellipse: vi.fn(), fill: vi.fn(), getImageData: vi.fn(() => ({ data: new Uint8ClampedArray(140 * 140 * 4) })), lineTo: vi.fn(), moveTo: vi.fn(), quadraticCurveTo: vi.fn(), scale: vi.fn(), setTransform: vi.fn(), } function setReducedMotion(matches) { vi.stubGlobal('matchMedia', vi.fn(() => ({ matches, addEventListener: vi.fn(), removeEventListener: vi.fn(), }))) } describe('canvas animation lifecycle', () => { beforeEach(() => { vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue(context) Object.defineProperty(document, 'hidden', { configurable: true, value: false }) vi.stubGlobal('requestAnimationFrame', vi.fn(() => 17)) vi.stubGlobal('cancelAnimationFrame', vi.fn()) }) afterEach(() => { vi.restoreAllMocks() vi.unstubAllGlobals() }) it('does not schedule background animation with reduced motion', () => { setReducedMotion(true) render() expect(requestAnimationFrame).not.toHaveBeenCalled() }) it('cancels a scheduled background frame on unmount', () => { setReducedMotion(false) const { unmount } = render() expect(requestAnimationFrame).toHaveBeenCalled() unmount() expect(cancelAnimationFrame).toHaveBeenCalledWith(17) }) it('does not schedule dot animation with reduced motion', async () => { setReducedMotion(true) render() await act(async () => Promise.resolve()) expect(requestAnimationFrame).not.toHaveBeenCalled() }) })