gilbarbara / react-inlinesvg

An SVG loader component for ReactJS

Home Page:https://codesandbox.io/s/github/gilbarbara/react-inlinesvg/tree/main/demo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Could not convert the src to a React element

imjakechapman opened this issue · comments

We're using react-inlinesvg and we have no issues with it in our project.
This issue arises when running jest. We have a wrapper SVG component that just passes the source to react-inlinesvg and this component causes all tests that include an SVG component.

We're using react-testing-library.

jest-config:

module.exports = {
  testEnvironment: "jsdom",
  setupFilesAfterEnv: ["<rootDir>/client/setupTests.ts"],
  roots: ["client/views"],
  transform: {
    "^.+\\.jsx?$": "babel-jest",
    "^.+\\.(tsx|ts)?$": "ts-jest",
    ".scss$": "<rootDir>/node_modules/jest-css-modules-transform",
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/fileTransformer.ts"
  },
  globals: {
    "ts-jest": {
      tsConfig: "<rootDir>/client/tsconfig.json",
    },
  },
  transformIgnorePatterns: ["/node_modules/(?!(lodash-es|react)/)"],
  testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
  moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
  moduleNameMapper: {
    ".+\\.(svg|png|jpg|scss)$": "identity-obj-proxy",
  },
  moduleDirectories: ["node_modules", "client"],
  collectCoverage: false,
  collectCoverageFrom: ["client/**/*.ts?(x)", "client/**/*.js?(x)"],
  coverageDirectory: "./coverage",
  coverageReporters: ["json", "lcov", "text"],
  snapshotSerializers: ["enzyme-to-json/serializer"],
};

The test error itself:

 console.error node_modules/react-inlinesvg/lib/index.js:91
      Error [InlineSVGError]: Could not convert the src to a React element
          at new InlineSVGError (/Users/jakechapman/[redacted]/[redacted]/node_modules/react-inlinesvg/src/helpers.ts:23:5
          at InlineSVG.Object.<anonymous>.InlineSVG.getElement (/Users/jakechapman/[redacted]/[redacted]/node_modules/react-inlinesvg/src/index.tsx:248:24)
          at callCallback (/Users/jakechapman/[redacted]/[redacted]/node_modules/react-dom/cjs/react-dom.development.js:13829:12)

I've boiled this down to something happening in the getElement() method.

Not sure if you could help pinpoint a cause or possible come up with a fix or lead me down the path for possibly opening up a pull request to fix this.

Hey,

I've never used identity-obj-proxy but perhaps it doesn't provide the response this package needs.

You could add a react-inlinesvg.js to your test's __mocks__ directory:

import React from 'react';

export default ({ src }) => <svg id={src} />;

Reading about identity-obj-proxy, it is only recommended to be used as a proxy with CSS modules.

But the src prop for this package needs to be a string.

@gilbarbara This definitely fixed the errors. Holy moley that was a run around trying to figure out what was causing this. Absolutely glorious. Thanks for the push in the right direction. Definitely appreciate it.

Hi there, I'm having kind the same problem.
Here is my jest config:

module.exports = {
  clearMocks: true,
  collectCoverageFrom: ['src/**/*.{ts,tsx,js,jsx}'],
  coverageDirectory: 'coverage',
  coveragePathIgnorePatterns: [
    '/node_modules/',
    'src/index.tsx',
    'src/temp/',
    'src/types/',
    'src/helpers/testHelper.ts',
    'src/helpers/constants.ts',
    'src/pages/Errors/*',
  ],
  coverageThreshold: {
    global: {
      branches: 90,
      functions: 90,
      lines: 90,
      statements: 90,
    },
  },
  moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx'],
  moduleNameMapper: {
    '\\.(css|scss|sass)$': 'identity-obj-proxy',
    '\\.svg$': '<rootDir>/__mocks__/genericMock.js',
    '^@src/(.*)$': '<rootDir>/src/$1',
    '^@helpers/(.*)$': '<rootDir>/src/helpers/$1',
    '^@appConfig(.*)$': '<rootDir>/config/application/appConfigTypes.ts',
  },
  preset: 'ts-jest',
  setupFilesAfterEnv: ['./src/helpers/jestHelper.ts'],
  testEnvironment: 'jsdom',
  testMatch: ['**/*.(test|spec).(ts|tsx)'],
  transform: {
    '^.+\\.(ts|tsx)$': 'ts-jest',
  },
  transformIgnorePatterns: ['node_modules/(?!(react-native|[omitted]|lodash)/)'],

I've tried to add a react-inlinesvg.js to test's mocks directory
but I'm getting a

    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:
     • 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:

    /[omitted]/__mocks__/react-inlinesvg.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import React from 'react';
                                                                                             ^^^^^^

    SyntaxError: Cannot use import statement outside a module

I solve it going into babeljs and converting the code to vanila js.

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _react = _interopRequireDefault(require("react"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var _default = ({
  src
}) => /*#__PURE__*/_react.default.createElement("svg", {
  id: src
});

exports.default = _default;

hey @wviana

I think you were using the module syntax (import/export) in your mock with the js extension and apparently jest isn't transforming js files, just ts.

Replace the mock extension to tsx?

Worked like a charm. Just had to add a porps interface and a return type.

Here is the code for react-inlinesvg.tsx

import React from 'react';

interface Props {
  src: string;
}

const InlineSvgMock = ({ src }: Props): React.ReactElement => <svg id={src} />;

export default InlineSvgMock;

Thanks @wviana! This helped us out a lot! Haha.

We're using Typescript and also adding a title element within the svg worked well for us. Thank you!

import React from 'react';

const InlineSvgMock = ({
  title,
  ...props
}: {
  className: string;
  src: string;
  title: string;
}) => <svg {...props}>{title ? <title>{title}</title> : null}</svg>;

export default InlineSvgMock;