Importing images breaks jest test

ReactjsTestingWebpackJestjs

Reactjs Problem Overview


In React components importing assets (ex, import logo from "../../../assets/img/logo.png) gives such error

> ({"Object.":function(module,exports,require,__dirname,__filename,global,jest){�PNG
SyntaxError: Invalid or unexpected token at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:305:17)

my jest config is

"jest": {
"testRegex": ".*\\.spec\\.js$",
"moduleFileExtensions": [
  "js",
  "jsx",
  "json"
],
"moduleDirectories": [
  "node_modules",
  "src",
  "assets"
],
"moduleNameMapper": {
  "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$/": "<rootDir>/__mocks__/fileMock.js",
  "\\.(css|less|scss)$": "<rootDir>/__mocks__/styleMock.js"
},
"verbose": true,
"bail": true
}

what am i missing?

Reactjs Solutions


Solution 1 - Reactjs

When you import image files, Jest tries to interpret the binary codes of the images as .js, hence runs into errors.

The only way out is to mock a default response anytime jest sees an image import!

How do we do this?
  • first you tell Jest to run the mock file each time an image import is encountered. you do this by adding the key below to your package.json file
"jest": {
 "moduleNameMapper": {
      "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/mocks/fileMock.js",
      "\\.(css|less)$": "<rootDir>/mocks/fileMock.js"
    }
}

Note: if you already have the "Jest" key, just add the "moduleNameMapper" child in it

  • lastly, create a mocks folder in your root and create fileMock.js file inside it. populate the file with the snippet below
module.exports = ''; 

Note: If you are using es6 you can use export default ''; to avoid an Eslint flag

when you are done with the above steps, you can restart the test and you are good to go.

Note. remember to add the varying extensions of your image files in the moduleNameMapper so that they can be mocked.

I hope I have been able to help. #cheers!

Solution 2 - Reactjs

For anyone looking into this problem. You have to do install npm install --save-dev identity-obj-proxy to get the necessary dependencies.

"jest": {
    "moduleNameMapper": {
      ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "identity-obj-proxy"
    }
  }

Solution 3 - Reactjs

I had the same problem and I solved it as follows:

  1. npm install -D jest-transform-stub
  2. Then, in package.json, I added the following transformation:


"jest": {
...
"transform": {
...
".+\.(css|scss|png|jpg|svg)$": "jest-transform-stub"

Solution 4 - Reactjs

If you want to use jest with webpack, you need to explicitly configure it as so. Take a look at this guide here: https://jestjs.io/docs/webpack

Solution 5 - Reactjs

I had this same issue! I'm not sure if it's the same case as in the original question, but for me jest was still somehow trying to load the images as JS and trying to parse them while I had the files matching image extensions mapped to a mock in moduleNameMapper. My file also included some code to map the @ character to the root src directory, since I had webpack and this was configured as a webpack alias in the project (and in TS). The full moduleNameMapper entry in jest.config.js looked like this for me:

    moduleNameMapper: {
        '^@$': '<rootDir>/src',
        '^@/(.*)':
            '<rootDir>/src/$1',
        '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
            '<rootDir>/__mocks__/fileMock.js',
        // '\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
        '.*\\.(css|less)$': 'identity-obj-proxy',
    }

For me it turned out that when I was importing the images in my components, the path was something like: '@/assets/someImage.jpg'. However, it seems this would match the first regex first, the one covering the @ alias: ^@/(.*). Thus, it was being mapped to <rootDir>/src/$1 instead of the <rootDir>/__mocks__/fileMock.js.

I fixed it by making the alias only match non-images:

    moduleNameMapper: {
        '^@$': '<rootDir>/src',
        '^@/(.*)\\.(?!jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
            '<rootDir>/src/$1',
        '.*\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
            '<rootDir>/__mocks__/fileMock.js',
        // '\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
        '.*\\.(css|less)$': 'identity-obj-proxy',
    }

Solution 6 - Reactjs

In case of IOS image names with @

moduleNameMapper: {
    "^image![a-zA-Z0-9$_-]+$": "GlobalImageStub",
    "^[@./a-zA-Z0-9$_-]+\\.(png|gif)$": "RelativeImageStub"
  }

Solution 7 - Reactjs

For those who use Vue test util in Nuxt 2 and are faced with question or this problem ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){ SyntaxError: Invalid or unexpected token

make a file with the name of fileTransformer.js in the test/unit directory, and then add these codes:

const path = require('path')

module.exports = {
  process(src, filename, config, options) {
    return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';'
  },
}

and then add these codes to jest.config.js file:

  transform: {
    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
    '<rootDir>/test/unit/fileTransformer.js',
    // ... other configs
  },

Solution 8 - Reactjs

Adding bellow line into jest.config.js file helped me to test pass,

"\\.(jpg|jpeg|png)$": "identity-obj-proxy",

Example:

 moduleNameMapper: {
    "\\.(css)$": "identity-obj-proxy",
    "\\.(jpg|jpeg|png)$": "identity-obj-proxy",
  },

Solution 9 - Reactjs

In React Native we use preset: 'react-native'

https://github.com/facebook/react-native/blob/main/jest-preset.js

Or add transform into jest.config.js

  transform: {
    '^.+\\.(js|ts|tsx)$': 'babel-jest',
    '^.+\\.(bmp|gif|jpg|jpeg|mp4|png|psd|svg|webp)$': require.resolve(
      '../node_modules/react-native/jest/assetFileTransformer.js',
    ),
  },

If you do not use React Native, need to create a file https://github.com/facebook/react-native/blob/main/jest/assetFileTransformer.js into your project and changes path into require.resolve

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAni AlaverdyanView Question on Stackoverflow
Solution 1 - ReactjsAdépòjù OlúwáségunView Answer on Stackoverflow
Solution 2 - ReactjsLucas ProcopioView Answer on Stackoverflow
Solution 3 - Reactjswww.admiraalit.nlView Answer on Stackoverflow
Solution 4 - ReactjskngrooView Answer on Stackoverflow
Solution 5 - ReactjsJapser36View Answer on Stackoverflow
Solution 6 - ReactjsBogdan UstyakView Answer on Stackoverflow
Solution 7 - ReactjsMohammadView Answer on Stackoverflow
Solution 8 - ReactjskandaView Answer on Stackoverflow
Solution 9 - ReactjsVasyl NahuliakView Answer on Stackoverflow