Next.js | Jest + React testing library + Typescript 单元测试框架搭建及实现


highlight: atom-one-dark
theme: fancy

前言

单元测试和 E2E 测试作为前端项目健壮性的保障,虽然在许多团队可能并没有足够的能力和资源去实现很好的自动化测试,但基本的了解还是必不可少的。

最近在上手并集成单元测试到已有的 Next.js 项目中,网上的文档虽然很多,但实际使用的时候遇到的问题可谓五花八门,这篇文章可以帮助你快速的在 Next.js + TS 的环境中构建单元测试环境及进行单测的编写。

框架搭建

Jest 是目前最主流的前端测试框架,仅通过 Jest 没办法完成前端的所有单元测试,因为前端的单元测试涉及到 Dom 和事件的模拟。因此我们还需要一些测试辅助库来为我们模拟相关的场景。DOM Testing Library 适用于任何提供 DOM API 的环境,这个库提供了包含 ReactVue, Angular 这三个主流框架的 API,使用这些 API 我们可以在执行单测时实现 类似于用户在页面上查找元素 的方式查询 DOM 中的节点的操作,帮助我们实现更加符合真实环境的测试。

下面我们在已有的 Next.js 项目的基础上引入 JestReact testing library 以及相关的一些依赖,执行以下命令:

yarn add jest jest-environment-jsdom @testing-library/react @testing-library/jest-dom -D

接下来我们需要创建一下一下 Jest 的配置文件,在项目根目录下创建 jest.config.ts ,写入以下配置:

const nextJest = require('next/jest');

const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: './',
});

// Add any custom config to be passed to Jest
const customJestConfig = {
  // Add more setup options before each test is run
  // if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
  moduleDirectories: ['node_modules', '<rootDir>/'],
  testEnvironment: 'jest-environment-jsdom',
  testPathIgnorePatterns: ['<rootDir>/cypress/'],
  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },
};

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);

export {};

然后再创建 jest.setup.ts 文件,暂时先写入以下配置:

import '@testing-library/jest-dom/extend-expect';

这个配置文件是根据 Next.js 文档中提供的配置进行修改的,我们先看看文档中对于这段配置的描述:

在后台,next/jest 会自动为我们配置 Jest,包括以下步骤:

  • 使用 SWC 设置 transform
  • 自动 mock 样式(包括.css.module.css 和它们的 scss 变量)、图片 import 以及 @next/font
  • 加载.env(所有的环境变量)到process.env
  • 在解析及编译测试时忽略 node_modules 目录
  • 在解析测试时忽略 .next 目录
  • 加载next.config.js用于启用 SWC transform 的配置

而我单独加的配置有如下几个:

  • testPathIgnorePatterns: ['<rootDir>/cypress/']: 需要忽略的测试目录,这里我忽略了 cypres 目录,因为我们的 E2E 测试使用的是 Cypress ,如果不忽略的话,在执行 jest 的测试命令时会把 E2E 的测试也给跑起来。
  • setupFilesAfterEnv: ['<rootDir>/jest.setup.ts']:配置 Jest 的 setup 文件位置,Jest 的 setup 文件用于在 执行测试时先执行一些固定的初始化操作,例如执行一些 import 等操作,这样就不需要在每一个测试中单独引入某些依赖了。
  • moduleNameMapper: { '^@/(.*)$': '<rootDir>/src/$1', }:这一步是为了配置一下测试文件中 引入依赖时的别名,就像 webpack 或 vite 中 alias 配置的功能,当在引入依赖的目录中开头为 @ 时,会指向根目录下的 src 目录。
  • 在配置文件的最后有一个 export {} ,这一步是为了解决当 tsconfig.json 中的 isolatedModules 设置为 true 时,如果 ts 文件中不存在
    importexport 时,ts 认为这个文件不是一个 ES Module,而是一个全局脚本,导致编译时报错。

接下来我们在 package.json 中新增一个指令:

"scripts": {
  //...
  "test": "jest"
}

当我们执行例如 yarn test 时,Jest 会去识别我们目录中的所有测试文件并执行。此时如果我们执行运行测试,会打印如下错误:

Error: Jest: Failed to parse the TypeScript config file

这个错误的原因是我们的配置文件是由 Node.js 去直接执行的,而 Node.js 并不能直接执行 ts 文件,我们也没有将配置文件进行编译,所以我们需要安装一下 ts-node,执行以下命令进行安装:

yarn add ts-node -D

安装后再次执行 yarn test 就不会报错了,ts-node 的作用就是让 Node.js 可以直接运行 ts 脚本,在执行的过程中自动进行编译,不需要我们自己提前编译为 js 脚本,更多详情可以参考 ts-node 官网

测试 Demo 编写

在框架搭建完成后,我们来实现一个简单的 demo 上手一下,首先我们需要设计一下测试的文件要放在哪个目录,这里我是将组件的测试目录与组件放在同一个目录中的,例如我们有一个 返回上一级的按钮组件 Back ,它的目录为 src/components/Back/index.tsx,这里我们再创建一个 src/components/Back/__test__ 目录用于放置测试文件,然后我们在目录中创建 index.test.tsx 文件,写入以下代码:

import { render, screen } from '@testing-library/react';

import Back from '../index';

describe('Back', () => {
  it('should render with default text', () => {
    render(<Back />);

    const element = screen.getByText(/back/i);

    expect(element).toBeInTheDocument();
  });

  it('should render with right test', () => {
    render(<Back text="Back to home" />);

    const element = screen.getByText(/Back to home/i);

    expect(element).toBeInTheDocument();
  });
});

describe 用于定义一个 测试用例组it 则用于定义一个 单独的测试用例,这两个 API 是全局定义的,并不需要引入。

代码中我们创建了一个测试用例组,其中包含了两个测试,it 的第一个参数用于描述测试的作用,这里就简单测试下 默认情况传入参数的情况 下组件是否能正确渲染。render 用于渲染组件,screen 大家可以理解为测试环境的 document,可以用于获取渲染的 dom 节点,expect 则是用于检查值是否满足特定条件。

因此这里的测试流程也就是:

  1. 引入并渲染组件
  2. 根据某些条件获取 dom 节点
  3. 判断组件是否正确渲染

后续更复杂的测试大致也是根据这种测试思路进行延伸,关于 API 的具体作用请参考 React-testing-library 文档Jest API 文档

配置 Github Action

在我们的测试可以顺利执行后,我们可以实现一下单测的自动化,这里以 Github Action
为例,基础的实现还是非常简单的,首先创建一个新的 workfolw 配置文件 your_project/.github/workflows/frontend-unit.yml

然后写入以下配置:

name: CI
on: push
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Install modules
      run: yarn
    - name: Run tests
      run: yarn test

这个配置文件就是在 ubuntu 环境中执行 yarn test 开始测试,当然在实际的项目中肯定不止这么简单,但根据实际情况进行触发时机的修改或增加执行流程即可,当然你也可以增加测试覆盖率的打印等命令,这个会在后面我实践后单独出文章介绍。

总结

这篇文章介绍了下如何在 Next.js 搭建组件测试的环境以及最基本的测试实现,关于更多的踩坑以及一些最佳实践会在后续摸索后继续出文章,如果大家对于 E2E 测试想要了解也可以评论区留言,在 E2E 测试方面我们已经有了比较丰富的实践经验,可以期待下后续的文章。如果这篇文章对你有帮助欢迎点赞或关注

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容