现有React项目接入jest+enzyme踩坑经历

279 阅读3分钟

背景

最近在做如何提升代码质量的事情,有个思路是通过增加单侧来减少bug量的方式,于是就在现有的项目中接入jest+enzyme来实现纯函数的单侧以及针对react组件的测试用例,本来感觉很简单的,但是在真实操作中还是遇到了好多坑,自己一步一步摸索出来终于搞定了,把踩坑经历分享出来供大家参考。

踩坑经历

项目信息

react@16.14.0+react-router@3.2.6+typescript@4.9.5

接入单测工具信息

jest@29.7.0+enzyme@3.11.0+enzyme-adapter-react-16@1.15.7

babel配置

首先需要配置babel信息来支持ts以及jsx,tsx文件编辑为js文件

在根目录创建babel.config.js文件,文件内容如下,@babel/preset-env包用来转换es6,@babel/preset-react用来转换react组件,@babel/preset-typescript用来转换ts

// babel.config.js
{
  "presets": [["@babel/preset-env"], ["@babel/preset-react"], "@babel/preset-typescript"]
}

纯函数测试

增加完jest+enzyme后就可以创建测试用例了,我直接用的jest默认配置,及创建__tests__文件夹来标识是单侧文件,找了一个纯函数来测试,执行成功,感觉有点太easy了,然而头疼的在后头呢

import { test, expect } from '@jest/globals';
import { getBpmStatusIconConfig } from '../helper';

test('测试demo', () => {
  expect(getBpmStatusIconConfig(1)).toEqual({
    class: '',
    iconType: 'more-circle-fill',
  });
});

react组件测试

然后就开始找简单的react组件做测试,首先想试用一下快照测试,然后就遇到了各种问题

mount函数支持报错

image.jpeg

问题原因:

需要利用浏览器能力渲染出来真实dom,然后在node环境是无法渲染的,这句需要借助于jsdom库来模拟生成

解决方案:

  1. 运行一下命令安装

    npm i -D jsdom jsdom-global
    

    注意:jsdom版本与react版本是有对应关系的,我使用的react@16.14.0,对应的jsom@11.12.0;我直接装最新版本的会报错,目前还没找到对应关系是啥,只是找到与react@16.14.0发布相似时间点的版本测试(灵感来源于使用react-test-renderer版本报错,查阅资料发现他是react包提供的功能,需要独立版本与react保持一致才行)

  2. 在入口文件setupFiles.js文件中通过 require('jsdom-global/register'); 加载,这样就可以在所有的单侧文件中有jsdom环境(推荐);还可以单文件引入该包

提示需要适配器

image.jpeg

问题原因:

jest中使用enzyme,需要增加enzyme-adapter-react-15适配器

解决方案:

  1. 新建入口文件setupFiles.js

    // setupFiles.js
    const { configure } = require('enzyme');
    const Adapter = require('enzyme-adapter-react-16');
    require('jsdom-global/register');
    
    configure({ adapter: new Adapter() });
    
  2. 在jest配置中指定入口文件

    // package.json文件
    "jest": {
        "setupFilesAfterEnv": [
          "<rootDir>/dev/test/setupFiles.js"
        ],
      }
    
无法识别scss文件

image.jpeg

问题原因:

scss样式文件无法识别

解决方案:

在jest配置(我使用的是在package.json中加jest配置,也可使用独立文件方式)中增加moduleNameMapper转换,记得添加对应的目录及文件(如:/dev/test/__mocks__/fileMock.js)

// package.json文件
"jest": {
    "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/dev/test/__mocks__/fileMock.js",
      "\\.(css|scss)$": "<rootDir>/dev/test/__mocks__/styleMock.js"
    }
  }

// fileMock.js 文件
module.exports = 'test-file-stub';


// styleMock.js文件
module.exports = {};
快照内容不是真实dom结构而是js对象

image.jpeg

import React from 'react';
import { mount } from 'enzyme';
import { describe, test, expect } from '@jest/globals';
import NoPermission from '../index';


describe('NoPermission组件单侧', () => {
  test('快照测试', () => {
    // const tree = renderer.create(<NoPermission description="页面存在错误" title="提示" />).toJSON();
    const tree = mount(<NoPermission description="页面存在错误" title="提示" />);
    expect(tree.render()).toMatchSnapshot();
  });
});

问题原因:

enzyme的mount需要通过enzyme-to-json来转成dom的json

解决方案:

  1. 安装enzyme-to-json包

  2. 在jest配置中增加配置

    // package.json
    "jest": {
        "snapshotSerializers": [
          "enzyme-to-json/serializer"
        ]
      }
    
组件中有加载三方包报错

image.jpeg

问题原因:

  1. node_modules中的包为esm,需要配置对应的babel配置,配置了.babelrl.json不生效

  2. 部分包存在编辑的问题(老的业务自定义的包,还不确定为什么提示加载报错)

babel配置内容只针对业务代码有效,不对node_modules文件有有效,如一些包需要在业务代码中编译

参考文章: juejin.cn/post/703262…

解决方案:

  1. .babelrl.json对jest不起作用改为使用babel.config.js就可以了

  2. 设置jest配置在运行时实时做编辑

    // package.json 
    {
    	"jest":{
      	"transformIgnorePatterns": [
          "<rootDir>/node_modules/(?!(@common/utils)/)"
        ]
      }
    }