酶不模拟 React Material-UI v1 上的更改事件 - 选择组件

Posted

技术标签:

【中文标题】酶不模拟 React Material-UI v1 上的更改事件 - 选择组件【英文标题】:enzyme not simulating change event on React Material-UI v1 - Select component 【发布时间】:2018-09-11 02:22:43 【问题描述】:

所以我开始使用 Jest 和 Enzyme 设置对由 Material-UI 组件组成的 React 组件进行单元测试。到目前为止,每个事件模拟都运行良好,直到我遇到来自 Material-UI 的 Select 组件。 (下面有更多信息)

使用 create-react-app 引导项目并使用 material-ui-next。

依赖版本

反应:16.2.0 React-Dom:16.2.0 反应脚本:1.1.1 材质界面:1.0.0-beta.35 开玩笑:安装包中的一个 (22.4.3) 酶:3.3.0 酶适配器反应 16:1.1.1

问题

我有一个名为 FiltersDesktop 的纯功能组件,由 Material-UI 表单字段组成。其中三个是 Select 组件,其他是来自 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 测试代码

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 字段交互时,会调用更新函数。以下是我为测试Select编写的测试代码:

选择测试代码

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。

请帮助我找出在模拟它时未在 Select 组件上触发更改事件的原因。

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

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

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

【问题讨论】:

【参考方案1】:

我克隆了您的分支并进行了测试,但我发现了一些有趣的东西:ShallowWrapper 和 ReactWrapper 中的模拟方法的工作方式不同,即使用浅层和使用挂载时模拟的工作方式不同。

首先看一下这个问题: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();
);

如您所见,在使用 shallow 的第二种方法中,我调用了变量包装器,因为它是组件的包装器,而不是组件,此外,您可以注意到,在第一种安装方法中,测试仅在以下情况下有效通过 props 直接调用 onChange。

【讨论】:

您好,感谢您的快速回复。我浏览了你提到的链接,我忽略了一个很好的解释。感谢那。另外,我注意到不是用引号写 Select,我猜你实际上把他们的 Select from material-ui 引用。我让它以这种方式工作。这是故意的吗?如果是这样,那么 find 在以字符串形式提供组件时没有返回浅包装器的任何原因。如 - .find('Select') 是的,这也是我忘记告诉你的一点,我真的更喜欢使用这种方法,因为字符串引用很容易被破坏,所以我避免这样做。 再次感谢您,我浏览了酶文档进行浅层渲染并在那里得到了答案。我会一直打开这个,直到我确定关于浅层的某些事情,最多需要 2 天。对于那些寻找正确解决方案的人,请参考此解决方案。对我来说效果很好,请查看提到的链接。 对于mount() 示例,请注意您正在直接调用onChange 函数。这绕过了 Select 的打开以及对其中是否存在任何条目的验证。当列表中只有 0-2 时,您可以传递值 3,这仍然有效。 MUI 自己的测试使用render() 并没有帮助。话虽如此,我们并没有真正测试 MUI 或浏览器,是吗? github.com/enzymejs/enzyme/issues/1081#issuecomment-323866479

以上是关于酶不模拟 React Material-UI v1 上的更改事件 - 选择组件的主要内容,如果未能解决你的问题,请参考以下文章

在 react material-ui 菜单中测试嵌套菜单项

Google--Material Design UI素材库React版

Material-ui v1标签标签包装错误

React & Material-UI 分页 - 将 Material-UI 的组件连接到 React-Router

Material Design UI素材库React版--定制

使用 React 和 Material-UI 的开源项目?