Jest - не удалось найти модуль с динамической строкой шаблона импорта - PullRequest
0 голосов
/ 13 мая 2019

у меня есть настройка с Webpack и Jest для тестирования реакции, а также с использованием псевдонимов Webpack с использованием знака "@" для каталога моего проекта, который называется "src / app", я также знаю, что он должен быть сопоставлен с jest .config, используя свойство moduleNameMapper для правильного выравнивания с этим псевдонимом.

проблема в том, что есть компонент <Icon />, который интернирует динамически импортирует значки .svg, используя динамический импорт ES.

это регулярное выражение для этого отображения для 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);

  });
});

Я полагаю, что-то связано с динамическим импортом?

1 Ответ

0 голосов
/ 17 мая 2019

вот как я это исправил, проблема в том, что Jest почему-то жалуется при использовании литералов шаблона внутри динамического импорта.так что чтобы исправить это просто используйте обычную конкатенацию строк и все.

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