Files
user-system/frontend/admin/src/pages/auth/ResetPasswordPage/ResetPasswordPage.test.tsx

122 lines
4.8 KiB
TypeScript

import { MemoryRouter, Route, Routes } from 'react-router-dom'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { message } from 'antd'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { ResetPasswordPage } from './ResetPasswordPage'
const validateResetTokenMock = vi.fn()
const resetPasswordMock = vi.fn()
vi.mock('@/services/auth', () => ({
validateResetToken: (token: string) => validateResetTokenMock(token),
resetPassword: (payload: unknown) => resetPasswordMock(payload),
}))
function renderResetPasswordPage(initialEntry: string) {
return render(
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={[initialEntry]}>
<Routes>
<Route path="/reset-password" element={<ResetPasswordPage />} />
</Routes>
</MemoryRouter>,
)
}
describe('ResetPasswordPage', () => {
beforeEach(() => {
validateResetTokenMock.mockReset()
resetPasswordMock.mockReset()
validateResetTokenMock.mockResolvedValue({
valid: true,
email: 'user@example.com',
expires_at: '2026-03-28T12:00:00Z',
})
resetPasswordMock.mockResolvedValue(undefined)
vi.spyOn(message, 'success').mockImplementation(() => undefined as never)
vi.spyOn(message, 'error').mockImplementation(() => undefined as never)
})
it('shows an invalid-link state when the reset token is missing', async () => {
renderResetPasswordPage('/reset-password')
expect(await screen.findByText('链接无效')).toBeInTheDocument()
expect(validateResetTokenMock).not.toHaveBeenCalled()
expect(screen.getByRole('button', { name: '重新申请' })).toBeInTheDocument()
expect(screen.getByRole('button', { name: '返回登录' })).toBeInTheDocument()
})
it('shows an invalid-link state when token validation fails', async () => {
validateResetTokenMock.mockRejectedValueOnce(new Error('token invalid'))
renderResetPasswordPage('/reset-password?token=expired-token')
await waitFor(() => expect(validateResetTokenMock).toHaveBeenCalledWith('expired-token'))
expect(await screen.findByText('链接无效')).toBeInTheDocument()
expect(screen.getByRole('button', { name: '重新申请' })).toBeInTheDocument()
})
it('renders the reset form after token validation succeeds', async () => {
renderResetPasswordPage('/reset-password?token=token-123')
await waitFor(() => expect(validateResetTokenMock).toHaveBeenCalledWith('token-123'))
expect(await screen.findByRole('heading', { name: '重置密码' })).toBeInTheDocument()
expect(screen.getByPlaceholderText('新密码')).toBeInTheDocument()
expect(screen.getByPlaceholderText('确认新密码')).toBeInTheDocument()
expect(screen.getByRole('button', { name: '确认重置' })).toBeInTheDocument()
expect(screen.getByText('user@example.com')).toBeInTheDocument()
})
it('submits the new password and shows the success state', async () => {
const user = userEvent.setup()
const { container } = renderResetPasswordPage('/reset-password?token=token-123')
await waitFor(() => expect(validateResetTokenMock).toHaveBeenCalledWith('token-123'))
await waitFor(() => expect(container.querySelectorAll('input[type="password"]')).toHaveLength(2))
const passwordInputs = Array.from(
container.querySelectorAll('input[type="password"]'),
) as HTMLInputElement[]
await user.type(passwordInputs[0], 'NewPass123!')
await user.type(passwordInputs[1], 'NewPass123!')
await user.click(screen.getByRole('button', { name: '确认重置' }))
await waitFor(() =>
expect(resetPasswordMock).toHaveBeenCalledWith({
token: 'token-123',
new_password: 'NewPass123!',
confirm_password: 'NewPass123!',
}),
)
expect(await screen.findByText('密码已重置')).toBeInTheDocument()
expect(screen.getByRole('button', { name: '立即登录' })).toBeInTheDocument()
expect(message.success).toHaveBeenCalledWith('密码重置成功')
})
it('surfaces backend failures when resetting the password', async () => {
const user = userEvent.setup()
const { container } = renderResetPasswordPage('/reset-password?token=token-123')
resetPasswordMock.mockRejectedValueOnce(new Error('reset failed'))
await waitFor(() => expect(validateResetTokenMock).toHaveBeenCalledWith('token-123'))
await waitFor(() => expect(container.querySelectorAll('input[type="password"]')).toHaveLength(2))
const passwordInputs = Array.from(
container.querySelectorAll('input[type="password"]'),
) as HTMLInputElement[]
await user.type(passwordInputs[0], 'NewPass123!')
await user.type(passwordInputs[1], 'NewPass123!')
await user.click(screen.getByRole('button', { name: '确认重置' }))
await waitFor(() => expect(message.error).toHaveBeenCalledWith('reset failed'))
})
})