【问题标题】:Detect synthetic click in React during testing with Jest/Enzyme在使用 Jest/Enzyme 进行测试期间检测 React 中的合成点击
【发布时间】:2017-07-24 20:35:13
【问题描述】:

我正在使用 React 构建一个应用程序。我在 react-bootstrap Button 的“后面”隐藏了一个文件输入元素 (<input type="file"/>),以便能够控制样式。因此,当单击按钮时,我转身并在文本输入元素上触发合成单击事件,如下所示。

class OpenFileButton extends React.Component {
  ...
  clickHandler() {
    this.refs['input'].click();
  }

  render() {
    return (
      <ButtonGroup>
        <div>
          <input type="file" onChange={this.props.someCallback}
            ref="input" style={{display: 'none'}}/>
          <Button onClick={this.clickHandler}>Open File</Button>
        </div>
      </ButtonGroup>
    );
  }
}

我希望能够使用 Jest/Enzyme 进行测试。但是,虽然我可以模拟按钮上的点击事件,但我还没有弄清楚如何检测文件输入元素上的合成点击事件。

我曾尝试使用 Jest/Enzyme 来模拟输入元素上的点击方法。

const component = mount(<OpenFileButton/>);
const fileInput = component.find('input');
const button    = component.find('Button');
fileInput.click = jest.fn();
button.simulate('click');
expect(fileInput.click).toHaveBeenCalled();

但是,以这种方式模拟 click 方法是行不通的。我也无法添加onClick 属性,即fileInput.props().onClick = jest.fn() 不起作用。

This question 是关于在代码本身中检测合成点击事件,而不是在测试代码中,因此不相关。

那么,如何使用 Jest/Enzyme 检测 DOM 元素上的(合成)点击事件?

【问题讨论】:

    标签: javascript reactjs jestjs enzyme html-input


    【解决方案1】:

    &lt;input /&gt;this.refs.inputHTMLInputElement 的一个实例。

    然后你可以测试HTMLInputElement.prototype.click是否被调用。

    使用,您将拥有:

    import sinon from 'sinon';
    import {mount} from 'enzyme';
    
    const clickInputSpy = sinon.spy(HTMLInputElement.prototype, 'click')
    const component = mount(<OpenFileButton/>);
    
    const button    = component.find('Button');
    
    button.simulate('click');
    expect(clickInputSpy.called).toBeTruthy();
    clickInputSpy.restore();
    

    const clickInputSpy = sinon.spy(HTMLInputElement.prototype, 'click');
    
    
    console.log(
     'Is <input /> clicked ? ', clickInputSpy.called 
    );
    document.querySelector('input').click();
    
    
    console.log(
     'Is <input /> clicked ? ', clickInputSpy.called 
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/1.15.4/sinon.min.js"></script>
    
    <input />

    【讨论】:

    • 太棒了!谢谢你。完美运行。只是为了直接回答我的问题,为了对 Jasmine/Jest 而不是 Sinon 做同样的事情,请执行以下操作:(A)将您的 sinon.spy(... 替换为 spyOn(...。 (B) 将expect 语句更改为expect(clickInputSpy).toHaveBeenCalled()(或类似的东西)。 (C) 如果您需要在定义间谍的同一 itdescribe 块中恢复间谍,请按照建议的 here 使用 clickInputSpy.and.callThrough()
    • 但是,有一个问题,虽然不一定完全无法克服。 any/all 输入元素的间谍间谍,而不是我感兴趣的特定元素。在许多情况下,可能不会有多个不同的 input 元素需要区分,所以可能没问题。但是,它确实使测试有些不理想。如果您想在相同类型的两个元素之间“转移”点击,它也会使该策略完全不可行,例如单击一个按钮,然后以编程方式单击另一个按钮。
    • 所以我不知道是否可以直接窥探实例。如果是这样,请使用spy(component.ref('input'), 'click') 而不是spy(HTMLInputElement.prototype, 'click')。 ..它可能工作或spy(component.find('input').get(0), 'click')
    • 感谢您的想法。我已经在我发布的替代答案中使用了您的最后一个建议,即spy(...find...get..., 'click'),它似乎正在工作。无论如何,再次感谢您最初的回答让我朝着正确的方向前进。
    【解决方案2】:

    这里的解决方案涉及监视我感兴趣的特定文件输入元素的click 方法。因此,我可以检查是否在单击后调用了此 file-input-element-click-spy在button元素上模拟,如下:

    const openFileButtonWrapper = mount(<OpenFileButton/>);
    const buttonWrapper = openFileButtonWrapper.find(Button);
    const fileInputWrapper = openFileButtonWrapper.find('input [type="file"]');
    const fileInput = fileInputWrapper.get(0);
    const clickInputSpy = spyOn(fileInput, 'click');
    buttonWrapper.simulate('click');
    expect(clickInputSpy).toHaveBeenCalled();
    

    @AbdennourTOUMI 的回答使用了 Sinon 的 spy 方法,这提醒我 Jest 使用了一些 Jasmine 功能,包括它的 spyOn 方法,这在 Jest 文档中并不明显。因此,即使其他答案最终监视了 _all_ 输入元素,这并不理想,但它确实让我朝着正确的方向前进,所以谢谢你,Adbennour。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-07
      • 1970-01-01
      • 1970-01-01
      • 2020-09-07
      • 2018-11-09
      • 2018-08-31
      • 1970-01-01
      • 2017-02-12
      相关资源
      最近更新 更多