Enzyme: Potentially swallowed errors

Created on 19 Oct 2017  ·  15Comments  ·  Source: enzymejs/enzyme

I've read through the common issues guide but I can't seem to find any answers. It seems like errors are being swallowed when I use mount:

  ● Example › can mount properly

    Error: The above error occurred in one of your React components:
        in div (created by Box)
        in Box (created by FelaBox)
        in FelaBox (created by FelaBox)
        in FelaBox (created by Example)
        in Example (created by WrapperComponent)
        in WrapperComponent

    Consider adding an error boundary to your tree to customize error handling behavior.
    You can learn more about error boundaries at https://fb.me/react-error-boundaries.

      at BufferedConsole.Object.<anonymous>.global.console.error (test-setup/patch-console.js:8:9)
      at captureError (node_modules/react-dom/cjs/react-dom.development.js:12997:17)
      at performWork (node_modules/react-dom/cjs/react-dom.development.js:12825:22)
      at scheduleUpdateImpl (node_modules/react-dom/cjs/react-dom.development.js:13185:19)
      at scheduleUpdate (node_modules/react-dom/cjs/react-dom.development.js:13124:12)
      at scheduleTopLevelUpdate (node_modules/react-dom/cjs/react-dom.development.js:13395:5)
      at Object.updateContainer (node_modules/react-dom/cjs/react-dom.development.js:13425:7)
      at node_modules/react-dom/cjs/react-dom.development.js:17105:19
      at Object.unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:13256:14)
      at renderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:17104:17)
      at Object.render (node_modules/react-dom/cjs/react-dom.development.js:17129:12)
      at Object.render (node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js:216:50)
      at new ReactWrapper (node_modules/enzyme/build/ReactWrapper.js:98:16)
      at mount (node_modules/enzyme/build/mount.js:19:10)
      at mount (test-setup/felaMount.js:25:37)
      at Object.<anonymous> (packages/rio-component-flex/src/__tests__/Example.test.js:6:19)
          at new Promise (<anonymous>)
          at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)

There's no indication of what the error actually is. Has anyone seen this before and could provide some guidance?

Versions:

    "enzyme": "^3.1.0",
    "enzyme-adapter-react-16": "^1.0.1",
    "enzyme-to-json": "^3.1.4",
    "react": "^16.0.0",

The component:

import React, { Children, Component } from 'react';
import PropTypes from 'prop-types';
import { Box } from '..';

/**
* Example is just a box with flex: true. It can be used to help debug laying
* components out and therefore is recommended over using <Box flex />.
*/
class Example extends Component {
  static propTypes = {
    /** If true, all Boxes will be rendered in debug mode */
    debug: PropTypes.bool,
    /** The content to render */
    children: PropTypes.node,
  };

  render() {
    const { children, debug, ...rest } = this.props;

    return (
      <Box flex={true} debug={debug} {...rest}>
        {Children.map(children, child => {
          if (child.type === Box) {
            return React.cloneElement(child, { debug });
          } else {
            return child;
          }
        })}
      </Box>
    );
  }
}

export default Example;

The test:

import React from 'react';
import Example from '../Example';

describe('Example', function() {
  it('can mount properly', function() {
    const wrapper = felaMount(<Example debug={false}>something</Example>);
    expect(wrapper.type()).toEqual(Example);
  });
});

And my custom mounter which adds the necessary context for the CSS-in-JS solution:

import React from 'react';
import PropTypes from 'prop-types';
import { mount as enzymeMount } from 'enzyme';
import { createRenderer } from '@covered/rio-style-tools';
import { theme } from '@covered/rio-style-const';
import { renderToString } from 'fela-tools';
import { createTheme } from 'fela-bindings';
import toJson from 'enzyme-to-json';

const prettifyFelaString = str =>
  str
    // adds extra lines before @media
    .replace(/\@media/g, '\n\n@media')
    // adds extra lines between keyframes and following selectors
    .replace(/\}\.([a-zA-Z])/g, '}\n\n.$1')
    // adds extra indentation and lines to nested selectors
    .replace(
      /\)\{(\.[\s\S]+?\})(\})/g,
      (match, p1) => `) {\n  ${p1.replace(/\n/g, '\n  ')}\n}`,
    );

const mount = (node, options = {}) => {
  const renderer = createRenderer();

  const component = enzymeMount(node, {
    childContextTypes: {
      renderer: PropTypes.object,
      theme: PropTypes.object,
    },
    context: {
      renderer,
      theme: createTheme(theme),
    },
    ...options,
  });

  component.snapshot = function snapshot() {
    return {
      component: toJson(this),
      styles: `\n${prettifyFelaString(renderToString(renderer))}\n`,
    };
  };

  return component;
};

global.felaMount = mount;
mount

All 15 comments

What happens if you use shallow? Have you tried on react 15?

I'm having the same problem with a similar setup. When I use shallow as opposed to mount, my test passes.

Yup shallow seems to work fine. I have not tried on React 15 sorry

@SpencerCDixon What does the code for Box look like, since that's the last custom component in your stack trace?

Also, does your test pass if you shallow-render Box directly?

Box:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { css } from '..';
import { connect } from '@covered/rio-style-fela';
import { classnames as cn } from '@covered/rio-style-tools';

const debug = ({ theme: { colors } }) => ({
  border: `1px solid ${colors.primary}`,
  background: 'rgba(86, 131, 255, .1)',
  backgroundImage:
    'linear-gradient(rgba(86,131,255, .2) 1px, transparent 0), linear-gradient(90deg, rgba(86,131,255, .2) 1px, transparent 0)',
  backgroundSize: '20px 20px',
});

/**
 * Box is useful for laying out content where it belongs
*/
class Box extends Component {
  static propTypes = {
    /** @ignore - internal */
    styles: PropTypes.object,
    /** Optional override */
    className: PropTypes.string,
    /** Optional bool to start making box debug easier */
    debug: PropTypes.bool,
    /** The content to render */
    children: PropTypes.node,
  };

  static defaultProps = {
    debug: false,
  };

  render() {
    const { children, className, styles, debug, ...rest } = this.props;

    return (
      <div
        className={cn(className, styles.css, { [styles.debug]: debug })}
        {...rest}
      >
        {children}
      </div>
    );
  }
}

export default connect({ debug, css })(Box);

And yes box will mount just fine, I have a test that mounts the box that passes which is why it seems super weird to me. Tests for Box that pass:

import React from 'react';
import { Box, Flex } from '..';

describe('Box', function() {
  it('renders okay', function() {
    const ss = felaSnapshot(<Box> something</Box>);
    expect(ss.component).toMatchSnapshot();
    expect(ss.styles).toMatchSnapshot();
  });

  it('can mount', function() {
    const wrapper = felaMount(<Box>something</Box>);
  });
});

I added a shallow mount to the ^ tests and it works fine too for Box.

If you remove the Children.map function in Example, and replace it with just {children}, does it work?

Nope, still fails. I then tried making it just render a <div> and it still fails. However, when I remove the props being spread then it works! So:

      <Box>
        {Children.map(children, child => {
          // Only clone if we want to render Boxes in 'debug' mode
          if (debug && child && child.type === Box) {
            return cloneElement(child, { debug });
          } else {
            return child;
          }
        })}
      </Box>

Will mount correctly

Yeah confirmed it's the flex prop. If I remove that from the Box then it mounts correctly. Very likely my css-in-js is throwing for some reason, what I don't get is why it swallows the error and doesn't give me any indicator as to _why_ it's failing haha. Makes it very hard to debug mounting

aha! yeah, spread props are generally an antipattern anyways; and invalid HTML props trigger an error.

In other words, it's that the flex ends up on the div, which isn't a valid attribute.

Cool yeah I can totally change that on my side to fix but do you know if there is a way to get enzyme to tell users that's the problem with their mounting? I'm happy to try and provide a PR if I could get some guidance/direction.

The errors come from inside React, so I'm not sure if it'd be possible for enzyme to provide a better message here.

Ahhh okay dokes. Thanks for taking the time to look into this with me @ljharb! Closing for now

@SpencerCDixon that issue looks like it needs to be fixed on react level see https://github.com/facebook/react/issues/11098 for more details

Was this page helpful?
0 / 5 - 0 ratings