import { act, renderHook, waitFor } from '@testing-library/react-native' import { AccessibilityInfo, EmitterSubscription } from 'react-native' import * as Reanimated from 'react-native-reanimated' import { useReduceMotion } from '../use_reduce_motion' type ReduceMotionListener = (enabled: boolean) => void describe('useReduceMotion', () => { let listener: ReduceMotionListener | undefined const remove = jest.fn() beforeEach(() => { listener = undefined remove.mockClear() jest.spyOn(Reanimated, 'useReducedMotion').mockReturnValue(false) jest.spyOn(AccessibilityInfo, 'isReduceMotionEnabled').mockResolvedValue(true) const addEventListener: typeof AccessibilityInfo.addEventListener = (_event, handler) => { listener = handler as ReduceMotionListener return { remove } as unknown as EmitterSubscription } jest.spyOn(AccessibilityInfo, 'addEventListener').mockImplementation(addEventListener) }) afterEach(() => jest.restoreAllMocks()) it('seeds synchronously from the launch-time setting', async () => { jest.spyOn(Reanimated, 'useReducedMotion').mockReturnValue(true) jest.mocked(AccessibilityInfo.isReduceMotionEnabled).mockResolvedValue(false) const { result } = renderHook(() => useReduceMotion()) expect(result.current).toBe(true) await waitFor(() => expect(result.current).toBe(false)) }) it('updates to the live setting once it resolves', async () => { const { result } = renderHook(() => useReduceMotion()) expect(result.current).toBe(false) await waitFor(() => expect(result.current).toBe(true)) }) it('follows reduceMotionChanged while mounted', async () => { const { result } = renderHook(() => useReduceMotion()) await waitFor(() => expect(result.current).toBe(true)) act(() => listener?.(false)) expect(result.current).toBe(false) act(() => listener?.(true)) expect(result.current).toBe(true) }) it('removes the listener on unmount', () => { const { unmount } = renderHook(() => useReduceMotion()) expect(remove).not.toHaveBeenCalled() unmount() expect(remove).toHaveBeenCalledTimes(1) }) })