I have a component which is wrapped in both a Material-UI withStyles
HOC and a React memo
HOC.
I am unable to test this component as I am unable to call dive()
:
ShallowWrapper::dive() can only be called on components
The only option I am currently aware of is to independently export Demo
and export default withStyles(styles)(Demo)
. This allows me to test the component that isn't wrapped in withStyles
. I would like to avoid this method.
If I remove memo(), I am able to test the component. Likewise, if I remove withStyles(), I am also able to test the component. The combination of these HOCs render my component un-testable.
What are some available strategies to effectively test this component?
demo.js
import React, { memo } from "react";
import MUIIconButton from "@material-ui/core/IconButton";
import { withStyles } from "@material-ui/core/styles";
import Tooltip from "@material-ui/core/Tooltip";
import Typography from "@material-ui/core/Typography";
const styles = () => ({
root: {
backgroundColor: "red"
/* more styles... */
}
});
const Demo = memo(({ label, classes }) => (
<div className={classes.root}>
<Tooltip disableFocusListener title={label}>
<Typography>label</Typography>
</Tooltip>
</div>
));
export default withStyles(styles)(Demo);
demo.test.js
import React from "react";
import Adapter from "enzyme-adapter-react-16";
import { configure, shallow } from "enzyme";
import Demo from "./demo";
import MUIIconButton from "@material-ui/core/IconButton";
import Tooltip from "@material-ui/core/Tooltip";
configure({ adapter: new Adapter() });
describe("Demo", () => {
it("Should have a tooltip with label", () => {
const tooltip = "My tooltip";
const el = shallow(<Demo label={tooltip} />).dive();
expect(el.find(Tooltip).props().title).toEqual(tooltip);
});
});
Full working Sandbox
As skyboyer suggests, you should just export
the memoized function. You can import
the default export HOC
and utilize mount
, but you'll need to mock the classes
object to match how it's being used within the component.
Working example: https://codesandbox.io/s/4r492qvoz9
components/Demo/demo.js
import React, { memo } from "react";
import MUIIconButton from "@material-ui/core/IconButton";
import { withStyles } from "@material-ui/core/styles";
import Tooltip from "@material-ui/core/Tooltip";
import Typography from "@material-ui/core/Typography";
const styles = () => ({
root: {
backgroundColor: "red"
/* more styles... */
}
});
export const Demo = memo(({ label, classes }) => {
return (
<div className={classes.root}>
<Tooltip disableFocusListener title={label}>
<Typography>label</Typography>
</Tooltip>
</div>
);
});
export default withStyles(styles)(Demo);
components/Demo/__tests__/demo.test.js if ever need to see the DOM
structure, then just use console.log(wrapper.debug());
-- for example console.log(mountHOComponent.debug());
)
import React from "react";
import Adapter from "enzyme-adapter-react-16";
import { configure, shallow, mount } from "enzyme";
import { Demo } from "../demo";
import HOCDemo from "../demo";
configure({ adapter: new Adapter() });
const initialProps = {
label: "My tooltip",
classes: {
root: "component-example"
}
};
const shallowWrapper = shallow(<Demo {...initialProps} />);
const mountWrapper = mount(<Demo {...initialProps} />);
const mountHOComponent = mount(<HOCDemo {...initialProps} />);
describe("Demo", () => {
afterAll(() => {
shallowWrapper.unmount();
mountWrapper.unmount();
});
it("shallowWrap renders a tooltip with label", () => {
expect(shallowWrapper.find("WithStyles(Tooltip)").props().title).toBe(
initialProps.label
);
});
it("mountWrap renders a tooltip with label", () => {
expect(mountWrapper.find("Tooltip").props().title).toBe(initialProps.label);
});
it("mountHOComponent renders a tooltip with label", () => {
expect(mountHOComponent.find("Tooltip").props().title).toBe(
initialProps.label
);
});
});