I am developing a React APP using the development environment Vite. Since Vite is well supported I included several plugins that work pretty well with it, particularly one that give me the opportunity for creating components directly importing an *.svg in a particular format. It is called vite-plugin-svgr
and you can create a component in the following way just including ?react
at the end:
import Lock from '../assets/icons/lock.svg?react'
Once I did that I then started to develop some tests with Jest and testing-library/react and it looks like the method "render" from testing-library/react does not like how the components are created using the plugin.
Basically it throws the following error: `console.error Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `Widget`.
at repositoryData (/Users/joscormir/Dev/dashboard_project/src/components/Widget.jsx:13:26)
at section
at Dashboard (/Users/joscormir/Dev/dashboard_project/src/components/Dashboard.jsx:9:61)
24 | {repositoryData.organization.login}/{repositoryData.name}
25 | </a>
> 26 | {repositoryData.private ? <Lock /> : <UnLock />}
| ^
27 | </header>
28 |
29 | <div className={styles.widget__body}>`
Take into account <UnLock />
is a component created in the way explained before as:
import UnLock from '../assets/icons/unlock.svg?react'
and Widget.jsx
is the component that includes the <UnLock />
component.
It is clearly having troubles rendering that component.
Since this is pretty straight forward I thought about using a Jest plugin called jest-transformer-svg
import React from 'react';
import MySvg from '../images/an-image.svg';
function MyComponent() {
return (
<div>
<MySvg style={{ color: 'blue' }} />
</div>
);
}
Then since the extension of my files are a little bit different I tried to use Jest transform the extension\*.svg?react
to meet the requirements of the example above including the following sentence in myjest.config.js\
file.
'^.+\\.(svg\\?react)$': 'jest-transformer-svg'
But it did not work. The whole Test suit fails to work since it says now it cannot find the module declare with the *.svg\?react
extensions what means the jest-transformer-svg
is not quite working from my understanding
I found a way to make this work. It works like a charm and I found it reading the issues in the vite-plugin-svgr. The key point here is to substitute the .svg?react
extension for .svg
. This is possible modifying the way we include in vite.config.js
the call of the plugin.
We need to modify it in the following way:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import svgr from 'vite-plugin-svgr'
export default defineConfig({
plugins: [react(), svgr({ include: '**/*.svg' })],
})
The key is the way we include the svg files, with this modification we can change how we were importing components from using UnLock from '../assets/icons/unlock.svg?react'
to use UnLock from '../assets/icons/unlock.svg'
With this modification we can now properly use jest-transformer-svg
since it will interpret correctly the .svg
files including in jest.config.js
file the transform rule telling the jest transformer to transform all the files with that extensions '^.+\\.svg$': 'jest-transformer-svg'
:
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/tests/setupTests.js'],
testMatch: ['<rootDir>/tests/**/*.(test).(js|jsx)'],
testPathIgnorePatterns: ['<rootDir>/tests/e2e/'],
transform: {
'^.+\\.(js|jsx|ts|tsx)$': [
'@swc/jest',
{
sourceMaps: true,
jsc: {
parser: {
syntax: 'ecmascript',
jsx: true,
},
transform: {
react: {
runtime: 'automatic',
},
},
},
},
],
'^.+\\.svg$': 'jest-transformer-svg',
},
moduleNameMapper: {
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'jest-transform-stub',
},
}
The above is my configuration files shared just in order to clarify where the transform rule must be placed, everything else could change depending on your own jest configuration.