前言
在之前的文章中我们已经学习了不少单测的相关知识,这一篇我们来补充一个知识点,测试定时器(timer)相关的功能,在js中setTimeout setInterval clearTimeout clearTimeout,clearInterval这些都是非常重要的api,在我们的开发中时不时会用到,当然一般用了react的话自己会尽量避免使用这些,除非是真的很有必要。针对定时器的这些api我们也需要响应的能力来测试定时器。
编写Timeout组件
由于我们之前的写的组件都没有用到定时器,所以我们写一个使用了定时器的组件
在components
目录下新建一个todo-timer
的组件
import { useState, useEffect } from "react";
export default function TodoTimer() {
const [todoContent, setTodoContent] = useState("");
useEffect(() => {
const timerId = setTimeout(() => {
setTodoContent("延迟1s后的内容");
}, 1000);
return () => {
clearTimeout(timerId);
};
}, []);
return <span>{todoContent}</span>;
}
走读一下这个组件,这个组件用了setTimeout
启动了定时器,初始化之后启动定时器,1s之后改变内容并且渲染到视图中,最后clearTimeout
清除副作用
看一下效果,在App.tsx中引入,可以看到1s之后内容变更了
编写Timeout单测
和之前一样我们还是在components/__tests__
目录下新建对应的单测文件,命名为todo-timer.test.tsx
import { act, render } from "@testing-library/react";
import TodoTimer from "../todo-timer";
describe("测试TodoTimer组件", () => {
it("正确运行定时器", async () => {
jest.useFakeTimers();
const { queryByText } = render(<TodoTimer />);
act(() => {
jest.runAllTimers();
});
const element = queryByText("延迟1s后的内容");
expect(element).not.toBeNull();
});
});
我们运行一下这个单测
pnpm test src/components/__tests__/todo-timer.test.tsx
这里我们用到了jest两个新的api,我们简单说明一下
- jest.useFakeTimers(): 模拟定时器的执行,不用再等待指定的时间
- jest.runAllTimers(): 把所有的定时器执行
这里我们通过这两个api来运行定时器,因为在实际应用中我们定时器的等待时间可能非常的长,而我们单测的目的只是想保证我们的输入输出是否符合预期,按定时器设置的事件来等待没有太大意义,而且也不现实,所以我们通过这两个api的作用直接运行模拟定时器的执行即可。
然后就是跟我们之前的判断基本一致,判断页面中是否有符合预期的输出即可。
编写Interval组件
上面我们写了一个setTimeout的例子,这里我们再补充一个setIntervael的例子,新建一个todo-interval
组件
import { useState, useEffect } from "react";
export default function TodoInterval({ callback }: { callback: () => void }) {
const [todoContent, setTodoContent] = useState("");
useEffect(() => {
const timerId = setInterval(() => {
setTodoContent("延迟1s后的内容");
callback();
}, 1000);
return () => {
clearInterval(timerId);
};
}, [callback]);
return <span>{todoContent}</span>;
}
和上面的timeout组件不一样的是我们这里增加了一个callback,定时器生效的时候顺便调用这个回调函数
编写Interval单测
import { act, render } from "@testing-library/react";
import TodoInterval from "../todo-interval";
describe("测试TodoInterval组件", () => {
it("正确运行定时器", async () => {
jest.useFakeTimers();
const callback = jest.fn();
render(<TodoInterval callback={callback} />);
act(() => {
jest.runOnlyPendingTimers();
});
expect(callback).toBeCalled();
});
});
这里我们补充了一个新的api,jest.runOnlyPendingTimers();
,这个和之前的runAllTimer
的区别在于这个api主要是用来处理一些有循环定时器的情况,例如setTimeout里面嵌套setTimeout的情况或者这种setInterval的情况
看下结果
传送门
前端单测学习(1)—— 单测入门之react单测项目初步
前端单测学习(2)—— react 组件单测初步
前端单测学习(3)—— react组件单测进阶
前端单测学习(4)—— react 组件方法&fireEvent
前端单测学习(5)—— 快照
前端单测学习(6)—— 定时器
前端单测学习(7)—— mock
前端单测学习(8)—— react hook
前端单测学习(9)—— 覆盖率报告
前端单测学习(10)—— 状态管理redux
前端单测学习(11)—— react hook 进阶
前端单测学习(12)—— 性能优化
前端单测学习(13)—— 自动化测试
代码仓库:github.com/liyixun/rea…