好吧,我有一个设置Webpack和Jest用于测试React的设置,还使用我的项目目录的" src/app",我使用"@"符号使用webpack的别名,我还知道它必须使用" Modulenamapper"属性将其映射到Jest.config中,以与该别名正确对齐。
问题在于有一个<Icon />
组件,该组件使用ES Dynamic Import动态导入.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;
及其测试ofcourse
// @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);
});
});
我相信与动态导入有关?
这是我修复的方式,问题是出于某种原因,它在使用动态导入中使用模板文字时抱怨。因此,要修复它,只需使用普通字符串串联即可。
(async () => {
// $FlowIgnore
const icon = await import('@/assets/svg/icons/' + name + '.svg');
setIconPath(icon.default);
})();
也可以通过用--watchAll
--watch
标志而在不删除模板文字的情况下解决此问题。