reactjs - 如何模拟/监视在 ReactJS 中调用 ref 的 addEventListener 方法?

标签 reactjs testing jestjs enzyme snapshot

我正在对一个在其 div 上有 ref 的组件进行快照测试。该组件看起来像 -

import React, { PureComponent } from 'react';

class SearchFlightBuilder extends PureComponent {

  scrollRef = React.createRef();

  state = {
    loading: true,
    error: false,
    filteredList: [],
    pageIndex: 0,
    scrollCalled: false,
  };


  handleScroll = (event) => {
    // make sure scroll should be called once
    if ((this.scrollRef.current.scrollTop + this.scrollRef.current.clientHeight >= this.scrollRef.current.scrollHeight) && !this.state.scrollCalled)  {
      this.setState({
          pageIndex: this.state.pageIndex + 1
      });
      this.setState({scrollCalled: true});
    }
  };

  componentDidMount = () => {
    this.scrollRef.current.addEventListener('scroll', this.handleScroll);
  };

  removeScrollEvent = () => {
    this.scrollRef.current.removeEventListener('scroll', this.handleScroll);
  };

  render() {

    return (
      <div className={c('Search-flight-builder')}  ref={this.scrollRef}>
        <p>Hello</P
      </div>
    );
  }
};

export default SearchFlightBuilder;

测试文件看起来像这样 -

import React from 'react';
import { shallow, mount, render } from 'enzyme';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

import SearchFlightBuilder from './SearchFlightBuilder';

configure({ adapter: new Adapter() });

const testFlightBuilder = () => <SearchFlightBuilder />;

describe('SearchFlightBuilder', () => {
  it('should render correctly', () => {
    const component = shallow(<SearchFlightBuilder />);
    expect(component).toMatchSnapshot();
  });


});

当我运行测试时,出现此错误 - TypeError:无法读取 null 的属性“addEventListener”。我尝试了各种方法,但没有一种方法有效。请在这里帮助我。我在这里使用 enzyme 库。

最佳答案

这是我的单元测试策略:

index.tsx:

import React, { PureComponent } from 'react';

class SearchFlightBuilder extends PureComponent {
  scrollRef: any = React.createRef();

  state = {
    loading: true,
    error: false,
    filteredList: [],
    pageIndex: 0,
    scrollCalled: false
  };

  handleScroll = event => {
    // make sure scroll should be called once
    if (
      this.scrollRef.current.scrollTop + this.scrollRef.current.clientHeight >= this.scrollRef.current.scrollHeight &&
      !this.state.scrollCalled
    ) {
      this.setState({
        pageIndex: this.state.pageIndex + 1
      });
      this.setState({ scrollCalled: true });
    }
  };

  componentDidMount = () => {
    this.scrollRef.current.addEventListener('scroll', this.handleScroll);
  };

  removeScrollEvent = () => {
    this.scrollRef.current.removeEventListener('scroll', this.handleScroll);
  };

  render() {
    return (
      <div className="Search-flight-builder" ref={this.scrollRef}>
        <p>Hello</p>
      </div>
    );
  }
}

export default SearchFlightBuilder;

由于 clientHeightscrollHeight 属性是只读的,因此需要使用 Object.defineProperty 模拟它们。

index.spec.tsx:

import React from 'react';
import { shallow } from 'enzyme';
import SearchFlightBuilder from './';

describe('SearchFlightBuilder', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  it('should handle scroll, pageindex + 1', () => {
    const mDiv = document.createElement('div');
    const events = {};
    const addEventListenerSpy = jest.spyOn(mDiv, 'addEventListener').mockImplementation((event, handler) => {
      events[event] = handler;
    });
    mDiv.scrollTop = 1;
    Object.defineProperty(mDiv, 'clientHeight', { value: 1 });
    Object.defineProperty(mDiv, 'scrollHeight', { value: 1 });
    const mRef = { current: mDiv };
    const createRefSpy = jest.spyOn(React, 'createRef').mockReturnValueOnce(mRef);
    const component = shallow(<SearchFlightBuilder />);
    expect(createRefSpy).toBeCalledTimes(1);
    expect(addEventListenerSpy).toBeCalledWith('scroll', component.instance()['handleScroll']);
    events['scroll']();
    expect(component.state('pageIndex')).toBe(1);
    expect(component.state('scrollCalled')).toBeTruthy();
  });
});

带有覆盖率报告的单元测试结果:

PASS  src/stackoverflow/57943619/index.spec.tsx (8.618s)
  SearchFlightBuilder
    ✓ should handle scroll, pageindex + 1 (15ms)

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |    94.44 |    85.71 |       80 |    93.75 |                   |
 index.tsx |    94.44 |    85.71 |       80 |    93.75 |                32 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.916s

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/57943619

关于reactjs - 如何模拟/监视在 ReactJS 中调用 ref 的 addEventListener 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57943619/

相关文章:

javascript - 开 Jest 配置错误 : "Preset @shelf/jest-mongodb not found."

jestjs - :click event 上的 Svelte 单元测试

javascript - 使用 Jest 模拟导入模块中的外部用户模块

javascript - React Routing 在本地机器上工作,但在 Heroku 上不工作

ruby - 模拟文件输入作为 Rspec 上的文件路径

c# - 使用 BackGroundWorker 运行 WatiN 打开 IE 浏览器

java - 自动生成单元测试

javascript - 在 react 钩子(Hook)状态不保留其先前的状态

node.js - babel-node 无法识别 jsx <

javascript - React 有相当于 Vue.set() 的函数吗?