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') }) }) })