Upload组件单元测试
上一篇文章中我们用React, Typescript开发了一个Upload
组件, 为了保证组件的健壮, 可用在这篇文章中我们将对该组件进行单元测试
在开始写测试用例之前我们先安装测试必须的依赖包@testing-library/jest-dom/extend-expect
该报主要用于模拟dom, @testing-library/react
该依赖包是React提供的供我们测试React组件
import '@testing-library/jest-dom/extend-expect'
import React from 'react'
import {render, renderResult, fireEvent, wait, createEvent} from '@testing-library/react'
import axios from 'axios'
import Upload, {UploadProps} from './upload'
const testProps: UploadProps = {
action: 'http://www.baidu.com',
onSuccess: jest.fn(),
onChange: jest.fn(),
onRemove: jest.fn(),
drag: true
}
首先我们导入了测试需要的依赖包, 然后创建了一个testProps
, 该props里包括Upload
组件的所需属性
let wrapper: renderResult, fileInput: HTMLInputElement, uploadArea: HTMLElement
describe('test upload component', () => {
beforeEach(() => {
wrapper = render(<Upload {...testProps}>Upload Files</Upload>)
fileInput = wrapper.container.querySelector('.r-file-input')
uploadArea = wrapper.queryByText('Upload Files')
})
})
在开始测试前我们需要render
出一个虚拟的Uplaod
组件, 接下来的测试中我们需要在虚拟的Upload
组件中做一些操作
const testFile = new File(['abc'], 'test.txt', {type: 'txt'})
describe('test upload component', () => {
beforeEach(() => {
...
})
it('upload process', async () => {
const {queryByText} = wrapper
// 期望uploadArea是HTML
expect(uploadArea).toBeInTheDocument()
// 期望fileInput是不可见的
expect(fileInput).not.toBeVisible()
// 对input模拟触发change事件并上传testFile
fireEvent.change(fileInput, {target: {files: [testFile]}})
// 期望出现spinner(上传时旋转的菊花动画)
expect(queryByText('spinner')).toBeInTheDocument()
// 一段时间后期望出现test.txt
await wait(() => {
expect(queryByText('test.txt')).toBeInTheDocument()
})
// 期望出现上传完成后的icon
expect(queryByText('check-circle')).toBeInTheDocument()
// 期望触发上传成功事件
expect(testProps.onSuccess).toHaveBeenCalledWith('ok', testFile)
expect(testProps.onChange).toHaveBeenCalledWith('testFile)
// 期望找到`times`
expect(queryByText('times')).toBeInTheDocument()
// 触发click
fireEvent.click(queryByText('times'))
expect(queryByText('test.txt')).not.toBeInTheDocument()
// 期望触发onRemove后返回文件信息
expect(testProps.onRemove).toHaveBeenCalledWith(expect.objectContaining({
raw: testFile,
status: 'success',
name: 'test.txt'
}))
})
}
第一个测试的是上传以及上传进度, 接下来完成拖拽测试
it('drag and drop file', async () => {
fireEvent.dragOver(uplodArea)
expect(uploadArea).toHaveClass('.is-dragover')
fireEvent.dragLeave(uploadArea)
expect(uploadArea).not.toHaveClass('.is-dragover')
const mockDropEvent = createEvent.drop(uploadArea)
Object.defineProperty(mockDropEvent, 'dataTransfer', {
value: {
files: [testFile]
}
})
fireEvent(uploadArea, mockDropEvent)
await wait(() => {
expect(wrapper.queryByText('test.txt')).toBeInTheDocument()
})
expect(testProps.onSuccess).toHaveBeenCalledWith('ok', testFile)
})
由于jest-dom
不支持drop事件, 所以我们需要用createEvent
模拟一个drop事件, 可以看到我们创建了一个mockDropEvent
事件并为其传入相应的参数, 最后模拟触发该事件以获取期望的结果.
最后说一下我们在测试之处有个action
props, 这涉及到了如何测试异步请求, 在此我们实现一下
jest.mock(axios)
const mockAxios = axios as jest.Mocked<typeof axios>
describe('upload component', () => {
...
it('test upload process', () => {
mockAxios.post.mockResolveValue({'data': 'ok'})
...
})
})