3.7 KiB
3.7 KiB
前端测试 (Vue + React)
Vue 前端测试
测试框架
- Vitest: 测试运行器
- Vue Test Utils: 组件测试
- MSW: API Mock
运行测试
npm run test
npm run test:watch
npm run test:coverage
组件测试
// UserList.test.ts
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import UserList from './UserList.vue'
describe('UserList', () => {
it('renders user list', () => {
const wrapper = mount(UserList, {
props: {
users: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
}
})
expect(wrapper.findAll('.user-item')).toHaveLength(2)
expect(wrapper.text()).toContain('Alice')
})
it('emits select event', async () => {
const wrapper = mount(UserList, {
props: { users: [{ id: 1, name: 'Alice' }] }
})
await wrapper.find('.user-item').trigger('click')
expect(wrapper.emitted('select')).toBeTruthy()
expect(wrapper.emitted('select')[0]).toEqual([1])
})
it('shows empty state', () => {
const wrapper = mount(UserList, {
props: { users: [] }
})
expect(wrapper.find('.empty-state').exists()).toBe(true)
})
})
API Mock (MSW)
// mocks/handlers.ts
import { rest } from 'msw'
export const handlers = [
rest.get('/api/v1/users', (req, res, ctx) => {
return res(ctx.json({
code: 0,
data: {
total: 2,
list: [{ id: 1, name: 'Alice' }]
}
}))
}),
rest.post('/api/v1/users', async (req, res, ctx) => {
const body = await req.json()
return res(ctx.json({
code: 0,
data: { id: 3, ...body }
}))
})
]
React 前端测试
测试框架
- Jest: 测试运行器
- React Testing Library: 组件测试
- Playwright: E2E 测试
运行测试
npm test
npm run test:e2e
npm run test:e2e:headed
组件测试
// TaskCard.test.tsx
import { render, screen, fireEvent } from '@testing-library/react'
import TaskCard from './TaskCard'
describe('TaskCard', () => {
const mockTask = {
id: 1,
title: 'Test Task',
status: 'todo',
priority: 'high'
}
it('renders task title', () => {
render(<TaskCard task={mockTask} />)
expect(screen.getByText('Test Task')).toBeInTheDocument()
})
it('displays priority', () => {
render(<TaskCard task={mockTask} />)
expect(screen.getByText('high')).toHaveClass('priority-high')
})
it('calls onClick', () => {
const handleClick = jest.fn()
render(<TaskCard task={mockTask} onClick={handleClick} />)
fireEvent.click(screen.getByRole('article'))
expect(handleClick).toHaveBeenCalledWith(mockTask)
})
})
Hook 测试
// useTimer.test.ts
import { renderHook, act } from '@testing-library/react-hooks'
import { useTimer } from './useTimer'
describe('useTimer', () => {
beforeEach(() => jest.useFakeTimers())
afterEach(() => jest.useRealTimers())
it('starts timer', () => {
const { result } = renderHook(() => useTimer())
act(() => result.current.start())
expect(result.current.isRunning).toBe(true)
})
it('increments time', () => {
const { result } = renderHook(() => useTimer())
act(() => {
result.current.start()
jest.advanceTimersByTime(3000)
})
expect(result.current.seconds).toBe(3)
})
})