1. 安装
1.1 最新版本的jest安装需要babel 7.X
npm install babel-jest jest --save-dev
1.2 babel 6.X的可安装以下版本或者升级babel
npm install [email protected] [email protected] --save-dev
1.3 jest不支持import语法 要安装
npm install babel-plugin-transform-es2015-modules-commonjs --save-dev
2. 配置packge.json
script: {
"test": "jest"
}
3. 初试demo
3.1 新建一个sum.js并编写
export function sum(a, b) {
return a + b;
};
3.2 新建一个sum.test.js并编写
import {sum} from "./sum.js";
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
3.3 在命令行输入
npm run jest
命令行打印为
PASS test/sum.test.js
√ adds 1 + 2 to equal 3 (3ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.829s
Ran all test suites.
4. 语法学习
4.1 expect
//示例语法
expect( 2 + 2 ).toBe( 4 )
- expect( 2 + 2)返回一个期望的对象
4.2 toBe
//示例语法
expect( 2 + 2 ).toBe( 4 )
- toBe() 是一个匹配器. 他是调用Object.is 来测试精确相等.
- 不能用来匹配浮点数相加,因为浮点数有舍入误差
- 如果想测试对象的值,请使用toEqual
4.3 toEqual(递归检查对象或数组的每个字段是否相等)
//示例语法
const data = {one: 1};
data['two'] = 2;
expect(data).toEqual({one: 1, two: 2});
4.4 not (类似于非运算符)
//示例语法
expect( 2 + 2 ).not.toBe( 0 )
4.5 匹配null、false、if语句的真假
- toBeNull 只匹配 null
- toBeUndefined 只匹配 undefined
- toBeDefined 与 toBeUndefined 相反
- toBeTruthy 匹配任何 if 语句为真
- toBeFalsy 匹配任何 if 语句为假
4.6 toBeCloseTo(用于匹配浮点数相加(比如float))
4.7 toMatch( 用正则来匹配字符串)
//示例代码
test('but there is a "stop" in Christoph', () => {
expect('Christoph').toMatch(/stop/);
});
4.8 toContain(检查一个数组或可迭代对象是否包含某个特定项)
const shoppingList = [
'diapers',
'kleenex',
'trash bags',
'paper towels',
'beer',
];
test('the shopping list has beer on it', () => {
expect(shoppingList).toContain('beer');
expect(new Set(shoppingList)).toContain('beer');
});
4.9 toThrow(测试的特定函数抛出一个错误)
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/);
});
5 回调函数callBack
export function fetchData(cb) {
setTimeout(() => {
cb("peanut butter");
}, 1000)
};
5.1 错误示例
import {fetchData} from "./sum.js";
test('cb prams jest', done => {
function cb(data) {
expect(data).toBe('peanut butter');
fetchData(cb);
});
- 这样测试会在执行完同步的fetchDate时,jest就会认为本次测试已经执行完,date不等于"peanut butter",而报错.
- 官方解释: 默认情况下,Jest 测试一旦执行到末尾就会完成。 那意味着该测试将不会按预期工作
5.1 正确示例
import {fetchData} from "./sum.js";
test('cb jest', done => {
function cb(data) {
try{
expect(data).toBe('peanut butter');
done();
} catch (error) {
done(error);
}
}
fetchData(cb);
});
使用单个参数调用 done,而不是将测试放在一个空参数的函数。 Jest会等done回调函数执行结束后,结束测试。
6. Promises( 如果承诺被拒绝,则测试将自动失败)
6.1 原始方法
export function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("peanut butter")
},500)
})
};
import {fetchData} from "./sum.js";
test('promise jest', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});
注意: 一定不要忘记把 promise 作为返回值⸺如果你忘了 return 语句的话,在 fetchData 返回的这个 promise 被 resolve、then() 有机会执行之前,测试就已经被视为已经完成了。
6.2 .resolves / .rejects
export function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("peanut butter")
},500)
})
};
import {fetchData} from "./sum.js";
test('promise jest', () => {
return expect(fetchData()).resolves.toBe('peanut butter');
});
一定不要忘记return!!!
test('the fetch fails with an error', () => {
return expect(fetchData()).rejects.toMatch('error');
});
6.3 async和await方案(最爽)
export function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("peanut butter")
},500)
})
};
import {fetchData} from "./sum.js";
test('async/auaiw jest', async () => {
const data = await fetchData();
expect(data).toBe("peanut butter")
});
7. 作用域(describe)
- 类似于js的花括号,形成自己的作用域
- 当 before 和 after 的块在 describe 块内部时,则其只适用于该 describe 块内的测试
8. 执行顺序
9. 快照
import React from 'react';
import Link from '../Link.react';
import renderer from 'react-test-renderer';
it('renders correctly', () => {
const tree = renderer
.create(Facebook)
.toJSON();
expect(tree).toMatchSnapshot();
});
9.1 更新快照
jest --updateSnapshot
10. 异步示例(不会)
11. 计时器模拟
11.1 模拟计时器
// timerGame.js
'use strict';
function timerGame(callback) {
console.log('Ready....go!');
setTimeout(() => {
console.log("Time's up -- stop!");
callback && callback();
}, 1000);
}
module.exports = timerGame;
// __tests__/timerGame-test.js
'use strict';
jest.useFakeTimers(); // 模拟定时器运行语句
test('waits 1 second before ending the game', () => {
const timerGame = require('../timerGame');
timerGame();
// 匹配被调用几次
expect(setTimeout).toHaveBeenCalledTimes(1);
// 匹配调用的时间间隔
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000);
});
- 可以通过jest.useFakeTimers()来模拟计时器函数
- 如果你需要在一个文件或一个描述块中运行多次测试,可以在每次测试前手动添加jest.useFakeTimers();或者在beforeEach中添加,如果不这样做的话将导致内部的计时器不被重置。
11.2 检测计时器的callback是否被执行
jest.useFakeTimers(); // 模拟计时器
test('calls the callback after 1 second', () => {
const timerGame = require('./sum');
const callback = jest.fn();
timerGame(callback);
// 在这个时间点,定时器的回调不应该被执行
expect(callback).not.toBeCalled();
// “快进”时间使得所有定时器回调被执行
jest.runAllTimers();
// 现在回调函数应该被调用了!
expect(callback).toBeCalled();
// cb应该只被执行了1次
expect(callback).toHaveBeenCalledTimes(1);
});
11.3 其他语法
- jest.runOnlyPendingTimers(); 运行待定计时器
- 按时间提前计时器
// “快进”时间,使得所有定时器回调都被执行
jest.advanceTimersByTime(1000);
12. 手动模拟
cnpm install [email protected] [email protected] babel-plugin-transform-require-ignore enzyme enzyme-adapter-react-16.1 enzyme-to-json --save-dev