test: add vitest config and unit tests
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
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'
|
||||
|
||||
// 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/>' } },
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
describe('Login.vue logic', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
localStorage.clear()
|
||||
})
|
||||
|
||||
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('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()
|
||||
})
|
||||
})
|
||||
|
||||
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()
|
||||
|
||||
// Simulate submitForm logic
|
||||
const username = 'admin'
|
||||
const password = '123456'
|
||||
const result = await login(username, password)
|
||||
|
||||
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')
|
||||
})
|
||||
|
||||
it('shows error message on failed login', async () => {
|
||||
vi.mocked(login).mockResolvedValue({ code: 401, message: '密码错误' } as any)
|
||||
|
||||
const result = await login('admin', 'wrong')
|
||||
if (result.code !== 200) {
|
||||
ElMessage.error(result.message)
|
||||
}
|
||||
|
||||
expect(ElMessage.error).toHaveBeenCalledWith('密码错误')
|
||||
expect(localStorage.getItem('isLoggedIn')).toBeNull()
|
||||
})
|
||||
|
||||
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()
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user