【实战】十二、自动化测试 —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十九)

文章目录


学习内容来源:React + React Hook + TS 最佳实践-慕课网


相对原教程,我在学习开始时(2023.03)采用的是当前最新版本:

版本
react & react-dom ^18.2.0
react-router & react-router-dom ^6.11.2
antd ^4.24.8
@commitlint/cli & @commitlint/config-conventional ^17.4.4
eslint-config-prettier ^8.6.0
husky ^8.0.3
lint-staged ^13.1.2
prettier 2.8.4
json-server 0.17.2
craco-less ^2.0.0
@craco/craco ^7.1.0
qs ^6.11.0
dayjs ^1.11.7
react-helmet ^6.1.0
@types/react-helmet ^6.1.6
react-query ^6.1.0
@welldone-software/why-did-you-render ^7.0.1
@emotion/react & @emotion/styled ^11.10.6

具体配置、操作和内容会有差异,"坑"也会有所不同。。。


一、项目起航:项目初始化与配置

二、React 与 Hook 应用:实现项目列表

三、TS 应用:JS神助攻 - 强类型

四、JWT、用户认证与异步请求


五、CSS 其实很简单 - 用 CSS-in-JS 添加样式


六、用户体验优化 - 加载中和错误状态处理



七、Hook,路由,与 URL 状态管理



八、用户选择器与项目编辑功能


九、深入React 状态管理与Redux机制





十、用 react-query 获取数据,管理缓存


十一、看板页面及任务组页面开发






十二、自动化测试

1.简介

目的

防止出现"新代码破坏旧代码"的无限循环,让开发过程不再战战兢兢。

分类

单元测试:传统单元测试、组件测试、hook测试

集成测试:模块级别

e2e测试(end):页面级别

2.传统单元测试

之前初始化项目的时候,默认安装了几个相关依赖:

json 复制代码
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",

再补充几个:

bash 复制代码
npm i @testing-library/react-hooks msw -D # --force

单元测试需要隔离环境,因此需要使用 msw 做 mock 使用

接下来写一个单元测试:

新建 src\__tests__\http.ts(用来测试 src\utils\http.ts

js 复制代码
import { setupServer } from "msw/node";
import { rest } from "msw";
import { http } from "utils/http";

const apiUrl = process.env.REACT_APP_API_URL;

const server = setupServer();

// jest 是对react最友好的一个测试库
// beforeAll 代表执行所有的测试之前,先来执行一下回调函数
beforeAll(() => server.listen());

// 每一个测试跑完以后,都重置mock路由
afterEach(() => server.resetHandlers());

// 所有的测试跑完后,关闭mock路由
afterAll(() => server.close());

test("http方法发送异步请求", async () => {
  const endpoint = "test-endpoint";
  const mockResult = { mockValue: "mock" };

  server.use(
    rest.get(`${apiUrl}/${endpoint}`, (req, res, ctx) =>
      res(ctx.json(mockResult))
    )
  );

  const result = await http(endpoint);
  expect(result).toEqual(mockResult);
});

test("http请求时会在header里带上token", async () => {
  const token = "FAKE_TOKEN";
  const endpoint = "test-endpoint";
  const mockResult = { mockValue: "mock" };

  let request: any;

  server.use(
    rest.get(`${apiUrl}/${endpoint}`, async (req, res, ctx) => {
      request = req;
      return res(ctx.json(mockResult));
    })
  );

  await http(endpoint, { token });
  expect(request.headers.get("Authorization")).toBe(`Bearer ${token}`);
});

执行 npm run test, 启动单元测试, 执行结果如下:

bash 复制代码
 PASS  src/__tests__/http.ts (5.495 s)
  √ http方法发送异步请求 (57 ms)
  √ http请求时会在header里带上token (7 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        7.61 s
Ran all test suites related to changed files.

Watch Usage: Press w to show more.

3.自动化测试 hook

新建 src\__tests__\use-async.ts

js 复制代码
import { useAsync } from "utils/use-async";
import { act, renderHook } from "@testing-library/react-hooks";

const defaultState: ReturnType<typeof useAsync> = {
  stat: "idle",
  data: null,
  error: null,

  isIdle: true,
  isLoading: false,
  isError: false,
  isSuccess: false,

  run: expect.any(Function),
  setData: expect.any(Function),
  setError: expect.any(Function),
  retry: expect.any(Function),
};

const loadingState: ReturnType<typeof useAsync> = {
  ...defaultState,
  stat: "loading",
  isIdle: false,
  isLoading: true,
};

const successState: ReturnType<typeof useAsync> = {
  ...defaultState,
  stat: "success",
  isIdle: false,
  isSuccess: true,
};

test("useAsync 可以异步处理", async () => {
  let resolve: any, reject;
  const promise = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });

  const { result } = renderHook(() => useAsync());
  expect(result.current).toEqual(defaultState);

  let p: Promise<any>;
  act(() => {
    p = result.current.run(promise);
  });
  expect(result.current).toEqual(loadingState);
  const resolvedValue = { mockedValue: "resolved" };
  await act(async () => {
    resolve(resolvedValue);
    await p;
  });
  expect(result.current).toEqual({
    ...successState,
    data: resolvedValue,
  });
});

4.自动化测试组件

新建 src\__tests__\mark.tsx:

js 复制代码
import React from "react";
import { render, screen } from "@testing-library/react";
import { Mark } from "components/mark";

test("Mark 组件正确高亮关键词", () => {
  const name = "物料管理";
  const keyword = "管理";

  render(<Mark name={name} keyword={keyword} />);

  expect(screen.getByText(keyword)).toBeInTheDocument();
  expect(screen.getByText(keyword)).toHaveStyle("color: #257AFD");
  expect(screen.getByText("物料")).not.toHaveStyle("color: #257AFD");
});


部分引用笔记还在草稿阶段,敬请期待。。。

相关推荐
码界奇点2 分钟前
Java Web学习 第1篇前端基石HTML 入门与核心概念解析
java·前端·学习·xhtml
云枫晖7 分钟前
Webpack系列-开发环境
前端·webpack
Rverdoser12 分钟前
制作网站的价格一般由什么组成
前端·git·github
拉不动的猪12 分钟前
深入理解 JavaScript 中的静态属性、原型属性与实例属性
前端·javascript·面试
linda261820 分钟前
链接形式与跳转逻辑总览
前端·javascript
怪可爱的地球人25 分钟前
骨架屏
前端
AAA不会前端开发25 分钟前
前端React实战项目 新闻管理发布系统
react.js
用户6778471506228 分钟前
前端将html导出为word文件
前端
前端付豪30 分钟前
如何使用 Vuex 设计你的数据流
前端·javascript·vue.js
李雨泽32 分钟前
通过 Prisma 将结构推送到数据库
前端