前端单测学习(6)—— 定时器

1,734 阅读3分钟

前言

在之前的文章中我们已经学习了不少单测的相关知识,这一篇我们来补充一个知识点,测试定时器(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之后内容变更了

image.png

编写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

image.png 这里我们用到了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的情况
看下结果

image.png

传送门

前端单测学习(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…