113 lines
3.1 KiB
TypeScript
113 lines
3.1 KiB
TypeScript
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()
|
|
})
|
|
})
|
|
})
|