File size: 2,130 Bytes
004f460 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { renderHook, act, waitFor } from '@testing-library/react'
import { useCamera } from './useCamera'
function fakeStream() {
const tracks = [
{ stop: vi.fn(), kind: 'video', getSettings: () => ({ deviceId: 'cam1' }) },
{ stop: vi.fn(), kind: 'video', getSettings: () => ({ deviceId: 'cam1' }) },
]
return {
_tracks: tracks,
getTracks: () => tracks,
getVideoTracks: () => tracks,
} as unknown as MediaStream & { _tracks: { stop: ReturnType<typeof vi.fn> }[] }
}
describe('useCamera — track lifecycle', () => {
let stream: ReturnType<typeof fakeStream>
beforeEach(() => {
stream = fakeStream()
Object.defineProperty(navigator, 'mediaDevices', {
configurable: true,
value: { getUserMedia: vi.fn().mockResolvedValue(stream), enumerateDevices: vi.fn().mockResolvedValue([]) },
})
})
afterEach(() => vi.restoreAllMocks())
it('start() acquires a stream and stop() stops ALL tracks', async () => {
const { result } = renderHook(() => useCamera())
await act(async () => { await result.current.start() })
await waitFor(() => expect(result.current.status).toBe('live'))
act(() => result.current.stop())
for (const tr of stream._tracks) expect(tr.stop).toHaveBeenCalled()
expect(result.current.status).toBe('idle')
})
it('maps NotAllowedError to denied', async () => {
const gum = navigator.mediaDevices.getUserMedia as ReturnType<typeof vi.fn>
gum.mockRejectedValueOnce(Object.assign(new Error('no'), { name: 'NotAllowedError' }))
const { result } = renderHook(() => useCamera())
await act(async () => { await result.current.start() })
await waitFor(() => expect(result.current.status).toBe('denied'))
})
it('reports nocamera when getUserMedia is unavailable', async () => {
Object.defineProperty(navigator, 'mediaDevices', { configurable: true, value: undefined })
const { result } = renderHook(() => useCamera())
await act(async () => { await result.current.start() })
expect(result.current.status).toBe('nocamera')
})
})
|