expo-popcore-app/tests/hooks/use-change-password.test.ts

157 lines
4.3 KiB
TypeScript

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<typeof authClient.changePassword>
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<typeof authClient.changePassword>
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<typeof authClient.changePassword>
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)
})
})