【问题标题】:TypeError: Cannot read property 'scrollIntoView' of null - react. jest enzymeTypeError:无法读取 null 的属性“scrollIntoView” - 做出反应。笑话酶
【发布时间】:2019-02-19 06:25:57
【问题描述】:

使用 react 16.3.1、jest 16.3.1、酶 3.3.0。

在我的 React Class 组件中,我创建了一个 react ref,我使用它来确保在安装组件时浏览器位于页面顶部。

class PageView extends React.Component {

  constructor(props) {
    super(props);
    this.topOfPageRef = React.createRef();
  }

  componentDidMount() {
    ReactDOM.findDOMNode(this.topOfPageRef.current).scrollIntoView();
  }

  render(){
    const { x } = this.props;

    return (
      <React.Fragment>
        <div className="main-wrapper" ref={this.topOfPageRef}>
         Top
        </div>
        )}
      </React.Fragment>
    );
  }
}

这一切都在浏览器中完美运行,但在我的酶测试中失败。

我的测试很简单,它只是尝试渲染组件。

  it('should render component correctly', () => {
    const props = {
      ...defaultProps,
    };
    const wrapper = mount(<PageView {...props} />);
    expect(wrapper).toMatchSnapshot();
  });

TypeError: Cannot read property 'scrollIntoView' of null

我已经尝试了 shallowmount 方法,虽然找到的元素不为空,但它似乎是 HTMLDivElement 的一个反应实例,它缺少 scrollIntoView 方法。

【问题讨论】:

    标签: javascript reactjs testing jestjs enzyme


    【解决方案1】:

    你得到的错误是因为 ReactDOM.findDOMNode 给你返回 null。

    正如 React 文档所说:

    当组件渲染为 null 或 false 时,findDOMNode 返回 null

    还有

    在大多数情况下,您可以将 ref 附加到 DOM 节点并完全避免使用 findDOMNode。

    你不应该使用 React.findDOMNode

    componentDidMount() {
       ReactDOM.findDOMNode(this.topOfPageRef.current).scrollIntoView();
    }
    

    但是:

    componentDidMount() {
       this.topOfPageRef.current.scrollIntoView();
    }
    

    希望它会有所帮助。

    【讨论】:

      【解决方案2】:

      错误信息说明

      在上面的示例代码中使用mount 会出现此错误:

      TypeError: _reactDom2.default.findDOMNode(...).scrollIntoView is not a function

      使用shallow 会出现上面列出的错误:

      TypeError: Cannot read property 'scrollIntoView' of null


      问题

      shallow 不进行 DOM 渲染,因此永远不会有可以调用 scrollIntoView() 的 DOM 节点。

      解决方案

      任何进行 DOM 操作的代码都需要使用mount 提供的完整 DOM 渲染进行测试。


      挂载

      "The default environment in Jest is a browser-like environment through jsdom".

      "jsdom is a pure-JavaScript implementation of many web standards...[that] emulate[s] enough of a subset of a web browser to be useful for testing".

      问题

      jsdom 实现了大部分浏览器环境,但并未实现所有内容。这个问题需要特别注意的是它没有实现scrollIntoView,因为jsdomdoes not do layout and would therefore not be able to provide an accurate implementation

      因为jsdom 没有实现scrollIntoView,它将在jsdom 提供的元素上未定义。

      解决方案

      recommended approach from this Google dev 是在您的测试代码中添加以下行:

      Element.prototype.scrollIntoView = () =&gt; {};

      该行会将scrollIntoView 的noop 实现添加到jsdom-提供的Element

      对于您的测试,您可以更进一步,将 scrollIntoView 设置为 spy 以确保它被调用:

      it('should render component correctly', () => {
        const props = {
          ...defaultProps,
        };
        Element.prototype.scrollIntoView = jest.fn();  // set scrollIntoView to a spy
        const wrapper = mount(<PageView {...props} />);
        expect(wrapper).toMatchSnapshot();
        expect(Element.prototype.scrollIntoView).toHaveBeenCalled();  // PASSES
      });
      

      另外,Antonio 是正确的,你不需要使用ReactDOM.findDOMNode(),你应该可以直接使用this.topOfPageRef.current

      componentDidMount() {
        this.topOfPageRef.current.scrollIntoView();
      }
      

      【讨论】:

      • 我到处都能看到这个修复,但是你是从哪里导入元素的?我得到“未定义元素”我正在使用带有 chai 的酶。
      • @JamesTrickey Element 引用来自 DOM 的 Element 类。 default test environment for Jestjsdom 提供的类似浏览器的环境,它在全局范围内提供Element 类(就像浏览器一样)。
      • 感谢您澄清这一点。我使用的是酶,但不是开玩笑,所以这就是全球不存在的原因。最后将功能提取到传递给组件的“服务”中,以便对其进行模拟。不理想,但停止了错误。伙计们干杯!
      【解决方案3】:

      可以在窗口中设置

        it('should call paginator component', () => {
            window.HTMLElement.prototype.scrollIntoView = jest.fn();
            // arrange
            // act
            // assertion
        })
        
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-20
        • 1970-01-01
        • 2020-04-27
        • 2021-11-21
        • 1970-01-01
        • 2021-12-25
        • 2019-04-25
        • 2018-10-29
        相关资源
        最近更新 更多