Jest won't parse SVG pictures in NextJS application

Viewed 1473

When I run yarn test, I get the following message:

 Jest encountered an unexpected token

This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

Here's what you can do:
 • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
 • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
 • If you need a custom transformation specify a "transform" option in your config.
 • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html

Details:

/home/marouane/projects/manage-landing-page/jest.setup.ts:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import "@testing-library/jest-dom/extend-expect";
                                                                                         ^^^^^^

SyntaxError: Cannot use import statement outside a module

  at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1350:14)

I looked online, I found that I have to install the jest-svg-transformer, which I did.

I also added the required lines to the jest.config.js file:

module.exports = {
  setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
  transform: {
    '^.+\\.jsx?$': 'babel-jest',
    '^.+\\.svg$': 'jest-svg-transformer',
  },

};

And it still does not work. I tried all other solutions on the web but to no avail.

Any help would be greatly appreciated! Thank you!

edit:

Apparently, I should've typed tsx instead of jsx in the jest.config.js file, and that was all there is to it... Stupid error, I know... Oh well!!!

1 Answers

I had this issue. I think you should inline your files. In jest.config, I check for .svg and replace it with an inline string.

// jest.config.js
module.export = {
  transform: {
    '^.+\\.[tj]sx?$': 'babel-jest',
    '^.+\\.svg$': '<rootDir>/svgTransformer.js',
  }
}
// svgTransformer.js
module.exports = {
  process(src, filename) {
    const assetFilename = JSON.stringify(path.basename(filename));

    if (filename.match(/\.svg$/)) {
      // Based on how SVGR generates a component name:
      // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
      const pascalCaseFilename = pascalCase(path.parse(filename).name);
      const componentName = `Svg${pascalCaseFilename}`;
      return `const React = require('react');
      module.exports = {
        __esModule: true,
        default: ${assetFilename},
        ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
          return {
            $$typeof: Symbol.for('react.element'),
            type: 'svg',
            ref: ref,
            key: null,
            props: Object.assign({}, props, {
              children: ${assetFilename}
            })
          };
        }),
      };`;
    }

    return `module.exports = ${assetFilename};`;
  },
};
// pascal-case.ts
import { camelCase, toUpper } from 'lodash';

export const pascalCase = (str: string) => camelCase(str).replace(/^(.)/, toUpper);

Let me know if you have any questions.

Related