酶不在React Material-UI v1上模拟变​​化事件 - 选择组件

时间:2018-04-01 19:00:05

标签: reactjs material-ui enzyme jest react-dom

所以我开始使用Jest和Enzyme设置对使用Material-UI组件组成的React组件进行单元测试。到目前为止,每个事件模拟都正常工作,直到我从Material-UI遇到Select组件。 (更多信息如下)

项目是使用create-react-app引导的,并使用了材料-ui-next。

依赖版本

  • React:16.2.0
  • React-Dom:16.2.0
  • React-Scripts:1.1.1
  • 材料用户界面:1.0.0-beta.35
  • Jest:一个装有设置(22.4.3)
  • 的人
  • 酶:3.3.0
  • 酶适配器反应16:1.1.1

问题

我有一个名为 FiltersDesktop 的纯功能组件,由Material-UI表单字段组成。其中三个是选择组件,其他是来自material-ui的文本字段和日期选择器。

用户界面代码

<Collapse in={props.visible} className={'filters-container-desk'}>
  <Grid container classes={{ typeContainer: "filter-container" }} id={'container-desk'}>

    <Grid item lg={2} xl={2}>
      <FormControl fullWidth={true}>
        <InputLabel htmlFor="sources">Sources</InputLabel>
        <Select
          open
          inputProps={{ name: 'sources-desk', id: 'sources-desk' }}
          value={props.filters.source || ''}
          onChange={(event) => props.updateFilter({ source: event.target.value })}
        >
          <MenuItem value=''>
            <em>None</em>
          </MenuItem>
          <MenuItem value={10}>Ten</MenuItem>
          <MenuItem value={20}>Twenty</MenuItem>
          <MenuItem value={30}>Thirty</MenuItem>
        </Select>
      </FormControl>
    </Grid>

    <Grid item lg={2} xl={2}>
    ...
    </Grid>
    ... // More Grid components of similar structure as above
  </Grid>
</Collapse>

当我尝试在textfield组件上模拟更改事件时,它可以正常工作。以下是我为测试文本字段而编写的代码:

TextField的测试代码

const props = {
  updateFilter: jest.fn()
};

test(`updateFilter should get called on simulating text changes in domain`, () => {
  const component = mount(<FiltersDesktop {...this.props} />);
  component.find('#domain-desk').last().simulate('change', { target: { value: 'scoopwhoop.com' } });
  expect(props.updateFilter).toHaveBeenCalled();
});

但类似的东西并不适用于Select组件。但是,当我实际通过接口与Select字段进行交互时,会调用update函数。以下是我为测试编写的测试代码选择:

选择

的测试代码
const props = {
  updateFilter: jest.fn()
};

test(`updateFilter should get called on simulating text changes in sources`, () => {
  const component = mount(<FiltersDesktop {...this.props} />);

  // Did not work
  component.find('#sources-desk').last().simulate('change', { target: { value: 20 } });

  // Did not work
  component.find('Select').first().simulate('change', { taget: { value: 20 } });

  // Did not work
  component.find('#sources-desk').forEach(element => element.simulate('change', { taget: { value: 20 } }))

  expect(props.updateFilter).toHaveBeenCalled();
});

由于某些原因,在所有上述情况下,find方法总是返回超过1个元素,因此我在适当的情况下使用first,last和forEach。

请帮助我弄清楚在模拟它时选择组件没有触发更改事件背后的原因。

请放心,我已经花了一周的时间在Github上阅读问题,尝试实施Jest和Enzyme的解决方案和测试指南。我确信我的测试设置很好,因为其他情况都正常。

如果您想要精确查看源代码,那么here是存储库的链接。对存储库的拉取请求也很感激。如果您在存储库中,请不要忘记切换到react-material分支。

P.S - 不要笑,因为我刚刚开始使用React:P

1 个答案:

答案 0 :(得分:15)

我克隆了你的分支并完成了测试工作,但我发现了一些有趣的东西:模拟方法在ShallowWrapper和ReactWrapper中的工作方式不同,这就是当使用浅和使用mount时,模拟的工作方式不同。

首先,看看这个问题:When should you use render and shallow in Enzyme / React tests?

最适合此类测试的应该是shallow()而不是mount(),因为您正在将此组件作为一个单元进行测试。

使用mount进行测试:

test("updateFilter should get called on simulating text changes in sources", () => {
  const component = mount(<FiltersDesktop {...props} />);

  component
    .find(Select)
    .at(0)
    .props()
    .onChange({ target: { value: 20 } });

  expect(props.updateFilter).toHaveBeenCalled();
});

使用浅层测试

test("updateFilter should get called on simulating text changes in sources", () => {
  const wrapper = shallow(<FiltersDesktop {...props} />);
  wrapper
    .find(Select)
    .at(0)
    .simulate("change", { target: { value: 20 } });

  expect(props.updateFilter).toHaveBeenCalled();
});

正如你所看到的,在使用浅的第二种方法中,我调用了变量包装器,因为它是组件的包装器而不是组件,此外你可以注意到在第一种方法中使用mount,测试仅在通过道具直接调用onChange时才有效。