【问题标题】:Testing Material UI components using Hooks API & Enzyme shallow rendering使用 Hooks API 和 Enzyme 浅层渲染测试 Material UI 组件
【发布时间】:2019-09-25 00:07:14
【问题描述】:

Material UI 的最新版本现在有一个用于样式组件的 Hooks 替代方案,而不是 HoC。所以不是

const styles = theme => ({
  ...
});

export const AppBarHeader = ({ classes, title }) => (
  ...
);
export default withStyles(styles)(AppBarHeader);

您可以选择这样做:

const useStyles = makeStyles(theme => ({
  xxxx
}));

const AppBarHeader = ({ title }) => {
  const classes = useStyles();
  return (
    ....
  )
};

export default AppBarHeader;

在某些方面这更好,但与所有钩子一样,您不能再向组件注入“存根”依赖项。以前,为了使用 Enzyme 进行测试,我只测试了非样式组件:

describe("<AppBarHeader />", () => {
  it("renders correctly", () => {
    const component = shallow(
      <AppBarHeader title="Hello" classes="{}" />
    );
    expect(component).toMatchSnapshot();
  });
});

然而,如果你使用钩子,没有类的“存根”依赖,你会得到:

  Warning: Material-UI: the `styles` argument provided is invalid.
  You are providing a function without a theme in the context.
  One of the parent elements needs to use a ThemeProvider.

因为您始终需要提供者。我可以去总结一下:

describe("<AppBarHeader />", () => {
  it("renders correctly", () => {
    const component = shallow(
      <ThemeProvider theme={theme}>
        <AppBarHeader title="Hello" classes="{}" />
      </ThemeProvider>
    ).dive();
    expect(component).toMatchSnapshot();
  });
});

但这似乎不再渲染组件的子组件(即使使用潜水调用)。人们是怎么做到的?

【问题讨论】:

  • 看来答案是 (a) 不要做浅渲染和 (b) 使用 react-testing-library 而不是 Enzyme

标签: material-ui enzyme react-hooks


【解决方案1】:

编辑:根据下面的 cmets,此实现存在一些时间问题。考虑使用 mount 测试而不是浅层测试,或者使用 withStyles HOC 并导出组件以进行浅层渲染。

所以我已经为此苦苦挣扎了一天。这是我想出的。

尝试存根 makeStyles 时存在一些问题,因为 MUI 似乎已将其设为只读。因此,我没有在每个组件中创建useStyles 挂钩,而是创建了自己的自定义useStyles 挂钩,该挂钩调用makeStyles。通过这种方式,我可以存根我的useStyles 钩子以进行测试,而对我的代码流的影响最小。

// root/utils/useStyles.js
// My custom useStyles hook

import makeStyles from '@material-ui/styles/makeStyles';

export const useStyles = styles => makeStyles(theme => styles(theme))();

这几乎就像使用withStyles HOC

// root/components/MyComponent.js
import React from 'react';
import { useStyles } from '../util/useStyles';

// create styles like you would for withStyles
const styles = theme => ({
  root: {
    padding: 0,
  },
});

export const MyComponent = () => {
  const classes = useStyles(styles);
  return(
    </>
  );
}
// root/component/MyComponent.spec.js
import { MyComponent } from './MyComponent';
import { shallow } from 'enzyme';
import { stub } from 'sinon';

describe('render', () => {
  it('should render', () => {
    let useStylesStub;
    useStylesStub = stub(hooks, 'useStyles');
    useStylesStub.returns({ });
    const wrapper = shallow(<MyComponent />);
    console.log('profit');
  });
});

这是我目前能想到的最好的,但总是愿意接受建议。

【讨论】:

  • 这种方法是有问题的。 makeStyles 旨在为每个样式对象调用一次,但使用您的方法,每次渲染都会调用一次。每个渲染都将使用makeStyles 返回的自定义挂钩的新版本。这也会对生成的样式表的顺序产生负面影响(请参阅我的回答 here 以获得解释)。使用withStyles 比使用这种方法要好得多。
  • 另请参阅我的回答here,以进一步了解这种方法将导致的问题。
  • 感谢您的更新,我担心这会导致问题
  • useEffect 没有适当的时间来正确管理它。我的建议是改变测试方法,不使用 @JamesCrowley 在他的评论中提到的浅渲染,而不是在你的代码中做奇怪的解决方法。
  • makeStyles 的计时仍将关闭。为了使父子组件样式之间的交互正常工作,应该在导入组件时调用makeStyles,而不是在渲染组件时调用。
猜你喜欢
  • 2016-10-29
  • 1970-01-01
  • 2020-05-10
  • 2018-11-27
  • 2018-04-28
  • 2016-12-18
  • 2017-03-11
  • 2021-10-29
  • 2021-06-24
相关资源
最近更新 更多