test: 单元测试改为直接测试真实代码

This commit is contained in:
2026-08-03 22:21:36 +08:00
parent f71abdd000
commit 6595ed0dfc
9 changed files with 522 additions and 808 deletions
+64 -85
View File
@@ -1,112 +1,91 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount } from '@vue/test-utils'
import { createRouter, createMemoryHistory } from 'vue-router'
import { reactive, ref } from 'vue'
import ElementPlus from 'element-plus'
import { ElMessage } from 'element-plus'
import Login from '@/components/Login.vue'
import router from '@/router'
import { login } from '@/api/login'
// Mock API
vi.mock('@/api/login', () => ({
login: vi.fn(),
logout: vi.fn(),
}))
// Mock Element Plus
vi.mock('element-plus', () => ({
ElMessage: {
success: vi.fn(),
error: vi.fn(),
warning: vi.fn(),
info: vi.fn(),
},
}))
import { login } from '@/api/login'
import { ElMessage } from 'element-plus'
function createTestRouter() {
return createRouter({
history: createMemoryHistory(),
routes: [
{ path: '/login', component: { template: '<div/>' } },
{ path: '/welcome', component: { template: '<div/>' } },
],
function mountLogin() {
return mount(Login, {
shallow: true,
global: {
plugins: [ElementPlus, router],
},
})
}
describe('Login.vue logic', () => {
beforeEach(() => {
function createForm(valid = true) {
return {
validate: (callback: (valid: boolean) => void) => callback(valid),
} as any
}
describe('Login.vue', () => {
beforeEach(async () => {
vi.clearAllMocks()
localStorage.clear()
await router.push('/login')
await router.isReady()
})
describe('isNotEmpty validator', () => {
it('calls callback with error message when value is empty', () => {
const callback = vi.fn()
const rule = { message: '请输入账号!' }
// isNotEmpty logic
const value = ''
if (!value) {
callback(rule.message)
} else {
callback()
}
expect(callback).toHaveBeenCalledWith('请输入账号!')
})
it('isNotEmpty validator reports empty value and accepts filled value', () => {
const wrapper = mountLogin()
const callback = vi.fn()
it('calls callback without error when value is present', () => {
const callback = vi.fn()
const rule = { message: '请输入账号!' }
const value = 'admin'
if (!value) {
callback(rule.message)
} else {
callback()
}
expect(callback).toHaveBeenCalledWith()
})
wrapper.vm.isNotEmpty({ message: '请输入账号!' } as any, '', callback)
expect(callback).toHaveBeenCalledWith('请输入账号!')
wrapper.vm.isNotEmpty({ message: '请输入账号!' } as any, 'admin', callback)
expect(callback).toHaveBeenCalledWith()
})
describe('submitForm logic', () => {
it('sets localStorage and navigates on successful login', async () => {
vi.mocked(login).mockResolvedValue({ code: 200, message: '登录成功' } as any)
const router = createTestRouter()
await router.push('/login')
await router.isReady()
it('sets localStorage and navigates on successful login', async () => {
vi.mocked(login).mockResolvedValue({ code: 200, message: '登录成功' } as any)
const wrapper = mountLogin()
wrapper.vm.registerData.username = 'admin'
wrapper.vm.registerData.password = '123456'
// Simulate submitForm logic
const username = 'admin'
const password = '123456'
const result = await login(username, password)
await wrapper.vm.submitForm(createForm(true))
if (result.code === 200) {
localStorage.setItem('isLoggedIn', 'true')
ElMessage.success(result.message)
await router.push('/welcome')
}
expect(localStorage.getItem('isLoggedIn')).toBe('true')
expect(ElMessage.success).toHaveBeenCalledWith('登录成功')
expect(router.currentRoute.value.path).toBe('/welcome')
})
expect(localStorage.getItem('isLoggedIn')).toBe('true')
expect(ElMessage.success).toHaveBeenCalledWith('登录成功')
expect(router.currentRoute.value.path).toBe('/welcome')
})
it('shows error message on failed login', async () => {
vi.mocked(login).mockResolvedValue({ code: 401, message: '密码错误' } as any)
const wrapper = mountLogin()
wrapper.vm.registerData.username = 'admin'
wrapper.vm.registerData.password = 'wrong'
it('shows error message on failed login', async () => {
vi.mocked(login).mockResolvedValue({ code: 401, message: '密码错误' } as any)
await wrapper.vm.submitForm(createForm(true))
const result = await login('admin', 'wrong')
if (result.code !== 200) {
ElMessage.error(result.message)
}
expect(ElMessage.error).toHaveBeenCalledWith('密码错误')
expect(localStorage.getItem('isLoggedIn')).toBeNull()
expect(router.currentRoute.value.path).toBe('/login')
})
expect(ElMessage.error).toHaveBeenCalledWith('密码错误')
expect(localStorage.getItem('isLoggedIn')).toBeNull()
})
it('does not submit again while loading', async () => {
let resolveLogin!: (value: any) => void
vi.mocked(login).mockImplementation(
() => new Promise((resolve) => { resolveLogin = resolve }),
)
const wrapper = mountLogin()
it('does not submit when already loading', async () => {
const loading = ref(true)
// Simulate guard: if (!formEl || loading.value) return;
if (loading.value) {
// Early return - no API call
}
expect(login).not.toHaveBeenCalled()
})
const firstSubmit = wrapper.vm.submitForm(createForm(true))
const secondSubmit = wrapper.vm.submitForm(createForm(true))
await Promise.resolve()
expect(login).toHaveBeenCalledTimes(1)
resolveLogin({ code: 200, message: '登录成功' })
await Promise.all([firstSubmit, secondSubmit])
expect(localStorage.getItem('isLoggedIn')).toBe('true')
})
})