expo-popcore-app/hooks/use-download-media.test.ts

255 lines
7.9 KiB
TypeScript

import { renderHook, act } from '@testing-library/react-native'
import { useDownloadMedia } from './use-download-media'
import * as MediaLibrary from 'expo-media-library'
jest.mock('expo-media-library', () => ({
requestPermissionsAsync: jest.fn(),
saveToLibraryAsync: jest.fn(),
}))
describe('useDownloadMedia', () => {
beforeEach(() => {
jest.clearAllMocks()
})
afterEach(() => {
jest.restoreAllMocks()
})
describe('initial state', () => {
it('should return initial state', () => {
const { result } = renderHook(() => useDownloadMedia())
expect(result.current.loading).toBe(false)
expect(result.current.error).toBeNull()
expect(result.current.progress).toBe(0)
expect(typeof result.current.download).toBe('function')
})
})
describe('permission handling', () => {
it('should return error when permission is denied', async () => {
;(MediaLibrary.requestPermissionsAsync as jest.Mock).mockResolvedValue({
status: 'denied',
})
const { result } = renderHook(() => useDownloadMedia())
let response
await act(async () => {
response = await result.current.download('https://example.com/image.jpg', 'image')
})
expect(response).toEqual({ success: false, error: 'Permission denied' })
expect(result.current.error).toBe('Permission denied')
expect(result.current.loading).toBe(false)
})
it('should proceed when permission is granted', async () => {
;(MediaLibrary.requestPermissionsAsync as jest.Mock).mockResolvedValue({
status: 'granted',
})
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockResolvedValue(undefined)
const { result } = renderHook(() => useDownloadMedia())
let response
await act(async () => {
response = await result.current.download('https://example.com/image.jpg', 'image')
})
expect(response).toEqual({ success: true })
expect(MediaLibrary.requestPermissionsAsync).toHaveBeenCalled()
})
})
describe('download functionality', () => {
beforeEach(() => {
;(MediaLibrary.requestPermissionsAsync as jest.Mock).mockResolvedValue({
status: 'granted',
})
})
it('should download image successfully', async () => {
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockResolvedValue(undefined)
const { result } = renderHook(() => useDownloadMedia())
let response
await act(async () => {
response = await result.current.download('https://example.com/image.jpg', 'image')
})
expect(response).toEqual({ success: true })
expect(MediaLibrary.saveToLibraryAsync).toHaveBeenCalledWith('https://example.com/image.jpg')
})
it('should download video successfully', async () => {
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockResolvedValue(undefined)
const { result } = renderHook(() => useDownloadMedia())
let response
await act(async () => {
response = await result.current.download('https://example.com/video.mp4', 'video')
})
expect(response).toEqual({ success: true })
expect(MediaLibrary.saveToLibraryAsync).toHaveBeenCalledWith('https://example.com/video.mp4')
})
it('should handle download failure', async () => {
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockRejectedValue(new Error('Network error'))
const { result } = renderHook(() => useDownloadMedia())
let response
await act(async () => {
response = await result.current.download('https://example.com/image.jpg', 'image')
})
expect(response).toEqual({ success: false, error: 'Network error' })
expect(result.current.error).toBe('Network error')
})
it('should handle save to library failure', async () => {
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockRejectedValue(new Error('Save failed'))
const { result } = renderHook(() => useDownloadMedia())
let response
await act(async () => {
response = await result.current.download('https://example.com/image.jpg', 'image')
})
expect(response).toEqual({ success: false, error: 'Save failed' })
expect(result.current.error).toBe('Save failed')
})
})
describe('loading state', () => {
beforeEach(() => {
;(MediaLibrary.requestPermissionsAsync as jest.Mock).mockResolvedValue({
status: 'granted',
})
})
it('should set loading to true during download', async () => {
let resolveSave: (value: any) => void
const savePromise = new Promise((resolve) => {
resolveSave = resolve
})
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockReturnValue(savePromise)
const { result } = renderHook(() => useDownloadMedia())
act(() => {
result.current.download('https://example.com/image.jpg', 'image')
})
expect(result.current.loading).toBe(true)
await act(async () => {
resolveSave!(undefined)
await savePromise
})
expect(result.current.loading).toBe(false)
})
it('should set loading to false after error', async () => {
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockRejectedValue(new Error('Error'))
const { result } = renderHook(() => useDownloadMedia())
await act(async () => {
await result.current.download('https://example.com/image.jpg', 'image')
})
expect(result.current.loading).toBe(false)
})
})
describe('progress tracking', () => {
beforeEach(() => {
;(MediaLibrary.requestPermissionsAsync as jest.Mock).mockResolvedValue({
status: 'granted',
})
})
it('should reset progress after completion', async () => {
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockResolvedValue(undefined)
const { result } = renderHook(() => useDownloadMedia())
await act(async () => {
await result.current.download('https://example.com/image.jpg', 'image')
})
// Progress should be reset after completion
expect(result.current.progress).toBe(0)
})
it('should reset progress on new download', async () => {
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockResolvedValue(undefined)
const { result } = renderHook(() => useDownloadMedia())
await act(async () => {
await result.current.download('https://example.com/image1.jpg', 'image')
})
expect(result.current.progress).toBe(0)
await act(async () => {
await result.current.download('https://example.com/image2.jpg', 'image')
})
expect(result.current.progress).toBe(0)
})
})
describe('error handling', () => {
it('should clear error on new download attempt', async () => {
;(MediaLibrary.requestPermissionsAsync as jest.Mock)
.mockResolvedValueOnce({ status: 'denied' })
.mockResolvedValueOnce({ status: 'granted' })
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockResolvedValue(undefined)
const { result } = renderHook(() => useDownloadMedia())
await act(async () => {
await result.current.download('https://example.com/image.jpg', 'image')
})
expect(result.current.error).toBe('Permission denied')
await act(async () => {
await result.current.download('https://example.com/image.jpg', 'image')
})
expect(result.current.error).toBeNull()
})
it('should handle unknown error types', async () => {
;(MediaLibrary.requestPermissionsAsync as jest.Mock).mockResolvedValue({
status: 'granted',
})
;(MediaLibrary.saveToLibraryAsync as jest.Mock).mockRejectedValue('Unknown error')
const { result } = renderHook(() => useDownloadMedia())
let response
await act(async () => {
response = await result.current.download('https://example.com/image.jpg', 'image')
})
expect(response).toEqual({ success: false, error: 'Download failed' })
expect(result.current.error).toBe('Download failed')
})
})
})