React-Leaflet:'Invalid LatLng object' on 运行 test when using boundsOptions

React-Leaflet: 'Invalid LatLng object' on running test when using boundsOptions

我使用 react-leaflet 构建了一个简单的应用程序来显示地图。该应用程序本身正在运行,并且地图在浏览器中正确显示。但是,当我尝试使用 react-testing-library 编写测试时,在使用 boundsOptions 时,我在执行中收到 Invalid LatLng object'。如果我删除 boundsOptions 属性 测试将通过。

Map.tsx

import "leaflet/dist/leaflet.css";
import React from "react";
import {
  LayersControl,
  Marker,
  Polyline,
  TileLayer,
  Tooltip,
  Map
} from "react-leaflet";
import './Map.css';

const { BaseLayer } = LayersControl;

const MapWrapper: React.FC = ({ ...props }) => {
  const layers = [
    {
      name: "OpenStreetMap.Mapnik",
      attribution:
        '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
      url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
    }
  ];

  const bounds: [number, number][] = [];

  [...] // Code that calculates the bounds to show (in production)

  if (bounds.length === 0) {
    bounds.push([35, -35]);
    bounds.push([65, 55]);
  }

  return (
      <Map bounds={bounds} boundsOptions={{ padding: [5, 5] }} className="map">
        <LayersControl position="topright">
          {layers.map(layer => {
            return (
              <BaseLayer
                key={layer.url}
                checked={true}
                name={layer.name}
              >
                <TileLayer attribution={layer.attribution} url={layer.url} />
              </BaseLayer>
            );
          })}
        </LayersControl>
      </Map>
  );
};

Map.css

.map {
  height: 400px;
  width: 640px;
}

Map.test.tsx

import React from 'react'
import MapWrapper from './Map';
import {render, fireEvent, cleanup} from '@testing-library/react';

afterEach(cleanup)

test('Simple test', () => {
  const { getByTestId } = render(<MapWrapper />)
})

测试出错

    console.error node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
      Error: Uncaught [Error: Invalid LatLng object: (NaN, NaN)]
          at reportException (C:\Repos\react-leaflet-jest\node_modules\jest-environment-jsdom\node_modules\jsdom\lib\jsdom\living\helpers\runtime-script-errors.js:66:24)
    ...
    console.error node_modules/react-dom/cjs/react-dom.development.js:19814
      The above error occurred in the <TileLayer> component:
          in TileLayer (created by Context.Consumer)

您可以在这里找到代码:https://bitbucket.org/netcoding/react-leaflet-jest/src/master/

如何使用 boundsOptions 设置 react-leaflet 以通过测试?

它似乎是 known issue 并且也可以复制,例如在 Jest 中。出现异常是因为渲染地图时(在测试中)无法正确确定地图容器大小。

解决方案是明确设置地图容器大小,如果react-leaflet library地图容器大小可以这样设置:

const { leafletElement: map } = this.mapRef.current as Map;
const container = map.getContainer(); //get leaflet map container
Object.defineProperty(container, "clientWidth", { value: 800 });
Object.defineProperty(container, "clientHeight", { value: 600 });

这是一个关于如何测试地图边界的完整示例:

test("Map test bounds", () => {
  class TestComponent extends React.Component<any, any> {
    mapRef: React.RefObject<Map>;

    constructor(props: any) {
      super(props);
      this.mapRef = React.createRef();
    }

    componentDidMount() {
      this.updateBoundsOptions();
    }

    resizeContainer(container: HTMLElement) {
      Object.defineProperty(container, "clientWidth", { value: 800 });
      Object.defineProperty(container, "clientHeight", { value: 600 });
    }

    updateBoundsOptions() {
      const { leafletElement: map } = this.mapRef.current as Map;
      const container = map.getContainer(); //get leaflet map container
      this.resizeContainer(container);
      map.fitBounds(this.props.bounds, this.props.boundsOptions);
    }

    render() {
      return (
        <MapWrapper mapRef={this.mapRef}>
          <span />
        </MapWrapper>
      );
    }
  }

  render(
    <TestComponent
      bounds={[[35, -35], [65, 55]]}
      boundsOptions={{ padding: [5, 5] }}
    />
  );
});

其中 MapWrapper 是自定义组件:

export interface MapWrapperProps extends MapProps {
  mapRef?: React.RefObject<Map>;
}

const MapWrapper: React.FC<MapWrapperProps> = ({ ...mapProps }) => {
  return (
    <Map ref={mapProps.mapRef} {...mapProps}>
      <TileLayer
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      />
    </Map>
  );
};