好吧,我有一个Webpack和Jest的安装程序,用于测试反应,也使用Webpack的别名,并在项目目录“ src / app”中使用“ @”符号,我也知道它也必须映射到jest中.config使用“ moduleNameMapper”属性正确地与该别名对齐。
问题在于,有一个<Icon />
组件可以使用ES动态导入来动态导入.svg图标。
这是jest.config.js映射的正则表达式
'^ @ /':'/ src / app / $ 1'
但仅在测试时会破坏
一切正常,除了测试时
我的文件夹结构如下:
config/
webpack-config/
src/
app/
assets/
img/
some images
svg/
icons/
cart.svg
components/
base/
core/
shared/
...
client/
...
server/
...
这是我正在使用的Webpack别名:
module.exports = {
extensions: ['.js', '.mjs', '.json', '.jsx', '.css'],
modules: paths.resolveModules,
alias: {
'@': paths.srcApp, // that just point
}
};
这是我的jest.config文件:
const paths = require('./config/paths');
module.exports = {
verbose: true,
collectCoverageFrom: ['src/**/*.{js,jsx,mjs}'],
setupFiles: [
'<rootDir>/node_modules/regenerator-runtime/runtime',
'<rootDir>/config/polyfills.js',
],
// A list of paths to modules that run some code to configure or set up the testing framework before each test.
setupFilesAfterEnv: ['<rootDir>config/jest/setup.js'],
testMatch: [
'<rootDir>/src/**/__tests__/**/*.{js,jsx,mjs}',
'<rootDir>/src/**/?(*.)(spec|test).{js,jsx,mjs}',
],
testEnvironment: 'node',
testURL: 'http://localhost',
modulePaths: ['src'],
moduleNameMapper: {
'^@[/](.+)': '<rootDir>/src/app/$1',
},
transform: {
'^.+\\.(js|jsx|mjs)$': '<rootDir>/node_modules/babel-jest',
'^.+\\.css$': '<rootDir>/config/jest/cssTransform.js',
'^(?!.*\\.(js|jsx|mjs|css|json|svg)$)': '<rootDir>/config/jest/fileTransform.js',
},
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$'],
moduleDirectories: paths.resolveModules,
moduleFileExtensions: ['js', 'json', 'jsx', 'node', 'mjs'],
};
这是我正在测试的组件
// @flow strict
import React, { useState } from 'react';
import './Icon.scss';
type PropsType = {
name: string,
selected?: string,
size: number | string
};
const Icon = ({ name, size }: PropsType) => {
const [iconPath, setIconPath] = useState('');
(async () => {
const icon = await import(`@/assets/svg/icons/${name}.svg`);
setIconPath(icon.default);
})();
return (
<img
alt={`icon ${name}`}
className="icon"
style={{
height: `${size}px`,
width: `${size}px`,
}}
src={iconPath}
/>
);
};
Icon.defaultProps = {
size: 16,
};
export default Icon;
这是测试
// @flow strict
import React from 'react';
import {
render,
} from 'react-testing-library';
import Icon from './Icon';
describe('Icon', () => {
it('should have "name" with the path of the icon', () => {
const { container } = render(<Icon name="cart" />);
});
});
这是输出
Configuration error:
Could not locate module @/assets/svg/icons/${name}.svg mapped as:
/Users/jero/Documents/my-shit/react-shop/src/app/assets/svg/icons/${name}.svg.
Please check your configuration for these entries:
{
"moduleNameMapper": {
"/^@[\/](.+)/": "/Users/jero/Documents/my-shit/react-shop/src/app/$1"
},
"resolver": null
}
有趣的是,当我将此正则表达式用于jest.config
moduleNameMapper: {
'/^@\/(.*)$/': '<rootDir>/src/app$1'
}
该错误消失了,但是当测试时一个组件导入其他组件时,该错误会中断:
FAIL src/app/components/shared/ImgLoader/ImgLoader.test.js
● Test suite failed to run
Cannot find module '@/components/base/Spinner/Spinner' from 'ImgLoader.js'
However, Jest was able to find:
'./ImgLoader.js'
'./ImgLoader.scss'
'./ImgLoader.test.js'
You might want to include a file extension in your import, or update your 'moduleFileExtensions', which is currently ['js', 'json', 'jsx', 'node', 'mjs'].
See https://jestjs.io/docs/en/configuration#modulefileextensions-array-string
2 | import React, { useState } from 'react';
3 |
> 4 | import Spinner from '@/components/base/Spinner/Spinner';
| ^
5 |
6 | import './ImgLoader.scss';
7 |
at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:230:17)
at Object.<anonymous> (src/app/components/shared/ImgLoader/ImgLoader.js:4:1)
这是<ImageLoader />
// @flow strict
import React, { useState } from 'react';
import Spinner from '@/components/base/Spinner/Spinner';
import './ImgLoader.scss';
type PropsType = {
src: string
};
function ImgLoader({ src }: PropsType) {
const [imgObj, setImg] = useState({ img: null, isLoading: true });
const image = new Image();
image.onload = () => setImg({ img: image.src, isLoading: false });
image.src = src;
return (
imgObj.isLoading ? (<Spinner />) : (<img className="imgLoader img-fluid" src={imgObj.img} alt="img" />)
);
}
export default ImgLoader;
及其测试路线
// @flow strict
import React from 'react';
import {
render,
} from 'react-testing-library';
import ImgLoader from './ImgLoader';
describe('ImgLoader', () => {
it('tests \'src\'', () => {
const src = 'https://static.street-beat.ru/upload/resize_cache/iblock/d69/450_450_1/d699afc7b3428f2f51c2f2de6665b506.jpg';
const { container } = render(<ImgLoader src={src} />);
console.log('container', container);
});
});
我相信与动态导入有关吗?
答案 0 :(得分:2)
在不删除模板文字的情况下也可以解决,方法是将Jest的--watch
标志替换为--watchAll
答案 1 :(得分:0)
这是我修复它的方法,问题是Jest由于某种原因,在动态导入中使用模板文字时会抱怨。因此,只需使用普通的字符串连接即可解决此问题。
(async () => {
// $FlowIgnore
const icon = await import('@/assets/svg/icons/' + name + '.svg');
setIconPath(icon.default);
})();