在项目中遇到的一些问题
1、执行 pnpm test 报错
原因:当引入外部库是es模块时,?jest无法处理导致报错,可以通过 babel-jest 进行处理,根据官方文档:jestjs.io/zh-Hans/doc…,还有一种就是修改jest.config.js 加入preset: 'ts-jest' ,会让部分测试成功但是还是会存在一些问题。
方案一:采用了 babel-jest 进行处理
pnpm add -D babel-jest @babel/core @babel/preset-env
安装完以后在工程的根目录下创建一个babel.config.js
module.exports = {
presets: [['@babel/preset-env', {targets: {node: 'current'}}]],
};
修改jest.config.js,增加transform
transform: {
"^.+\\.js$": "babel-jest",
"^.+\\.(ts|tsx)$": "ts-jest",
},
方案二:仍然采用 ts-jest ,把引起报错文件的后缀,如 js 改为 ts 即可
2、ts-jest和jest版本未对应
报如下错误:
升级后版本(仅供参考)
3、toBeInTheDocument、toHaveClass等报错
类型检查错误,应该是@testing-library/jest-dom类型没被引入导致的
有以下两种方案,都需要修改tsconfig.json
// 方案一,删除typeRoots
"typeRoots": ["node", "node_modules/@types", "./typings"]
// 方案二,添加types
"types": ["@testing-library/jest-dom"]
4、Cannot find namespace 'NodeJS’
修改 tsconfig.json ,往 types 中加入 node
"types": ["node", "@testing-library/jest-dom"]
5、module 'tslib' cannot be found
报错信息如下:
原因是在 tsconfig.json 中开启了如下配置:
"importHelpers": true,
解决方案如下:
方案一:
"importHelpers": false,
方案二:
pnpm add tslib
并且修改 tsconfig
"paths": {
"tslib" : ["./node_modules/tslib/tslib.d.ts"] //在paths下添加tslib路径
}
6、由于单测的运行环境问题,当遇到某些方法没有的时候尝试mock下
例如:
解决方案如下:
(global as any).document.createRange = () => ({
selectNodeContents: jest.fn(),
getBoundingClientRect: jest.fn(() => ({
width: 500,
})),
});
7、多个单测文件缺失某一个方法,可以采用如下配置
例如:多个单测文件有如下报错:
那么首先在 jest.comfig.js 中添加配置:
module.exports = {
setupFilesAfterEnv: ['./setupTests.ts'],
// ...
}
然后在 setupTests.ts 文件中:
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
8、The error below may be caused by using the wrong test environment;Consider using the "jsdom" test environment
依赖版本:
"ts-jest": "^28.0.8",
"jest": "^28.1.2",
解决方法: 在 jest.config.js 中添加配置
module.exports = {
verbose: true,
testEnvironment: 'jsdom',
// ...
}
并安装 jest-environment-jsdom (注意: 仅 jest 28 及更高版本需要安装此依赖项)
{
"devDependencies": {
"jest-environment-jsdom": "^28.1.2",
}
}
9、Echarts 单元测试 canvas 报错
在写 Echarts 单元测试的时候,会有 canvas 报错。原因很明显,Echarts 依赖了 canvas。
解决办法:使用 jest-canvas-mock,参考:Error: Not implemented: HTMLCanvasElement.prototype.getContext
注意:直接引入 canvas 虽然可以解决单元测试的报错,但是会导致安装依赖会有偶发性 canvas 报错。
10、引入了第三方的组件CodeMirrorEditor写单测报错
在对该组件进行单测时,由于引入了第三方的组件 CodeMirrorEditor ,编译时出现了以下问题,原因是试图导入 jest 无法解析的文件,而从实际上来说我们对当前组件的测试其实并不用去编译 dt-react-codemirror-editor。
因此,在 jest.config.js 文件加入编译时需要忽略的文件。
再次运行测试,然而。。。。。。
好吧,又失败了进入 index 查看,提示找不到 style 文件但是文件夹里又是存在的,初步尝试是否由于文件扩展名起,保存测试通过,但是修改 node_modules 里的文件扩展名无法从根本解决该问题,按照推荐提示在测试覆盖文件扩展名 moduleFileExtensions 内加入 css。
再次尝试,然而。。。。。。jest 去编译了 style.css 文件,然后它无法解析失败了,查看配置。
发现已经配置了当匹配到 css 文件时映射到一个空对象里,并不会去编译原样式文件,原因是由于加入到了编译覆盖的文件扩展名数组里 moduleFileExtensions,因此无法采用推荐方法。
再次回顾问题产生的原因,jest 无法找到 style 文件但是找到了 style.css 文件,但是 style 文件我们并不需要进行编译,加入 moduleNameMapper 当找到 style 文件时映射到一个空对象的文件里。
11、Route && Link
在测试面包屑组件BreadCrumb时,因为面包屑组件中只用了 Link 标签,最终会被转成 a 标签,用来路由导航。如下写法是将 Link 和 route 放在一个组件之中。然后报错:Invariant Violation: <Link>s rendered outside of a router context cannot navigate。
import React from 'react'
import BreadCrumb from '../index';
import { render, fireEvent } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect';
import { Router, Switch, Route } from 'react-router-dom';
import { createMemoryHistory } from 'history'
const testProps = {
breadcrumbNameMap: [
{
name: 'home',
path: '/home'
},
{
name: 'home/about',
path: '/home/about'
}
],
style: {
backgroundColor: '#dedede'
}
}
const Home = () => <h1>home</h1>
const About = () => <h1>about</h1>
const App = () => {
const history = createMemoryHistory();
return (
<>
<Router history={history}>
{< BreadCrumb {...testProps} />}
<Switch>
<Route exact path="/main" component={Home} />
<Route path="/main/home" component={About} />
</Switch>
</Router>
</>
)
}
describe('test breadcrumb', () => {
test('should navigate to home when click ', () => {
const { container, getByTestId } = render(<App />);
expect(container.innerHTML).toMatch('about')
fireEvent.click(getByTestId('/home-link'))
expect(container.innerHTML).toMatch('home')
})
})
主要原因是版本原因:3.0版本路由不支持这种写法。3.0是将react-router 和react-router-dom分开的;而4.0路由将其合并成了一个包,在具体使用时应该基于不同的平台要使用不同的绑定库。例如在浏览器中使用 react router,就安装 react-router-dom 库;在 React Native 中使用 React router 就应该安装 react-router-native 库,但是我们不会安装 react-router了。项目中用的是3.0版本路由,于是改为3.0写法,将link和router分开写在两个组件中,通过测试。
const testProps = {
breadcrumbNameMap: [
{
name: 'home',
path: '/home'
},
{
name: 'about',
path: '/about'
}
],
style: {
backgroundColor: '#dedede'
}
}
const App = (props) => {
return (
<div>
{<BreadCrumb {...testProps} />}
{props.children}
</div>
)
}
const About = () => <h1>about page</h1>
const Home = () => <h1>home</h1>
describe('test breadcrumb', () => {
afterEach(() => {
cleanup();
})
test('should navigate to home router when click ', () => {
const history = createMemoryHistory()
const { container, getByTestId } = render(
<Router history={history}>
<Route path="/" component={App}>
<IndexRoute component={About} />
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
</Route>
</Router>
);
expect(container.innerHTML).toMatch('about')
fireEvent.click(getByTestId('/home-link'))
expect(container.innerHTML).toMatch('home')
})
})
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理