如何浅测试包裹在备忘录和 withStyles 中的 React 组件?
How do I shallow test a react component wrapped in memo and withStyles?
我有一个组件被包裹在 Material-UI withStyles
HOC 和 React memo
HOC 中。
我无法测试此组件,因为我无法调用 dive()
:
ShallowWrapper::dive() can only be called on components
我目前知道的唯一选择是独立 export Demo
和 export default withStyles(styles)(Demo)
。这允许我测试未包含在 withStyles
中的组件。我想避免这种方法。
如果删除 memo(),我就可以测试该组件。同样,如果我删除 withStyles(),我也可以测试该组件。这些 HOC 的组合使我的组件无法测试。
有效测试此组件的一些可用策略是什么?
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);
});
});
完整的工作沙盒
正如 skyboyer 所建议的,您应该 export
记忆函数。您可以 import
默认导出 HOC
并利用 mount
,但您需要模拟 classes
对象以匹配它在组件中的使用方式。
工作示例: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 如果需要查看 DOM
结构,则只需使用 console.log(wrapper.debug());
-- 对于示例 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
);
});
});
此问题现已从 enzyme-adapter-react-16 v1.13.0 开始修复,添加了 memo dive() 支持。这是一个更新了依赖项的分叉沙箱,以显示两种测试方法(潜水和导出解决方法)现在都通过了。
当我用备忘录包裹时,我得到一个看起来像这样的形状
import MemoizedFoo from './Foo'
console.log(MemoizedFoo)
{ '$$typeof': Symbol(react.memo),
type:
{ [Function: Foo]
displayName: 'Foo',
defaultProps: { theme: {} } },
compare: null }
所以在我的笑话测试中,我可以通过引用类型键来获取内部组件
import MemoizedFoo from './Foo'
const Foo = MemoizedFoo.type
describe() { it() { shallow(Foo) ...etc } }
这非常适合浅层单元测试。
如果我正在安装一个父组件并寻找子组件存在,你可以这样做:
wrapper = mount(Layout)
wrapper.find('Memo(Foo)')
我有一个组件被包裹在 Material-UI withStyles
HOC 和 React memo
HOC 中。
我无法测试此组件,因为我无法调用 dive()
:
ShallowWrapper::dive() can only be called on components
我目前知道的唯一选择是独立 export Demo
和 export default withStyles(styles)(Demo)
。这允许我测试未包含在 withStyles
中的组件。我想避免这种方法。
如果删除 memo(),我就可以测试该组件。同样,如果我删除 withStyles(),我也可以测试该组件。这些 HOC 的组合使我的组件无法测试。
有效测试此组件的一些可用策略是什么?
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);
});
});
完整的工作沙盒
正如 skyboyer 所建议的,您应该 export
记忆函数。您可以 import
默认导出 HOC
并利用 mount
,但您需要模拟 classes
对象以匹配它在组件中的使用方式。
工作示例: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 如果需要查看 DOM
结构,则只需使用 console.log(wrapper.debug());
-- 对于示例 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
);
});
});
此问题现已从 enzyme-adapter-react-16 v1.13.0 开始修复,添加了 memo dive() 支持。这是一个更新了依赖项的分叉沙箱,以显示两种测试方法(潜水和导出解决方法)现在都通过了。
当我用备忘录包裹时,我得到一个看起来像这样的形状
import MemoizedFoo from './Foo'
console.log(MemoizedFoo)
{ '$$typeof': Symbol(react.memo),
type:
{ [Function: Foo]
displayName: 'Foo',
defaultProps: { theme: {} } },
compare: null }
所以在我的笑话测试中,我可以通过引用类型键来获取内部组件
import MemoizedFoo from './Foo'
const Foo = MemoizedFoo.type
describe() { it() { shallow(Foo) ...etc } }
这非常适合浅层单元测试。
如果我正在安装一个父组件并寻找子组件存在,你可以这样做:
wrapper = mount(Layout)
wrapper.find('Memo(Foo)')