【问题标题】:Testing input.focus() in Enzyme在 Enzyme 中测试 input.focus()
【发布时间】:2016-10-08 06:33:18
【问题描述】:

我如何在酶中测试input.focus()。我正在编写带有反应的脚本。我的代码如下:

public inputBox: any;

componentDidUpdate = () => {
    setTimeout(() => {
        this.inputBox.focus();
    }, 200);
}

render() {
    return (
        <div>
            <input
                type = 'number'
                ref = {element => this.inputBox = element } />
        </div>
    );
}

【问题讨论】:

    标签: reactjs typescript enzyme onfocus


    【解决方案1】:

    您可以使用mount 而不是浅。 然后你可以比较 document.activeElement 和输入 DOM 节点是否相等。

    const output = mount(<MyFocusingComponent/>);
    
    assert(output.find('input').node === document.activeElement);
    

    更多详情请见https://github.com/airbnb/enzyme/issues/316

    【讨论】:

    • 为我工作。需要明确的是,需要全局 windowdocument 对象才能挂载工作。我在我的第一个describe 之前使用了以下代码import jsdom from 'jsdom'; const doc = jsdom.jsdom('&lt;!doctype html&gt;&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;'); global.document = doc; global.window = doc.defaultView;
    • 对于 Jest,请确保在 CLI 中设置 --env=jsdom,或在 jest 配置中设置 "testEnvironment": "jsdom",然后您不需要导入它
    • 这是一个很好的答案,因为这是我发现的唯一一个也适用于 useRef 的东西,我还没有找到一种方法来获取函数组件中的引用。跨度>
    【解决方案2】:

    其他方法是测试元素是否获得焦点,即在节点元素上调用focus()。为了实现这一点,需要通过 ref 标签引用焦点元素,就像在您的示例中发生的那样 - 引用已分配给 this.inputBox。考虑下面的例子:

    const wrapper = mount(<FocusingInput />);
    const element = wrapper.instance().inputBox; // This is your input ref
    
    spyOn(element, 'focus');
    
    wrapper.simulate('mouseEnter', eventStub());
    
    setTimeout(() => expect(element.focus).toHaveBeenCalled(), 250);
    

    这个例子使用 Jasmine 的spyOn,尽管你可以使用任何你喜欢的间谍。

    【讨论】:

    • eventStub() 来自哪里?
    • eventStub 是使您的测试通过的任何东西。在此示例中,您可以假设组件FocusingInput 正在侦听“mouseEnter”事件,并且当触发此事件时(wrapper.simulate('mouseEnter', ...) 会这样做)事件处理程序可以对事件执行一些操作,例如preventDefault。要完成这项工作,您需要准备将处理此操作的事件存根并将此存根作为simulate 的第二个参数发送。这是我的event stub 的示例。
    • expect 包裹在setTimeout 中是危险的,因为无论setTimeout 内部发生了什么,您的测试运行者(在我的例子中是Jest)可能会说测试已经通过。在.toHaveBeenCalled 前面加上.not 试试看。
    【解决方案3】:

    我刚刚遇到了同样的问题并使用以下方法解决了:

    我的设置是 Jest (react-create-app) + Enzyme:

        it('should set the focus after render', () => {
          // If you don't create this element you can not access the 
          // document.activeElement or simply returns <body/>
          document.body.innerHTML = '<div></div>'
    
          // You have to tell Enzyme to attach the component to this
          // newly created element
          wrapper = mount(<MyTextFieldComponent />, {
            attachTo: document.getElementsByName('div')[0]
          })
    
          // In my case was easy to compare using id 
          // than using the whole element
          expect(wrapper.find('input').props().id).toEqual(
            document.activeElement.id
          )
        })
    

    【讨论】:

    • 按照你的例子,但我似乎从document.activeElement 得到一个字符串,而不是一个元素对象,所以测试结果是“对象可能是'null'”。有什么想法我可能会出错吗?
    • 感谢您提供此信息。 getElementsByName 应该是 getElementsByTagName
    【解决方案4】:

    根据 React 16.3 更新...如果您重新排列原始组件以使用新的 ref api,请使用 createRef 对于今天访问此帖子的任何人

    class InputBox extends PureComponent {
        constructor(props) {
            super(props);
            this.inputRef = React.createRef();
        }
        componentDidMount() {
            this.inputRef.current.focus();
        }
        render() {
            return (
                <input
                    ref={this.inputRef}
                />
            );
        }
    }
    

    然后在您的测试规范中

    it("Gives immediate focus on to name field on load", () => {
        const wrapper = mount(<InputBox />);
        const { inputRef } = wrapper.instance();
    
        jest.spyOn(inputRef.current, "focus");
    
        wrapper.instance().componentDidMount();
        expect(inputRef.current.focus).toHaveBeenCalledTimes(1);
    });
    

    注意 inputRef.current 属性的使用,它引用了当前分配的 DOM 节点。

    【讨论】:

      【解决方案5】:

      当我使用 mountuseRef 钩子时,这对我有用:

      expect(wrapper.find('input').get(0).ref.current).toEqual(document.activeElement)
      

      【讨论】:

        【解决方案6】:

        通过data-test 属性或类似属性进行选择是我能想到的最直接的解决方案。

        import React, { Component } from 'react'
        import { mount } from 'enzyme'
        
        class MyComponent extends Component {
          componentDidMount() {
            if (this.inputRef) {
              this.inputRef.focus()
            }
          }
        
          render() {
            return (
              <input data-test="my-data-test" ref={input => { this.inputRef = input } } />
            )
          }
        }
        
        it('should set focus on mount', () => {
          mount(<MyComponent />)
          expect(document.activeElement.dataset.test).toBe('my-data-test')
        })
        

        【讨论】:

          【解决方案7】:

          可以使用选择器检查对特定元素的关注。

          const wrapper = mount(<MyComponent />);
          
          const input = wrapper.find('input');
          expect(input.is(':focus')).toBe(true);
          

          【讨论】:

          • 这似乎不受支持。 Enzyme selectors
          • 干净的想法!使用 Enzyme@3.11 为我工作。
          【解决方案8】:

          这应该可以工作

          const wrapper = mount(<MyComponent />);
          
          const input = wrapper.find('input');
          
          expect(input).toHaveFocus();
          

          【讨论】:

            猜你喜欢
            • 2020-08-10
            • 2023-03-06
            • 2017-11-01
            • 2018-09-14
            • 2018-12-16
            • 2018-07-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多