Jest: Ошибка "SyntaxError: Unexpected token <" при использовании require для SVG
Не уверен, куда обратиться по поводу этой ошибки.
Использую Typescript с React, а для юнит-тестирования — Jest и Enzyme.
Пример файла package.json:
"scripts": {
"start": "node server.js",
"bundle": "cross-env NODE_ENV=production webpack -p",
"test": "jest"
},
"jest": {
"transform": {
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"json"
]
}
При запуске команды npm test
возникает ошибка:
FAIL src/components/Component.test.tsx
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest)<?xml version="1.0" encoding="UTF-8"?>
^
SyntaxError: Unexpected token <
Редактирование: Похоже, это происходит в том месте, где я использую require
для загрузки статического файла .svg
. Почему он не может это обработать? Существует ли способ игнорировать эту ошибку при использовании require
?
4 ответ(ов)
Jest не использует Webpack, поэтому не знает, как загружать файлы с другими расширениями, кроме js/jsx. Чтобы добавить поддержку других расширений, вам нужно написать свои собственные трансформаторы. Один из трансформаторов — это трансформатор для TypeScript, который вы уже определили в вашей конфигурации в следующем фрагменте кода:
"transform": {
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
Теперь вам нужно добавить трансформатор для файлов SVG. Давайте расширим вашу конфигурацию Jest:
"transform": {
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js",
"^.+\\.svg$": "<rootDir>/svgTransform.js"
},
Также создайте файл svgTransform.js
в корневом каталоге вашего проекта со следующим содержимым:
module.exports = {
process() {
return { code: 'module.exports = {};'}; // базовый трансформатор, возвращающий постоянное значение
},
getCacheKey() {
// Выход всегда будет одинаковым.
return 'svgTransform';
},
};
Этот базовый трансформатор всегда возвращает одно и то же значение.
Ссылка на документацию: Jest Configuration - Transform.
Вы можете использовать пакет npm jest-transform-stub
для этого. В файл конфигурации Jest добавьте следующий преобразователь:
"transform": {
...
"^.+\\.svg$": "jest-transform-stub",
...
}
Такой же преобразователь можно использовать для любых файлов ресурсов. Например:
"transform": {
...
"^.+\\.(css|less|sass|scss|png|jpg|gif|ttf|woff|woff2|svg)$": "jest-transform-stub",
...
}
Это позволит Jest правильно обрабатывать указанные типы файлов во время тестирования.
Чтобы замокировать ваши SVG файлы в Jest, выполните следующие шаги:
- Создайте файл для моков SVG, например,
__mocks__/svgMock.js
, с содержимым, подобным приведенному ниже:
import React from "react";
export default "SvgURL";
export const ReactComponent = ({ width, height }) => (
<div>
w-{width} h-{height}
</div>
);
Этот файл будет использоваться для замены реальных SVG файлов в тестах.
- Укажите Jest, где искать этот мок, добавив соответствующее свойство в ваш
jest.config.js
:
moduleNameMapper: {
"\\.svg": "<rootDir>/__mocks__/svgMock.js",
},
Таким образом, когда Jest встретит импорт SVG файла, он будет использовать созданный вами мок вместо реального SVG, что упростит тестирование ваших компонентов.
Чтобы настроить обработку файлов SVG в Jest, вам нужно отредактировать файл jest.config.js
, который находится в корневом каталоге вашего проекта.
Добавьте следующую строку внутрь объекта transform
:
'^.+\\.svg$': './svgTransform.js'
Теперь ваш файл jest.config.js
должен выглядеть следующим образом:
module.exports = {
rootDir: '.',
testEnvironment: 'jsdom',
transform: {
'^.+\\.(j|t)sx?$': 'babel-jest',
'^.+\\.svg$': './svgTransform.js',
},
//...
}
После этого создайте файл с именем svgTransform.js
в корневом каталоге проекта и добавьте в него следующий код:
module.exports = {
process() {
return 'module.exports = {};'
},
getCacheKey() {
// Вывод всегда одинаковый.
return 'svgTransform'
},
}
Если вы запускаете тесты в режиме наблюдения (watch mode), убедитесь, что полностью остановили тестовый набор и перезапустили его.
Когда использовать JSX.Element, ReactNode и ReactElement?
Какой тип имеет проп 'children'?
Не удается использовать JSX, если не указан флаг '--jsx'
Разница между "require(x)" и "import x"
@Directive против @Component в Angular