auth page enhancement
This commit is contained in:
@@ -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()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user