首页 > 解决方案 > 如何模拟 React componentWillUnmount 中使用的构造函数

问题描述

我正在尝试使用 mapbox-gl 并使用 Jest 和 react-testing-library 来测试 React 组件。在组件内部,我使用 mapbox 构造函数并将实例分配给this.map In componentWillUnmount 调用this.map.remove(),这会导致测试出错。

组件代码

import React, { Component } from "react";
import mapboxgl from "mapbox-gl";
import "./Map.css";

class Map extends Component {
  constructor(props) {
    super(props);
    this.map = null;
    this.mapContainer = React.createRef();
  }

  componentDidMount() {
    this.map = new mapboxgl.Map({
      container: this.mapContainer.current,
      style: "mapbox://styles/mapbox/streets-v11",
      center: [37.61513, 55.7513461], 
      zoom: 11,
    });
  }

  componentWillUnmount() {
    this.map.remove();
  }

  render() {
    return (
      <div
        data-testid="map"
        className="map-container"
        ref={this.mapContainer}
      />
    );
  }
}

export default Map;

尝试对其进行测试,例如:

import Map from "../../page/Map/Map";
import React from "react";
import renderer from "react-test-renderer";
import { render } from '@testing-library/react'
import mapboxgl from "mapbox-gl";

jest.mock('mapbox-gl', () => ({
    Map: jest.fn(() => ({
        remove: jest.fn()
    })),
}));

describe('Map.js', () => {    
    it('should call mapbox-gl', function () {
        const { getByTestId } = render( <Map />);
        expect(mapboxgl.Map).toHaveBeenCalledWith({
            container: getByTestId('map'),
            style: "mapbox://styles/mapbox/streets-v11",
            center: [37.61513, 55.7513461],
            zoom: 11,
        });
    });
})

并得到这个错误:

Map.js › 应该调用 mapbox-gl

TypeError: this.map.remove is not a function

  22 |
  23 |   componentWillUnmount() {
> 24 |     this.map.remove();
     |              ^
  25 |   }
  26 |
  27 |   render() {

标签: reactjsjestjsreact-testing-library

解决方案


根据jest docs ,

jest.fn()返回一个新的、未使用的模拟函数。可选地采用模拟实现。

在此处输入图像描述

jest.fn()rerurns 是没有构造函数的间谍函数,因此您将无法使用 为 (mapbox-gl.Map) 创建对象new,因此没有调用remove或等属性。

jest.mock('mapbox-gl', () => ({
    Map: jest.fn(() => ({ -> is mocked function and it doesn't have a constructor 
        remove: jest.fn()
    })),
}));

要模拟模块,您需要使用jest.mock,如下所示。

jest.mock('mapbox-gl')将自动模拟mapbox-gl并返回一个包装好的间谍对象的属性。


推荐阅读