npm i -D jest jest-environment-jsdom:安装依赖项
npm i -D babel-jest @babel/core @babel/preset-env:使用babel
// babel.config.js
module.exports = {
presets: [['@babel/preset-env']]
}
npx jest --init:初始化jest.config.js
jest.config.js配置文件中:
// 要测试的文件
testMatch: [
"**/__tests__/**/*.[jt]s?(x)",
"**/?(*.)+(spec|test).[tj]s?(x)"
],
// demo.test.js文件
// 钩子函数
beforeEach(() => { console.log('beforeEach') })
afterEach(() => { console.log('afterEach') })
beforeAll(() => { console.log('beforeAll') })
afterAll(() => { console.log('afterAll') })
// describe(name, fn) 是一个将多个相关的测试组合在一起的块
describe('A组件', () => {
test('方法1', () => {
expect(1 + 2).toBe(3)
})
test('方法2', () => {
expect(1 + 2).toEqual(3)
})
})
test('demo', ()=>{
expect({ name: 'tom' }).toEqual({ name: 'tom' })
expect('helloworld').toMatch(/world/)
expect(3).toBeGreaterThan(2)
expect(3).toBeGreaterThanOrEqual(2)
expect(3).toBeLessThan(5)
expect(3).toBeLessThanOrEqual(5)
expect(0.1 + 0.2).toBeCloseTo(0.3)
const shoppingList = ['milk', 'coffee']
expect(shoppingList).toContain('milk');
expect(new Set(shoppingList)).toContain('milk');
// let flag = false
// expect(flag).toBeNull()
// expect(flag).toBeUndefined()
// expect(flag).toBeFalsy()
// expect(flag).toBeTruthy
}
function compileAndroidCode() {
throw new Error('you are using the wrong JDK');
}
test('compiling android goes as expected', () => {
expect(() => compileAndroidCode()).toThrow();
expect(() => compileAndroidCode()).toThrow(Error);
// You can also use the exact error message or a regexp
expect(() => compileAndroidCode()).toThrow('you are using the wrong JDK');
expect(() => compileAndroidCode()).toThrow(/JDK/);
});
// 异步测试1
function getData(callback) {
setTimeout(() => {
callback({ foo: 'bar' })
}, 2000)
}
test('async test', (done) => {
getData(data => {
done()
expect(data).toEqual({ foo: 'bar' })
})
})
// 异步测试2
function getData() {
return new Promise((resolve, reject) => {
// reject('hello')
setTimeout(() => {
resolve({ foo: 'bar' })
}, 2000)
})
}
test('async test', (done) => {
getData().then(data => {
done()
expect(data).toEqual({ foo: 'bar' })
})
})
// 不用done的写法
test('async test', () => {
// return getData().then(data => {
// expect(data).toEqual({ foo: 'bar' })
// })
//也可这样写
return expect(getData()).resolves.toEqual({ foo: 'bar' })
// 异常 reject('hello')
// return expect(getData()).rejects.toMatch('hello')
})
// async await
test('async', async () => {
try {
const data = await getData()
expect(data).toEqual({ foo: 'bar' })
} catch (err) {
expect(err).toMatch('hello')
}
// 或者这样写
// await expect(getData()).resolves.toEqual({ foo: 'bar' })
// await expect(getData()).rejects.toMatch('hello')
})
Mock定时器
// 耗时的异步测试
function getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ foo: 'bar' })
}, 60000)
})
}
// mock定时器
jest.useFakeTimers()
test('demo', () => {
expect.assertions(1)
getData().then(data => {
expect(data).toEqual({ foo: 'bar' })
})
// 快速所有定时器
jest.runAllTimers()
})
// 循环定时器
function getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ foo: 'bar' })
getData()
}, 60000)
})
}
// mock定时器
jest.useFakeTimers()
test('demo', () => {
expect.assertions(1)
getData().then(data => {
expect(data).toEqual({ foo: 'bar' })
})
// 快进当前的定时器家属,不等待其他的
jest.runOnlyPendingTimers(
function getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ foo: 'bar' })
}, 2000)
})
}
// mock定时器
jest.useFakeTimers()
test('demo', () => {
expect.assertions(1)
getData().then(data => {
expect(data).toEqual({ foo: 'bar' })
})
jest.advanceTimersByTime(1000)
console.log(1)
jest.advanceTimersByTime(1000)
})
Mock函数
// 基本用法
function forEach(items, callbask) {
for (let i = 0; i < items.length; i++) {
callbask(items[i], i)
}
}
test('Mock Function', () => {
const items = [1, 2, 3]
const mockFn = jest.fn((val, index) => {
return val + 1
})
// 设置所有的mock函数返回值为123
// mockFn.mockReturnValue(123)
// 与mockFn.mockReturnValue(123)作用相同
// mockFn.mockReturnValueOnce(123)
// mockFn.mockReturnValueOnce(123)
// mockFn.mockReturnValueOnce(123)
forEach(items, mockFn)
console.log(mockFn.mock)
expect(mockFn.mock.calls.length).toBe(items.length)
expect(mockFn.mock.calls[0][0]).toBe(1)
expect(mockFn.mock.calls[0][1]).toBe(0)
})
// 模拟模块
//users.js
import axios from 'axios'
export const getAllusers = () => {
return axios.get('/users.json').then(res => res.data)
}
// mock-function.test.js
import axios from 'axios'
import { getAllusers } from './users'
jest.mock('axios')
test('should fetch users', async () => {
const users = [{ name: 'Bob' }]
const res = { data: users }
axios.get.mockResolvedValue(res)
const data = await getAllusers()
expect(data).toEqual(users)
})
// 模拟实现
//foo.js
export default function foo() {
return 1
}
// mock-function.test.js
jest.mock('./foo')
import foo from './foo'
foo.mockImplementation(() => 123)
test('Mock Implementations', () => {
expect(foo()).toBe(123)
})
DOM测试
function renderHtml() {
const div = document.createElement('div')
div.innerHTML = `
<h1>Hello World</h1>
`
document.body.appendChild(div)
}
test('DOM Testing', () => {
renderHtml()
expect(document.querySelector('h1').innerHTML).toBe('Hello World')
})
function renderVueComponent() {
document.body.innerHTML = `<div id="app"></div>`
new Vue({
template: `
<div id="app"><h1>{{message}}</h1></div>
`,
data: {
message: 'Hello World'
}
}).$mount('#app')
}
test('Vue Testing', () => {
renderVueComponent()
console.log(document.body.innerHTML)
expect(document.body.innerHTML).toMatch(/Hello World/)
})
快照测试
test.only('Snapshot Testing', () => {
renderVueComponent()
expect(document.body.innerHTML).toMatchSnapshot()
})
// 更新快照命令:npx jest --updateSnapshot