150 lines
4.7 KiB
TypeScript
150 lines
4.7 KiB
TypeScript
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()
|
|
})
|
|
})
|