I expect the tests to run without a problem.
I get an error:
TypeError: parentInstance.children.indexOf is not a function
I think this is due to portals not working properly in combination with jest snapshots.
import React from 'react';
import { storiesOf } from '@storybook/react';
import AlertDialog from './AlertDialog';
storiesOf('AlertDialog', module)
.add('basic', () => <AlertDialog bodyKey="test" onClick={() => {}} titleKey="test" open />);
Where <AlertDialog />
is a boring wrapper around <Dialog />
.
I'm sorry for not including a code snippet. I don't know how to set up the tests to illustrate the issue, but I tried my best to provide as much relevant information as possible.
I'm using storybooks with storysnaps (jest snapshots), and our tests are failing. I'm pretty sure it has something to do with https://github.com/airbnb/enzyme/issues/1150 and potentially https://github.com/reactjs/react-modal/issues/553 could benefit from a solution as well.
| Tech | Version |
|--------------|---------|
| Material-UI | 1.0.0-beta.21 |
| React | 16.0.0 |
| browser | N/A |
I have a feeling this is something that could be caught in storyshots but I'm not experienced enough with the material at hand. Any pointers, or better yet solutions would be greatly appreciated.
I'm not against fixing it and contributing either (if I get the right pointers to help me out).
Your issue has been closed because it does not conform to our issue requirements.
Please provide a full reproduction test case. This would help a lot 👷 .
A live example would be perfect. This codesandbox.io template _may_ be a good starting point. Thank you!
I'm sorry for not including a code snippet. I don't know how to set up the tests to illustrate the issue, but I tried my best to provide as much relevant information as possible.
The information provided aren't actionable on our end. We need a reproduction repository. Also, what is this AlertDialog
component?
@oliviertassinari
An error occured when fetching the sandbox:
Could not find package.json
While I do understand you want to keep things tidy in here, I'm not spending too much time on this. I'll just comment out my dialog stories for now. If anyone else comes across this issue, maybe they're willing to make the example.
@RWOverdijk Thanks, I will have a look at what's going on with codesandbox!
Yes, same on our side. We have limited ressources, trying reproducing issues has a poor value/cost ratio in comparaison to other tasks. It's why we use a strict policy.
Came across the same issue...
Environment
Component
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import Button from 'material-ui/Button';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
const styles = () => ({
div: {
display: 'block',
textAlign: 'center'
}
});
class Error extends React.Component {
constructor(props) {
super(props);
this.state = {
open: true
};
}
handleRequestClose = () => {
this.setState({ open: false });
}
render() {
const { classes, errorMsg } = this.props;
return (
<div className={classes.div}>
<Dialog ignoreBackdropClick ignoreEscapeKeyUp open={this.state.open} onRequestClose={this.handleRequestClose}>
<DialogTitle>{"You got an error!"}</DialogTitle>
<DialogContent>
<DialogContentText>
Error: {errorMsg}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleRequestClose} color="accent" autoFocus>
Dismiss
</Button>
</DialogActions>
</Dialog>
</div>
);
}
}
Error.propTypes = {
classes: PropTypes.object.isRequired,
errorMsg: PropTypes.string
};
export default withStyles(styles)(Error);
Test
import React from 'react';
import Error from '../shared/Error';
import renderer from 'react-test-renderer';
describe('Error component', () => {
it('should render', () => {
const tree = renderer.create(
<Error />
).toJSON();
expect(tree).toMatchSnapshot();
});
});
Error message
● Error component › should render
TypeError: parentInstance.children.indexOf is not a function
at appendChild (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7146:39)
at commitPlacement (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:4893:13)
at commitAllHostEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5651:13)
at HTMLUnknownElement.callCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1584:14)
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:219:27)
at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:126:9)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:87:17)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:36:27)
at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:61:35)
at Object.invokeGuardedCallbackDev (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1623:16)
at invokeGuardedCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1480:29)
at commitRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5771:9)
at performWorkOnRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6730:42)
at performWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6680:7)
at requestWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6596:7)
at scheduleWorkImpl (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6479:11)
at scheduleWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6441:12)
at scheduleTopLevelUpdate (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6904:5)
at Object.updateContainer (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6942:7)
at Object.create (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7562:18)
at Object.<anonymous> (src/components/pages/shared/Error.spec.js:7:44)
Just run into the same issue. It has something to do with the Portals. I made a simple reproduce project here: https://github.com/Skaronator/material-ui-issue-9243
Just run:
yarn
yarn test
And you'll get the following error:
$ react-scripts test --env=jsdom
FAIL src\App.test.js
● should match Snapshot
TypeError: parentInstance.children.indexOf is not a function
at appendChild (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7218:39)
at commitPlacement (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:4904:13)
at commitAllHostEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5678:13)
at HTMLUnknownElement.callCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1610:14)
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:219:27)
at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:126:9)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:87:17)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:36:27)
at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:61:35)
at Object.invokeGuardedCallbackDev (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1649:16)
at invokeGuardedCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1506:29)
at commitRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5798:9)
at performWorkOnRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6800:42)
at performWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6750:7)
at requestWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6661:7)
at scheduleWorkImpl (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6515:11)
at scheduleWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6472:12)
at scheduleTopLevelUpdate (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6976:5)
at Object.updateContainer (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7014:7)
at Object.create (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7637:18)
at Object.<anonymous>.it (src/App.test.js:8:46)
at new Promise (<anonymous>)
at Promise.resolve.then.el (node_modules/p-map/index.js:46:16)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
× should match Snapshot (61ms)
@Skaronator Enzyme do not support the portal API of React: https://github.com/airbnb/enzyme/issues/252. We use a mockPortal.js for our tests internally.
i have the same problem
I can confirm with @oliviertassinari that mockPortal.js solves this issue. (not all issues trying to snapshot a material-ui dialog, but this particular one)
Another mocking solution that works is the following
jest.mock('rc-util/lib/Portal')
(add this to the top of the test file)
Obviously the rc-util
package is needed for this.
@Skaronator Enzyme do not support the portal API of React: airbnb/enzyme#252. We use a mockPortal.js for our tests internally.
Enzyme now supports the portal API of React. We have removed our mockPortal.js
module.
@reyronald We don't rely on rc-util/lib/Portal
. We have been using our own Portal component: https://material-ui-next.com/utils/portal/.
Enzyme now supports the portal API of React.
Oh cool - didn't know that. They didn't even close the issue on thier repo.
package.json
"material-ui": "1.0.0-beta.42",
"enzyme": "3.3.0",
"enzyme-adapter-react-16": "1.1.1",
"react-test-renderer": "16.3.2",
Test
import React from 'react';
import renderer from 'react-test-renderer';
import { BtnIcon } from 'Components/buttons/btn-icon';
const buttonIcon = <i className="fa fa-close" />;
describe('BtnIcon should match Snapshot', () => {
it('without hint', () => {
const renderedValue = renderer.create(
<BtnIcon>{buttonIcon}</BtnIcon>
).toJSON();
expect(renderedValue).toMatchSnapshot();
});
});
btn-icon.js
import React from 'react';
import PropTypes from 'prop-types';
import IconButton from 'material-ui/IconButton';
import Hint from 'Components/hint';
const BtnIcon = ({
children, className, onClick, disabled, hint, hintPlacement, wrapperClassName
}) => (
<Hint
text={hint}
placement={hintPlacement}
className="tooltip-popper--btn-icon"
wrapperClassName={wrapperClassName}
>
<div> {/* Little hack for disabled button inside */}
<IconButton
className={`btn btn-icon ${className} ${disabled ? 'disabled' : ''}`}
onClick={onClick}
disabled={disabled}
tabIndex={-1}
>
{children}
</IconButton>
</div>
</Hint>
);
BtnIcon.propTypes = {
children: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
]).isRequired,
className: PropTypes.string,
onClick: PropTypes.func,
disabled: PropTypes.bool,
hint: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
]),
hintPlacement: PropTypes.string,
wrapperClassName: PropTypes.string
};
BtnIcon.defaultProps = {
className: '',
onClick: null,
disabled: false,
hint: '',
wrapperClassName: '',
hintPlacement: undefined
};
export { BtnIcon };
hint.js - tooltip
import React from 'react';
import PropTypes from 'prop-types';
import Tooltip from 'material-ui/Tooltip';
import './hint.scss';
const Hint = props => (
<Tooltip
title={props.text}
placement={props.placement}
classes={{
root: `hint-root ${props.wrapperClassName}`,
popper: `hint-popper ${props.className}`,
tooltip: 'hint__text',
open: 'opened',
tooltipPlacementLeft: 'left',
tooltipPlacementRight: 'right',
tooltipPlacementTop: 'top',
tooltipPlacementBottom: 'bottom'
}}
>
{props.children}
</Tooltip>
);
Hint.propTypes = {
children: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
]).isRequired,
text: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object
]),
placement: PropTypes.string,
className: PropTypes.string,
wrapperClassName: PropTypes.string
};
Hint.defaultProps = {
wrapperClassName: '',
className: '',
text: '',
placement: 'top'
};
export default Hint;
And I'm getting the same error:
FAIL __tests__/components/buttons/btn-icon/btn-icon.test.js
BtnIcon should match Snapshot
✕ without hint (96ms)
● BtnIcon should match Snapshot › without hint
TypeError: parentInstance.children.indexOf is not a function
at appendChild (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8565:39)
at commitPlacement (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5779:13)
at commitAllHostEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6946:13)
at HTMLUnknownElement.callCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:906:14)
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
at Object.invokeGuardedCallbackDev (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:944:16)
at invokeGuardedCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:993:29)
at commitRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7122:9)
at completeRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8065:36)
at performWorkOnRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8015:11)
at performWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7933:9)
at performSyncWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7910:5)
at requestWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7810:7)
at scheduleWorkImpl (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7685:13)
at scheduleWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7645:12)
at scheduleRootUpdate (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8273:5)
at updateContainerAtExpirationTime (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8301:12)
at Object.updateContainer (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8328:14)
at Object.create (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9009:18)
at Object.<anonymous> (__tests__/components/buttons/btn-icon/btn-icon.test.js:27:53)
console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5206
The above error occurred in the <Popper> component:
in Popper (created by Tooltip)
in Portal (created by Tooltip)
in Manager (created by Tooltip)
in Tooltip (created by WithStyles(Tooltip))
in WithStyles(Tooltip) (created by Hint)
in Hint (created by BtnIcon)
in BtnIcon
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5206
The above error occurred in the <div> component:
in div (created by Popper)
in Popper (created by Tooltip)
in Portal (created by Tooltip)
in Manager (created by Tooltip)
in Tooltip (created by WithStyles(Tooltip))
in WithStyles(Tooltip) (created by Hint)
in Hint (created by BtnIcon)
in BtnIcon
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5206
The above error occurred in the <BtnIcon> component:
in BtnIcon
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
How can I solve this issue while we are waiting for a new enzyme (enzyme that will support portals)?
Solved it with - import { createMount } from 'material-ui/test-utils';
I hope it will be helpful for someone.
Also you can use simple { mount }
- import { mount } from 'enzyme';
But it will not render Tooltip at snapshot. Enzyme release new version with supporting Portals soon, I hope.
Example:
import React from 'react';
import { createMount } from 'material-ui/test-utils';
import { BtnIcon } from 'Components/buttons/btn-icon';
describe('BtnIcon should match Snapshot', () => {
it('without hint', () => {
const renderedValue = createMount()(
// Code of this component - <BtnIcon /> you can find above
<BtnIcon>{buttonIcon}</BtnIcon>
);
expect(renderedValue.html()).toMatchSnapshot();
});
});
I still have this issue using material-ui and react-test-renderer 16.13.0.
Is the solution here to use createMount
from material-ui/test-utils
?
I would like to continue to use react-test-renderer
.
const tree = renderer.create(<MyComp />);
Most helpful comment
Came across the same issue...
Environment
Component
Test
Error message
● Error component › should render