开玩笑-无法使用动态导入模板字符串找到模块

时间:2019-05-13 13:03:28

标签: reactjs unit-testing webpack jestjs

好吧,我有一个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);

  });
});

我相信与动态导入有关吗?

2 个答案:

答案 0 :(得分:2)

在不删除模板文字的情况下也可以解决,方法是将Jest的--watch标志替换为--watchAll

答案 1 :(得分:0)

这是我修复它的方法,问题是Jest由于某种原因,在动态导入中使用模板文字时会抱怨。因此,只需使用普通的字符串连接即可解决此问题。

(async () => {
  // $FlowIgnore
  const icon = await import('@/assets/svg/icons/' + name + '.svg');
  setIconPath(icon.default);
})();