【问题标题】:Unit testing React component using Material UI Dialog使用 Material UI Dialog 对 React 组件进行单元测试
【发布时间】:2016-03-22 15:03:35
【问题描述】:

我目前正在为我的 React + MaterialUi 应用程序编写单元测试。

在我的应用程序中,我有一个对话框。我想确定取决于对话框上按下的按钮:

<FlatButton
  label="Cancel"
  secondary={true}
  onTouchTap={this._cancelDialog.bind(this)} 
 />
 <FlatButton
   label="Submit"
   primary={true}
   onTouchTap={this._confirmDialog.bind(this)} 
 />

内部状态会相应改变。

不幸的是,我无法使用 TestUtils.scryRenderedComponentsWithType(FlatButton)
或
scryRenderedComponentsWithTag("button")
等等。

关于如何测试该流程的任何想法?

更新 1

所以我可以通过调用 TestUtils.scryRenderedComponentsWithType(Dialog) 来获取 Dialog 实例。但我无法获得对话内容。 DOM 明智的内容不会呈现在视图本身内。它呈现在文档级别(div)上的新创建节点中。所以我尝试了这个:

let cancelButton = window.document.getElementsByTagName("button")[0];
Simulate.click(cancelButton);

cancelButton 在上面的例子中是正确的 DOM 元素。 Simulate.click 但是不会触发组件点击功能。

问候 乔纳斯

【问题讨论】:

  • 你能把你的问题改成更清晰的格式吗?

标签: unit-testing reactjs material-ui reactjs-testutils


【解决方案1】:

我遇到了同样的问题并这样解决:

const myMock = jest.genMockFunction();
const matcherComponent = TestUtils.renderIntoDocument(
      <MatcherComponent onClickCancel={myMock} activAction/>
        );
const raisedButton = TestUtils.findRenderedComponentWithType(
            matcherComponent, RaisedButton);

TestUtils.Simulate.click(ReactDOM.findDOMNode(raisedButton).firstChild);

expect(myMock).toBeCalled();

它对我来说很好用。但是我仍在为 Simulate.change 苦苦挣扎

【讨论】:

  • 感谢您的回复。不幸的是,TestUtils.findRenderedComponentWithType(dialog, FlatButton) 在对话框中没有返回任何内容。
  • 我自己在 Dialog 中遇到了同样的问题。也许 Material UI 的 Dialog 有问题?
【解决方案2】:

刚刚遇到同样的问题。我查看了源代码,Dialog组件的render方法实际上创建了组件RenderToLayer的一个实例。这个组件的行为就像一个门户,并通过在其渲染函数中返回 null 并直接附加到主体来破坏 react 的 DOM 树。

幸运的是,RenderToLayer 组件接受了 render 属性,它本质上允许组件向门户传递一个在渲染周期中要调用的函数。这意味着我们实际上可以自己手动触发这个事件。我承认,这并不完美,但是经过几天的尝试,试图为这个 hack 找到解决方案后,我认输并像这样编写我的测试:

var component = TestUtils.renderIntoDocument(<UserInteractions.signupDialog show={true}/>)
var dialog = TestUtils.renderIntoDocument(component.refs.dialog.renderLayer())
var node = React.findDOMNode(dialog)

这是我的 UserInteractions.signupDialog 的样子:

exports.signupDialog = React.createClass({
...
  render: function() {
    var self = this;

    return (
      <div>
        <Dialog
          ref='dialog'
          title="Signup"
          modal={false}
          actions={[
            <Button
              label="Cancel"
              secondary={true}
              onTouchTap={self.__handleClose}
            />,
            <Button
              label="Submit"
              primary={true}
              keyboardFocused={true}
              onTouchTap={self.__handleClose}
            />
          ]}
          open={self.props.show}
          onRequestClose={self.__handleClose}
          >
          <div className='tester'>ham</div>
          <TextField id='tmp-email-input' hintText='email' type='text'/>
        </Dialog>
      </div>
    )
  }
})

现在我可以对对话框中呈现的子组件进行断言,甚至可以对绑定到我的原始组件的事件进行断言,因为它们的关系保持不变。

如果您要继续使用材料 ui,我绝对建议您在测试堆栈中设置调试器。像这样的事情没有太多帮助。这是我的调试脚本的样子:

// package.json
{
  ...
  "scripts": {
    "test": "mocha --compilers .:./test/utils/compiler.js test/**/*.spec.js",
    "debug": "mocha debug --compilers .:./test/utils/compiler.js test/**/*.spec.js"
  }
}

现在您可以使用npm test 运行mocha 测试,并使用npm run debug 进入调试器。一旦进入调试器,它将立即暂停并等待您输入断点。此时输入c继续。现在您可以在代码中的任何位置放置debugger; 语句以生成调试器将响应的断点。一旦它找到了你的断点,它将暂停并允许你使用本地范围来参与你的代码。此时输入repl进入你的代码的本地作用域并访问你的本地变量。

也许您不需要调试器,但也许其他人会觉得这很有帮助。祝你好运,编码愉快!

【讨论】:

  • 我一直在努力解决对话测试的这个问题。优秀的答案。谢谢你。
【解决方案3】:

解决如下:

/*
* I want to verify that when i click on cancel button my showModal state is set * to false
*/

//shallow render my component having Dialog
const wrapper= shallow(<MyComponent store={store} />).dive();

//Set showModal state to true
wrapper.setState({showModal:true});

//find out cancel button with id 'cancelBtn' object from actions and call onTouchTap to mimic button click
wrapper.find('Dialog').props().actions.find((elem)=>(elem.props.id=='cancelBtn')).props.onTouchTap();

//verify that the showModal state is set to false
expect(wrapper.state('showModal')).toBe(false);

【讨论】:

    【解决方案4】:

    Solution by avocadojesus 非常棒。但我有一个补充。如果您尝试应用此解决方案并收到错误:

    错误:'警告:上下文类型失败:上下文 muiTheme 已标记 在DialogInline 中要求,但它的值为undefined。

    你应该修改他的代码如下:

    var component = TestUtils.renderIntoDocument(
      <MuiThemeProvider muiTheme={getMuiTheme()}>
        <UserInteractions.signupDialog show={true}/>
      </MuiThemeProvider>
    );
    
    var dialogComponent = TestUtils.findRenderedComponentWithType(component, UserInteractions.signupDialog);
    
    var dialog = TestUtils.renderIntoDocument(
      <MuiThemeProvider muiTheme={getMuiTheme()}>
        {dialogComponent.refs.dialog.renderLayer()}
      </MuiThemeProvider>
    );
    
    var node = React.findDOMNode(dialog);
    

    【讨论】:

      【解决方案5】:

      Material UI fork 2 种酶方法。您需要使用createMount 或createShallow 与潜水选项https://material-ui.com/guides/testing/#createmount-options-mount

      【讨论】:

        猜你喜欢
        • 2021-07-22
        • 2020-06-09
        • 1970-01-01
        • 1970-01-01
        • 2017-12-01
        • 1970-01-01
        • 2019-12-01
        • 1970-01-01
        • 2019-07-08
        相关资源
        最近更新 更多