Unit Testing Google Maps API with Jest

On my current project, the goal is to create unit tests for an existing codebase. The project’s main functionalities are based upon the Google Maps API, so to isolate our functions for testing, we needed to create some mocks for that API. We chose Jest as our Javascript testing library not only for its ease of use, but also because there’s a handy Jest-Junit reporter that creates compatible JUnit XML files for Jenkins CI.

We are currently using a modified version of jest-google-maps-mock with some mocks that we updated ourselves. To keep the mock lean, we trimmed and filled it in using only functionalities that our app currently touches.

let createGoogleMapsMock = function createGoogleMapsMock() {
  let maps = {
    InfoWindow: jest.fn().mockImplementation(function () {
    createMVCObject(this);
    createMockFuncsFromArray(this, ['setPosition', 'setContent', 'open', 'close']);
    }),
    Map: jest.fn().mockImplementation(function (mapDiv, opts) {
      this.mapDiv = mapDiv;
      this.opts = opts;
      createMVCObject(this);
      createMockFuncsFromArray(this, ['setCenter', 'setClickableIcons', 'setHeading', 'setMapTypeId', 'setOptions', 'setStreetView', 'setTilt', 'setZoom', 'fitBounds', 'getBounds', 'panTo', 'panToBounds']);
    }),
    Polyline: function Polyline() {},
    Size: function Size() {}
    };
    return maps;
};

Now that the Google Map API mocks are created, we can unit test our own functions. Say we had a simple function, displayInfoByCoord, which will pan the map to a given coordinate and display some information.

displayInfoByCoord(lat, long, info) {
  let googleMap = new google.maps.Map(document.getElementById('map'));
  let infoWindow = new google.maps.InfoWindow();
  googleMap.PanTo({lat: lat, lng: long});
  infoWindow.setPosition({lat: lat, lng: long});
  infoWindow.setContent(info);
  infoWindow.open(this.googleMap);
}

In our unit tests, we need to mock every Google Maps functionality that will be touched. For example, inside the displayInfoByCoord function, four Google Map functionalities need to be instantiated: googleMap.panTo, infoWindow.setPosition, infoWindow.setContent, and infoWindow.open.

let googleMaps = googleMap();
let Map = new googleMaps.Map();
let infoWindow = new googleMaps.InfoWindow();
displayInfoByCoord(34, -92, 'hello')

After that, we can use Jest’s matchers to make sure that the behavior is as expected.

expect(googleMaps.Map).toHaveBeenCalledTimes(1);
expect(infoWindow.setPosition).toHaveBeenCalledTimes(1);
expect(infoWindow.setPosition).toHaveBeenCalledWith({'lat':34, 'lng': -92});
expect(infoWindow.open).toHaveBeenCalledTimes(1);

For the way our codebase is structured, we also needed to mock the global google variable. For that, here’s a handy reference with multiple options to do so. Overall, having our own modified Google mock has proved to be easy to maintain and flexible for mocking the implementation as well.

Happy unit testing!