Enzyme: An InvalidCharacterError when mounting a component using an svg

Created on 28 Jan 2019  路  15Comments  路  Source: enzymejs/enzyme

I have a component which uses the following svg file:

delete.svg

<svg xmlns="http://www.w3.org/2000/svg" width="28" height="32" viewBox="0 0 28 32">
    <path fill="#95A6B8" fill-rule="evenodd" ... />
</svg>

MyComponent.js

import DeleteIcon from "./delete.svg";
import style from "./MyComponent.scss";

class MyComponent extends Component {
  removeItemFromList(item, event) {
      //...
  }

  render() {
      return <div>
              <DeleteIcon
                className={style.removeButton}
                onClick={this.removeItemFromList.bind(this, item)}
              />
      <div>
}
export default MyComponent;

MyComponent.test.js

  describe("editable", function() {
    let componentWrapper;

    beforeEach(() => {
      componentWrapper = mount(
        <MyComponent
          data={[]}
        />
      );
    });

    afterEach(() => {
      componentWrapper.unmount();
    });

    it("testing something...", () => {
      expect(componentWrapper.exists(".someClass")).toEqual(true);
    });

  })

Current behavior

When mounting, I get the following InvalidCharacterError error:

InvalidCharacterError: "" did not match the Name production: Unexpected syntax in top
Line 1:

^^^
    at exports.name (/node_modules/jsdom/lib/jsdom/living/helpers/validate-names.js:11:11)
    at DocumentImpl.createElement (/node_modules/jsdom/lib/jsdom/living/nodes/Document-impl.js:688:5)
    at Document.createElement (/node_modules/jsdom/lib/jsdom/living/generated/Document.js:134:45)
    at createElement (/node_modules/react-dom/cjs/react-dom.development.js:7630:34)
    at createInstance (/node_modules/react-dom/cjs/react-dom.development.js:8714:20)  

Expected behavior

Mounting is successful.
Using shallow this error isn't thrown.

Your environment

API

  • [x] shallow
  • [x] mount
  • [ ] render

Version

| library | version
| ------------------- | -------
| enzyme | 3.8.0
| react | 16.7.0
| jest | 23.6.0

Adapter

  • [x] enzyme-adapter-react-16
  • [ ] enzyme-adapter-react-16.3
  • [ ] enzyme-adapter-react-16.2
  • [ ] enzyme-adapter-react-16.1
  • [ ] enzyme-adapter-react-15
  • [ ] enzyme-adapter-react-15.4
  • [ ] enzyme-adapter-react-14
  • [ ] enzyme-adapter-react-13
  • [ ] enzyme-adapter-react-helper
  • [ ] others ( )

I've seen issue #1510 but it's really the same error...

mount Need More Information Need To Reproduce

Most helpful comment

OK, I managed to solve it using a babel plugin:babel-plugin-inline-react-svg
Thanks for the help!

All 15 comments

Does this mount fine in normal React, in the browser? What babel transform are you using that allows you to import svgs?

Does this mount fine in normal React, in the browser? What babel transform are you using that allows you to import svgs?

I do manage to mount simpler components, yes (or if replacing my svg with, say, a span...)
My project's configurations:

As for you question, I have this in my webpack.config.js:

            {
                test: /\.svg$/,
                use: [
                    {
                        loader: "babel-loader"
                    },
                    {
                        loader: "react-svg-loader",
                        options: {
                            jsx: true
                        }
                    }
                ]
            },

And using:
"react-svg-loader": "^2.1.0",

Apparently I am having a similar issue too. I tried to use mount for one of the tests in our component library & the same error popped up. We are using rollup to compile the components. Here's our .babelrc if that matters:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "browsers": [
            "last 2 versions",
            "ie >= 10"
          ]
        }
      }
    ],
    "@babel/preset-react"
  ],
  "plugins": [
    "styled-jsx/babel"
  ]
}

We are also using storybook.

Let me know if I can provide you with anything else to get to the root of what's happening.

react-svg-loader will only work in webpack - you need to have a way for it to work in node.

You may want to try using https://www.npmjs.com/package/babel-plugin-inline-react-svg for non-browser builds.

Also, I failed to mention in my case, I am not importing any svgs. It's failing on a simple component mount with that same error.

Hi @hagayl does your test works without svg? If you could make a minimal repo to reproduce the issue that would be great :)

@ankurkaushal360 Could you provide your component, test code and environment(rollup config / test setup...) or a minimal repo to reproduce the issue? Thanks.

@chenesan I was about to report what I found. Just a little background, we use styled-jsx for dynamic styles & sass for static styles.

Here's the rollup.config.js:

import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import scssStyledJsxComponentPlugin from 'rollup-plugin-sass-styled-jsx-component';
const { dependencies, peerDependencies } = require('./package.json');
export default {
  input: [
    'list-of-components'
  ],
  plugins: [
    resolve({
      jsnext: true,
      main: true,
      extensions: [ '.js', '.jsx' ]
    }),
    scssStyledJsxComponentPlugin(),
    babel({
      ignore: ['node_modules/**'],
      presets: [
        ['@babel/preset-env', {
          modules: false,
          loose: true,
          targets: {
            browsers: [
              'last 2 versions',
              'ie >= 10'
            ]
          }
        }],
        '@babel/preset-react'
      ],
      plugins: [
        '@babel/plugin-proposal-export-default-from',
        [
          'styled-jsx/babel',
          {
            optimizeForSpeed: true
          }
        ]
      ],
      babelrc: false
    }),
    commonjs()
  ],
  output: [
    { dir: 'dist/lib', format: 'cjs', exports: 'named' },
    { dir: 'dist/es', format: 'es', exports: 'named' }
  ],
  experimentalCodeSplitting: true,
  external: id => Object.keys(peerDependencies).includes(id) ||
  Object.keys(dependencies).includes(id) ||
    /^styled-jsx/.test(id)
};

From my investigation, I found that importing styles from the sass file seems to be the culprit.

Unfortunately the component(s) reside in a private repo but I can provide a sample.

We import styles like this:

import Styles from './Test.scss';

And use it the component like this:

class Test extends React.Component {
   render () {
       return (
          <div>
            <Styles /> --> That's the point where it fails.
          </div>
       )
   }
}

Usage of sass styles seems to be the issue.

@ankurkaushal360 hmm, I'll try to look into this.

@ankurkaushal360 Could you print the Styles component? I'm wondering it what this is.
I've tried directly use _JSXStyle component in the doc of styled-jsx and that works:

import Enzyme, { mount } from "enzyme"
import Adapter from 'enzyme-adapter-react-16'
import React from 'react'
import _JSXStyle from 'styled-jsx/style'

Enzyme.configure({ adapter: new Adapter() })

describe('test', () => {
  it('should work', () => {
    mount(<div>
      <_JSXStyle>{`
        p{ color: red;}
      `}</_JSXStyle>
    </div>)
  })
})

I suspect that Styles should be transpiled as _JSXStyle but it doesn't.

@chenesan How can I do that? 馃

@ankurkaushal360 If it's not ok (I see that it's in private repo..) to console.log it, could you provide a repo to reproduce this?
Also I notice that with rollup-plugin-sass-styled-jsx-component I will get unexpected token error when handling .scss in rollup, I have to use rollup-plugin-sass-styled-jsx to pass this. Not
sure if it's relative, though.

Note that importing scss, css, etc - basically anything that's not .js, .node, or .json - needs to have babel transforms NOT webpack config, to be able to have it work in tests (any tests, not just enzyme).

In general, very little should be in your webpack config, and it should all be done with babel transforms instead.

@ljharb which babel transforms are supposed to assist here? My current .babelrc is quite minimal:

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}

What's missing here for dealing with svg imports?
BTW the components works as expected and renders the imported svgs. My problem is testing it (mounting).

OK, I managed to solve it using a babel plugin:babel-plugin-inline-react-svg
Thanks for the help!

OK, I managed to solve it using a babel plugin:babel-plugin-inline-react-svg
Thanks for the help!

It works. thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aweary picture aweary  路  3Comments

amcmillan01 picture amcmillan01  路  3Comments

timhonders picture timhonders  路  3Comments

benadamstyles picture benadamstyles  路  3Comments

mattkauffman23 picture mattkauffman23  路  3Comments