13

Consider we have the following Map component. This is in TypeScript, but the same should apply for normal JavaScript.

import * as React from 'react';
import ReactMapboxGl from 'react-mapbox-gl';

const MapBox = ReactMapboxGl({
  accessToken: 'pk.<redacted>'
});

export default class Map extends React.Component {
  render() {
    return (
      <MapBox
        style="mapbox://styles/mapbox/streets-v9"
        zoom={[0]}
        containerStyle={{
          height: '500px',
          width: 'inherit'
        }}
      />);
  }
}

It is then part of some react application that is rendered as such:

import * as React from 'react';

export default class App extends React.Component {
  render() {
    return (
          <Map />
    );
  }
}

In order to test this setup we use Jest and JSDOM.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
});

This test will fail to run and produce the following output:

    TypeError: window.URL.createObjectURL is not a function

      at Object.254.../../source/worker (node_modules/mapbox-gl/dist/mapbox-gl.js:509:100)
      at s (node_modules/mapbox-gl/dist/mapbox-gl.js:1:711)
      at node_modules/mapbox-gl/dist/mapbox-gl.js:1:762
      at Object.280.../ (node_modules/mapbox-gl/dist/mapbox-gl.js:561:28)
      at s (node_modules/mapbox-gl/dist/mapbox-gl.js:1:711)
      at node_modules/mapbox-gl/dist/mapbox-gl.js:1:762
      at Object.263../worker_pool (node_modules/mapbox-gl/dist/mapbox-gl.js:527:29)
      at s (node_modules/mapbox-gl/dist/mapbox-gl.js:1:711)
      at node_modules/mapbox-gl/dist/mapbox-gl.js:1:762
      at Object.191.../render/glyph_manager (node_modules/mapbox-gl/dist/mapbox-gl.js:383:809)
      at s (node_modules/mapbox-gl/dist/mapbox-gl.js:1:711)
      at node_modules/mapbox-gl/dist/mapbox-gl.js:1:762
      at Object.248.../geo/lng_lat (node_modules/mapbox-gl/dist/mapbox-gl.js:497:338)
      at s (node_modules/mapbox-gl/dist/mapbox-gl.js:1:711)
      at node_modules/mapbox-gl/dist/mapbox-gl.js:1:762
      at Object.72.../package.json (node_modules/mapbox-gl/dist/mapbox-gl.js:144:148)
      at s (node_modules/mapbox-gl/dist/mapbox-gl.js:1:711)
      at e (node_modules/mapbox-gl/dist/mapbox-gl.js:1:882)
      at node_modules/mapbox-gl/dist/mapbox-gl.js:1:900
      at Object.<anonymous>.i (node_modules/mapbox-gl/dist/mapbox-gl.js:1:177)
      at Object.<anonymous> (node_modules/mapbox-gl/dist/mapbox-gl.js:1:413)
      at Object.<anonymous> (node_modules/react-mapbox-gl/lib/map.js:21:16)
      at Object.<anonymous> (node_modules/react-mapbox-gl/lib/index.js:3:13)
      at Object.<anonymous> (src/Map.tsx:14:25)
      at Object.<anonymous> (src/NewOrder.tsx:21:13)
      at Object.<anonymous> (src/Routes.ts:17:18)
      at Object.<anonymous> (src/App.tsx:16:16)
      at Object.<anonymous> (src/App.test.tsx:6:169)
          at <anonymous>

The question to you, my dear reader, is simply: Is it possible to work around this issue? Are there seams we can use to inject a mocked MapBoxGL library?

I've found multiple issues on GitHub related to this problem but none of them provide a solution: 1, 2. Some points toward using mapbox-gl-js-mock while others claim it is of no use since it too will require a real browser to run.

There is also the related issue on the JSDOM project about adding URL.createObjectURL which would perhaps resolve the underlying issue.

Rovanion
  • 4,382
  • 3
  • 29
  • 49

4 Answers4

14

I had the same issue and when i added the below code as listed here to the top of my test block it worked.

jest.mock('mapbox-gl/dist/mapbox-gl', () => ({
   Map: () => ({})
}));
meteor
  • 2,518
  • 4
  • 38
  • 52
  • 3
    [This issue](https://github.com/mapbox/mapbox-gl-js/issues/3436) is also relevant. In particular, I had to go a bit further (as [this comment](https://github.com/mapbox/mapbox-gl-js/issues/3436#issuecomment-485535598) suggests) before I had a working setup. – maltem-za Jul 25 '19 at 08:52
8

You can add this to your test entry file for setupTest.ts

jest.mock('mapbox-gl/dist/mapbox-gl', () => ({
  GeolocateControl: jest.fn(),
  Map: jest.fn(() => ({
    addControl: jest.fn(),
    on: jest.fn(),
    remove: jest.fn(),
  })),
  NavigationControl: jest.fn(),
}));
Morlo Mbakop
  • 3,518
  • 20
  • 21
0

You can mock the entire map with a custom element like this:

jest.mock('react-mapbox-gl', () => ({
  __esModule: true,
  default: () => function () {
    return <span>Mock map</span>;
  },
  Cluster: () => <span>Mock cluster</span>,
}));
Mareș Ștefan
  • 430
  • 1
  • 4
  • 13
-1

If your are using import and typescript:

jest.mock('mapbox-gl/dist/mapbox-gl', () => {
  return {
    'default': {
      accessToken: '',
      GeolocateControl: jest.fn(),
      Map: jest.fn(() => ({
        addControl: jest.fn(),
        on: jest.fn(),
        remove: jest.fn(),
        fitBounds: jest.fn(),
      })),
      NavigationControl: jest.fn(),
    }
  }
});
Seb
  • 99
  • 1
  • 5