import React from 'react'; import { QueryClientProvider } from '@tanstack/react-query'; import { renderHook, waitFor } from '@testing-library/react'; import { mockContentLibrary } from '@src/library-authoring/data/api.mocks'; import { initializeMocks } from '@src/testUtils'; import { libraryAuthoringQueryKeys } from '../../data/apiHooks'; import { useCreateLibraryRestore, useCreateLibraryV2, useGetLibraryRestoreStatus, } from './apiHooks'; import { LibraryRestoreStatus } from './restoreConstants'; mockContentLibrary.applyMock(); const { axiosMock, queryClient } = initializeMocks(); const wrapper = ({ children }: { children: React.ReactNode }) => ( {children} ); describe('create library apiHooks', () => { beforeEach(() => { queryClient.clear(); axiosMock.reset(); }); describe('useCreateLibraryV2', () => { it('should create library and invalidate queries', async () => { const libraryData = { title: 'Test Library', org: 'test-org', slug: 'test-library', learning_package: 1, }; const expectedResult = { id: 'lib:test-org:test-library', title: 'Test Library', org: 'test-org', slug: 'test-library', }; // Mock the API call axiosMock.onPost('http://localhost:18010/api/libraries/v2/').reply(200, expectedResult); // Spy on query invalidation const invalidateQueriesSpy = jest.spyOn(queryClient, 'invalidateQueries'); const { result } = renderHook(() => useCreateLibraryV2(), { wrapper }); await result.current.mutateAsync(libraryData); expect(axiosMock.history.post[0].url).toEqual('http://localhost:18010/api/libraries/v2/'); expect(JSON.parse(axiosMock.history.post[0].data)).toEqual({ description: '', ...libraryData, }); // Check that queries are invalidated on success expect(invalidateQueriesSpy).toHaveBeenCalledWith({ queryKey: libraryAuthoringQueryKeys.contentLibraryList(), }); expect(invalidateQueriesSpy).toHaveBeenCalledWith({ queryKey: ['content_search'], }); }); }); describe('useCreateLibraryRestore', () => { it('should restore library from file', async () => { const file = new File(['test content'], 'test.tar.gz', { type: 'application/gzip' }); const expectedResult = { taskId: 'test-task-id' }; axiosMock.onPost('http://localhost:18010/api/libraries/v2/restore/').reply(200, expectedResult); const { result } = renderHook(() => useCreateLibraryRestore(), { wrapper }); const response = await result.current.mutateAsync(file); expect(axiosMock.history.post[0].url).toEqual('http://localhost:18010/api/libraries/v2/restore/'); expect(axiosMock.history.post[0].data).toBeInstanceOf(FormData); expect(response).toEqual(expectedResult); }); it('should handle restore error', async () => { const file = new File(['test content'], 'test.tar.gz', { type: 'application/gzip' }); axiosMock.onPost('http://localhost:18010/api/libraries/v2/restore/').reply(400, 'Bad Request'); const { result } = renderHook(() => useCreateLibraryRestore(), { wrapper }); await expect(result.current.mutateAsync(file)).rejects.toThrow(); }); }); describe('useGetLibraryRestoreStatus', () => { it('should get restore status when taskId is provided', async () => { const taskId = 'test-task-id'; const expectedResult = { state: LibraryRestoreStatus.Succeeded, result: { learningPackageId: 123, title: 'Test Library', org: 'test-org', slug: 'test-library', key: 'lib:test-org:test-library', archiveKey: 'archive-key', containers: 1, components: 5, collections: 2, sections: 1, subsections: 1, units: 1, createdOnServer: '2024-01-01T00:00:00Z', createdAt: '2024-01-01T00:00:00Z', createdBy: { username: 'testuser', email: 'test@example.com', }, }, error: null, errorLog: null, }; axiosMock.onGet(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`).reply(200, expectedResult); const { result } = renderHook(() => useGetLibraryRestoreStatus(taskId), { wrapper }); await waitFor(() => { expect(result.current.isLoading).toBeFalsy(); }); expect(result.current.data).toEqual(expectedResult); expect(axiosMock.history.get[0].url).toEqual(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`); }); it('should not make request when taskId is empty', async () => { const { result } = renderHook(() => useGetLibraryRestoreStatus(''), { wrapper }); await waitFor(() => { expect(result.current.isLoading).toBeFalsy(); }); expect(result.current.data).toBeUndefined(); expect(axiosMock.history.get).toHaveLength(0); }); it('should handle pending status with refetch interval', async () => { const taskId = 'pending-task-id'; const pendingResult = { state: LibraryRestoreStatus.Pending, result: null, error: null, error_log: null, }; const expectedResult = { state: LibraryRestoreStatus.Pending, result: null, error: null, errorLog: null, }; axiosMock.onGet(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`).reply(200, pendingResult); const { result } = renderHook(() => useGetLibraryRestoreStatus(taskId), { wrapper }); await waitFor(() => { expect(result.current.isLoading).toBeFalsy(); }); expect(result.current.data).toEqual(expectedResult); expect(axiosMock.history.get[0].url).toEqual(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`); }); it('should handle in-progress status with refetch interval', async () => { const taskId = 'in-progress-task-id'; const inProgressResult = { state: LibraryRestoreStatus.InProgress, result: null, error: null, error_log: null, }; const expectedResult = { state: LibraryRestoreStatus.InProgress, result: null, error: null, errorLog: null, }; axiosMock.onGet(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`).reply(200, inProgressResult); const { result } = renderHook(() => useGetLibraryRestoreStatus(taskId), { wrapper }); await waitFor(() => { expect(result.current.isLoading).toBeFalsy(); }); expect(result.current.data).toEqual(expectedResult); expect(axiosMock.history.get[0].url).toEqual(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`); }); it('should handle failed status', async () => { const taskId = 'failed-task-id'; const failedResult = { state: LibraryRestoreStatus.Failed, result: null, error: 'Restore failed', error_log: 'Error details here', }; const expectedResult = { state: LibraryRestoreStatus.Failed, result: null, error: 'Restore failed', errorLog: 'Error details here', }; axiosMock.onGet(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`).reply(200, failedResult); const { result } = renderHook(() => useGetLibraryRestoreStatus(taskId), { wrapper }); await waitFor(() => { expect(result.current.isLoading).toBeFalsy(); }); expect(result.current.data).toEqual(expectedResult); expect(axiosMock.history.get[0].url).toEqual(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`); }); it('should handle API error', async () => { const taskId = 'error-task-id'; axiosMock.onGet(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`).reply(404, 'Not Found'); const { result } = renderHook(() => useGetLibraryRestoreStatus(taskId), { wrapper }); await waitFor(() => { expect(result.current.isError).toBeTruthy(); }); expect(result.current.data).toBeUndefined(); expect(axiosMock.history.get[0].url).toEqual(`http://localhost:18010/api/libraries/v2/restore/?task_id=${taskId}`); }); }); });