auth page enhancement

This commit is contained in:
2026-03-18 18:04:41 +08:00
parent b6abf43075
commit 58e1c34b69
8 changed files with 640 additions and 2 deletions
@@ -0,0 +1,149 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { mount, flushPromises } from '@vue/test-utils'
import { nextTick } from 'vue'
import { message } from 'ant-design-vue'
import { ApiError } from '@/types/api'
import { useUserStore } from '@/stores/user'
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: (query: string) => ({
matches: false,
media: query,
onchange: null,
addListener: () => {},
removeListener: () => {},
addEventListener: () => {},
removeEventListener: () => {},
dispatchEvent: () => false,
}),
})
vi.mock('@/utils/request', () => ({
api: {
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
},
}))
const mockPush = vi.fn()
vi.mock('vue-router', () => ({
useRouter: () => ({ push: mockPush }),
useRoute: () => ({ path: '/profile/password' }),
}))
describe('Password Change Page', () => {
let wrapper: ReturnType<typeof mount>
beforeEach(() => {
setActivePinia(createPinia())
localStorage.clear()
vi.restoreAllMocks()
mockPush.mockReset()
vi.useFakeTimers()
})
afterEach(() => {
wrapper?.unmount()
vi.useRealTimers()
})
async function mountPage() {
const store = useUserStore()
store.setToken('h.p.s', 'r.p.s', true)
store.setUser({ id: 1, username: 'u', email: 'u@e.com', role: 'user', status: 1 })
const { default: PasswordPage } = await import('../password.vue')
wrapper = mount(PasswordPage, { attachTo: document.body })
await flushPromises()
await nextTick()
return wrapper
}
it('renders three password fields', async () => {
await mountPage()
const html = wrapper.html()
expect(html).toContain('当前密码')
expect(html).toContain('新密码')
expect(html).toContain('确认新密码')
})
it('submits password change and redirects to login', async () => {
const { api } = await import('@/utils/request')
vi.mocked(api.put).mockResolvedValueOnce(undefined)
const successSpy = vi.spyOn(message, 'success').mockImplementation(() => ({}) as never)
await mountPage()
const vm = wrapper.getCurrentComponent().setupState
vm.formState.old_password = 'oldpass'
vm.formState.new_password = 'newpass123'
vm.formState.new_password_confirmation = 'newpass123'
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
await vm.handleSubmit()
await flushPromises()
expect(api.put).toHaveBeenCalledWith('/api/v1/me/password', {
old_password: 'oldpass',
new_password: 'newpass123',
new_password_confirmation: 'newpass123',
})
expect(successSpy).toHaveBeenCalledWith('密码修改成功,请重新登录')
vi.advanceTimersByTime(1500)
expect(mockPush).toHaveBeenCalledWith('/login')
successSpy.mockRestore()
})
it('shows error message on ApiError (wrong old password)', async () => {
const { api } = await import('@/utils/request')
vi.mocked(api.put).mockRejectedValueOnce(new ApiError('旧密码错误', 422))
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
await mountPage()
const vm = wrapper.getCurrentComponent().setupState
vm.formState.old_password = 'wrong'
vm.formState.new_password = 'newpass123'
vm.formState.new_password_confirmation = 'newpass123'
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
await vm.handleSubmit()
await flushPromises()
expect(errorSpy).toHaveBeenCalledWith('旧密码错误')
expect(mockPush).not.toHaveBeenCalled()
errorSpy.mockRestore()
})
it('shows network error on generic failure', async () => {
const { api } = await import('@/utils/request')
vi.mocked(api.put).mockRejectedValueOnce(new Error('Network'))
const errorSpy = vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
await mountPage()
const vm = wrapper.getCurrentComponent().setupState
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
await vm.handleSubmit()
await flushPromises()
expect(errorSpy).toHaveBeenCalledWith('密码修改失败,请检查网络连接')
errorSpy.mockRestore()
})
it('does not redirect on error', async () => {
const { api } = await import('@/utils/request')
vi.mocked(api.put).mockRejectedValueOnce(new ApiError('旧密码错误', 422))
vi.spyOn(message, 'error').mockImplementation(() => ({}) as never)
await mountPage()
const vm = wrapper.getCurrentComponent().setupState
vm.formRef = { validate: vi.fn().mockResolvedValue(true) }
await vm.handleSubmit()
await flushPromises()
vi.advanceTimersByTime(2000)
expect(mockPush).not.toHaveBeenCalled()
})
})