4

我目前正在为我的 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)
or
scryRenderedComponentsWithTag("button")
等​​来获取对话内容。

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

更新 1

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

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

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

关于乔纳斯

4

5 回答 5

7

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

幸运的是,RenderToLayer组件接受了 prop 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;在代码中的任何位置放置语句以生成调试器将响应的断点。一旦它找到了你的断点,它将暂停并允许你使用本地范围来参与你的代码。此时, enterrepl进入您的代码的本地范围并访问您的本地变量。

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

于 2016-02-01T18:47:48.947 回答
5

解决如下:

/*
* 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);
于 2017-03-09T21:52:31.237 回答
0

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

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 苦苦挣扎

于 2015-12-18T10:14:11.457 回答
0

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);
于 2017-07-21T08:53:46.100 回答
0

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

于 2020-04-16T19:42:24.323 回答