import { renderHook, act } from '@testing-library/react-native' import { useTemplateLike } from './use-template-like' import { root } from '@repo/core' import { TemplateSocialController } from '@repo/sdk' import { handleError } from './use-error' jest.mock('@repo/core', () => ({ root: { get: jest.fn(), }, })) jest.mock('./use-error', () => ({ handleError: jest.fn(async (cb) => { try { const data = await cb() return { data, error: null } } catch (e) { return { data: null, error: e } } }), })) describe('useTemplateLike', () => { beforeEach(() => { jest.clearAllMocks() }) afterEach(() => { jest.restoreAllMocks() }) describe('initial state', () => { it('should return initial state with templateId', () => { const { result } = renderHook(() => useTemplateLike('template-1')) expect(result.current.liked).toBe(false) expect(result.current.loading).toBe(false) expect(result.current.error).toBeNull() }) it('should return initial state without templateId', () => { const { result } = renderHook(() => useTemplateLike()) expect(result.current.liked).toBe(false) expect(result.current.loading).toBe(false) expect(result.current.error).toBeNull() }) }) describe('like function', () => { it('should like template successfully', async () => { const mockController = { like: jest.fn().mockResolvedValue(undefined), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) let response await act(async () => { response = await result.current.like() }) expect(mockController.like).toHaveBeenCalledWith({ templateId: 'template-1' }) expect(result.current.liked).toBe(true) expect(result.current.error).toBeNull() }) it('should handle API errors when liking', async () => { const mockError = { status: 500, statusText: 'Internal Server Error', message: 'Failed to like template', } const mockController = { like: jest.fn().mockRejectedValue(mockError), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) let response await act(async () => { response = await result.current.like() }) expect(result.current.error).toEqual(mockError) expect(response).toEqual({ error: mockError }) }) it('should do nothing if templateId is not provided', async () => { const { result } = renderHook(() => useTemplateLike()) let response await act(async () => { response = await result.current.like() }) expect(response).toEqual({ error: { message: 'TemplateId is required' } }) }) }) describe('unlike function', () => { it('should unlike template successfully', async () => { const mockController = { unlike: jest.fn().mockResolvedValue(undefined), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) // 先设置为已点赞 act(() => { result.current.like = jest.fn().mockResolvedValue({}) }) let response await act(async () => { response = await result.current.unlike() }) expect(mockController.unlike).toHaveBeenCalledWith({ templateId: 'template-1' }) expect(result.current.liked).toBe(false) expect(result.current.error).toBeNull() }) it('should handle API errors when unliking', async () => { const mockError = { status: 500, statusText: 'Internal Server Error', message: 'Failed to unlike template', } const mockController = { unlike: jest.fn().mockRejectedValue(mockError), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) let response await act(async () => { response = await result.current.unlike() }) expect(result.current.error).toEqual(mockError) expect(response).toEqual({ error: mockError }) }) it('should do nothing if templateId is not provided', async () => { const { result } = renderHook(() => useTemplateLike()) let response await act(async () => { response = await result.current.unlike() }) expect(response).toEqual({ error: { message: 'TemplateId is required' } }) }) }) describe('checkLiked function', () => { it('should check liked status successfully', async () => { const mockData = { liked: true } const mockController = { checkLiked: jest.fn().mockResolvedValue(mockData), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) let response await act(async () => { response = await result.current.checkLiked() }) expect(mockController.checkLiked).toHaveBeenCalledWith({ templateId: 'template-1' }) expect(result.current.liked).toBe(true) expect(result.current.error).toBeNull() }) it('should handle not liked status', async () => { const mockData = { liked: false } const mockController = { checkLiked: jest.fn().mockResolvedValue(mockData), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) await act(async () => { await result.current.checkLiked() }) expect(result.current.liked).toBe(false) }) it('should handle API errors when checking liked status', async () => { const mockError = { status: 500, statusText: 'Internal Server Error', message: 'Failed to check liked status', } const mockController = { checkLiked: jest.fn().mockRejectedValue(mockError), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) let response await act(async () => { response = await result.current.checkLiked() }) expect(result.current.error).toEqual(mockError) expect(response).toEqual({ error: mockError }) }) it('should do nothing if templateId is not provided', async () => { const { result } = renderHook(() => useTemplateLike()) let response await act(async () => { response = await result.current.checkLiked() }) expect(response).toEqual({ error: { message: 'TemplateId is required' } }) }) }) describe('loading state', () => { it('should set loading to true during like operation', async () => { let resolveLike: (value: any) => void const likePromise = new Promise((resolve) => { resolveLike = resolve }) const mockController = { like: jest.fn().mockReturnValue(likePromise), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) act(() => { result.current.like() }) expect(result.current.loading).toBe(true) await act(async () => { resolveLike!(undefined) await likePromise }) expect(result.current.loading).toBe(false) }) it('should set loading to true during unlike operation', async () => { let resolveUnlike: (value: any) => void const unlikePromise = new Promise((resolve) => { resolveUnlike = resolve }) const mockController = { unlike: jest.fn().mockReturnValue(unlikePromise), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) act(() => { result.current.unlike() }) expect(result.current.loading).toBe(true) await act(async () => { resolveUnlike!(undefined) await unlikePromise }) expect(result.current.loading).toBe(false) }) it('should set loading to true during checkLiked operation', async () => { let resolveCheck: (value: any) => void const checkPromise = new Promise((resolve) => { resolveCheck = resolve }) const mockController = { checkLiked: jest.fn().mockReturnValue(checkPromise), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) act(() => { result.current.checkLiked() }) expect(result.current.loading).toBe(true) await act(async () => { resolveCheck!({ liked: false }) await checkPromise }) expect(result.current.loading).toBe(false) }) it('should set loading to false after error', async () => { const mockError = { status: 500, message: 'Error' } const mockController = { like: jest.fn().mockRejectedValue(mockError), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) await act(async () => { await result.current.like() }) expect(result.current.loading).toBe(false) }) }) describe('error handling', () => { it('should clear error on successful like', async () => { const mockError = { status: 500, message: 'Error' } const mockController = { like: jest.fn() .mockRejectedValueOnce(mockError) .mockResolvedValueOnce(undefined), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) await act(async () => { await result.current.like() }) expect(result.current.error).toEqual(mockError) await act(async () => { await result.current.like() }) expect(result.current.error).toBeNull() }) it('should clear error on successful unlike', async () => { const mockError = { status: 500, message: 'Error' } const mockController = { unlike: jest.fn() .mockRejectedValueOnce(mockError) .mockResolvedValueOnce(undefined), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) await act(async () => { await result.current.unlike() }) expect(result.current.error).toEqual(mockError) await act(async () => { await result.current.unlike() }) expect(result.current.error).toBeNull() }) it('should clear error on successful checkLiked', async () => { const mockError = { status: 500, message: 'Error' } const mockController = { checkLiked: jest.fn() .mockRejectedValueOnce(mockError) .mockResolvedValueOnce({ liked: false }), } ;(root.get as jest.Mock).mockReturnValue(mockController) const { result } = renderHook(() => useTemplateLike('template-1')) await act(async () => { await result.current.checkLiked() }) expect(result.current.error).toEqual(mockError) await act(async () => { await result.current.checkLiked() }) expect(result.current.error).toBeNull() }) }) })