import { renderHook, act, waitFor } from '@testing-library/react-native' import { useChangePassword } from '@/hooks/use-change-password' import { authClient } from '@/lib/auth' // Mock authClient jest.mock('@/lib/auth', () => ({ authClient: { changePassword: jest.fn(), }, })) describe('useChangePassword', () => { beforeEach(() => { jest.clearAllMocks() }) afterEach(() => { jest.restoreAllMocks() }) it('should change password successfully', async () => { const mockChangePassword = authClient.changePassword as jest.MockedFunction mockChangePassword.mockResolvedValue({ error: null }) const { result } = renderHook(() => useChangePassword()) await act(async () => { await result.current.changePassword({ oldPassword: 'oldPass123', newPassword: 'newPass123', }) }) expect(mockChangePassword).toHaveBeenCalledWith({ oldPassword: 'oldPass123', newPassword: 'newPass123', revokeOtherSessions: true, }) expect(result.current.error).toBeNull() }) it('should validate old password is not empty', async () => { const { result } = renderHook(() => useChangePassword()) await act(async () => { await result.current.changePassword({ oldPassword: '', newPassword: 'newPass123', }) }) expect(result.current.error).toEqual({ message: '旧密码不能为空', }) expect(authClient.changePassword).not.toHaveBeenCalled() }) it('should validate new password and confirm password match', async () => { const { result } = renderHook(() => useChangePassword()) await act(async () => { await result.current.changePassword({ oldPassword: 'oldPass123', newPassword: 'newPass123', confirmPassword: 'differentPass123', }) }) expect(result.current.error).toEqual({ message: '新密码和确认密码不一致', }) expect(authClient.changePassword).not.toHaveBeenCalled() }) it('should validate new password length (minimum 6 characters)', async () => { const { result } = renderHook(() => useChangePassword()) await act(async () => { await result.current.changePassword({ oldPassword: 'oldPass123', newPassword: '12345', }) }) expect(result.current.error).toEqual({ message: '新密码长度至少为6位', }) expect(authClient.changePassword).not.toHaveBeenCalled() }) it('should validate new password is different from old password', async () => { const { result } = renderHook(() => useChangePassword()) await act(async () => { await result.current.changePassword({ oldPassword: 'samePass123', newPassword: 'samePass123', }) }) expect(result.current.error).toEqual({ message: '新密码不能与当前密码相同', }) expect(authClient.changePassword).not.toHaveBeenCalled() }) it('should handle API errors', async () => { const mockError = { status: 400, statusText: 'Bad Request', message: '旧密码错误', } const mockChangePassword = authClient.changePassword as jest.MockedFunction mockChangePassword.mockRejectedValue(mockError) const { result } = renderHook(() => useChangePassword()) await act(async () => { await result.current.changePassword({ oldPassword: 'wrongPass', newPassword: 'newPass123', }) }) expect(result.current.error).toEqual(mockError) }) it('should set loading state during password change', async () => { let resolveChangePassword: (value: any) => void const changePasswordPromise = new Promise((resolve) => { resolveChangePassword = resolve }) const mockChangePassword = authClient.changePassword as jest.MockedFunction mockChangePassword.mockReturnValue(changePasswordPromise) const { result } = renderHook(() => useChangePassword()) act(() => { result.current.changePassword({ oldPassword: 'oldPass123', newPassword: 'newPass123', }) }) expect(result.current.loading).toBe(true) await act(async () => { resolveChangePassword!({ error: null }) await changePasswordPromise }) expect(result.current.loading).toBe(false) }) })