码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 【实战】十二、自动化测试 —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十九)


    文章目录

      • 一、项目起航:项目初始化与配置
      • 二、React 与 Hook 应用:实现项目列表
      • 三、TS 应用:JS神助攻 - 强类型
      • 四、JWT、用户认证与异步请求
      • 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式
      • 六、用户体验优化 - 加载中和错误状态处理
      • 七、Hook,路由,与 URL 状态管理
      • 八、用户选择器与项目编辑功能
      • 九、深入React 状态管理与Redux机制
      • 十、用 react-query 获取数据,管理缓存
      • 十一、看板页面及任务组页面开发
      • 十二、自动化测试
        • 1.简介
        • 2.传统单元测试
        • 3.自动化测试 hook
        • 4.自动化测试组件


    学习内容来源: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
    prettier2.8.4
    json-server0.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 应用:实现项目列表

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

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

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

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

    • 四、 JWT、用户认证与异步请求(上)

    • 四、 JWT、用户认证与异步请求(下)

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

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

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

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

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

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

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

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

    • 七、Hook,路由,与 URL 状态管理(上)

    • 七、Hook,路由,与 URL 状态管理(中)

    • 七、Hook,路由,与 URL 状态管理(下)

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

    • 八、用户选择器与项目编辑功能(上)

    • 八、用户选择器与项目编辑功能(下)

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

    • 九、深入React 状态管理与Redux机制(一)

    • 九、深入React 状态管理与Redux机制(二)

    • 九、深入React 状态管理与Redux机制(三)

    • 九、深入React 状态管理与Redux机制(四)

    • 九、深入React 状态管理与Redux机制(五)

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

    • 十、用 react-query 获取数据,管理缓存(上)

    • 十、用 react-query 获取数据,管理缓存(下)

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

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

    • 十一、看板页面及任务组页面开发(二)

    • 十一、看板页面及任务组页面开发(三)

    • 十一、看板页面及任务组页面开发(四)

    • 十一、看板页面及任务组页面开发(五)

    • 十一、看板页面及任务组页面开发(六)

    十二、自动化测试

    1.简介

    目的

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

    分类

    单元测试:传统单元测试、组件测试、hook测试
    集成测试:模块级别
    e2e测试(end):页面级别

    2.传统单元测试

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

    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    
    • 1
    • 2
    • 3

    再补充几个:

    npm i @testing-library/react-hooks msw -D # --force
    
    • 1

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

    接下来写一个单元测试:

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

    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}`);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

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

     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.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.自动化测试 hook

    新建 src\__tests__\use-async.ts

    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,
      });
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    4.自动化测试组件

    新建 src\__tests__\mark.tsx:

    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");
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14


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

  • 相关阅读:
    cartographer接入2D雷达laser+odom+imu实时建图
    【Android 屏幕适配】屏幕适配基础概念 ① ( Android 与 iOS 屏幕宽高比种类 | 屏幕像素密度 DPI )
    利用vue-cli构建SPA项目以及在SPA项目中使用路由
    C语言常考面试基础问题
    k8s学习笔记一(搭建&部署helloworld应用)
    C++设计模式_14_Facade门面模式
    计算机毕业设计SSM电影网站系统设计【附源码数据库】
    每日力扣算法题(简单篇)
    OpenCV_Mat类对象的基本操作、常用操作及相关成员函数介绍
    2022杭电多校第三场题解
  • 原文地址:https://blog.csdn.net/qq_32682301/article/details/132657198
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号