Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock window.google in a vue.js unit test

I am trying to test a vue component that displays a google map

The google include script element is somewhere in a parent component and the component I am trying to test gets is reference to it globally:

const googleInstance = window.google

My alarm bells rang when I saw it is global, but its the code I have been given and I need to get my coverage higher!

The code in the component gets the instance here:

this.map = new googleInstance.maps.Map(mapElement, this.options)

I get many errors starting with:

TypeError: Cannot read property 'maps' of undefined

I have tried adding googleInstance and google to the mocks parameter when shallow mounting the wrapper

const wrapper = shallowMount(Map, {
  mocks: {
    google: {
      maps: () => {}
    }
  }
})

Neither worked and I get the same response:

TypeError: Cannot read property 'maps' of undefined

I tried:

global.google = {
  maps: () => {}
}

That did not work either

Here is a simplified version of the map component that I am trying to test:

<template>
<div>
  <div refs="mapLayer" :id="mapName" class="mapLayer" />
</div>
</template>
<script>
const googleGlobal = window.google

export default {
  name: 'Map',
  props: {
    name: {
      type: String,
      required: true
    }
  },
  mounted () {
    this.initMap()
  },
  methods: {
    initMap () {
      const mapElement = document.getElementById(this.mapName)
      this.map = new googleGlobal.maps.Map(mapElement)
    }
  }
}
</script>

The code has been refactored and previously the google instance came via the Vuex store and my tests worked

My other thought was to return googleInstance from a separate file, which I could then mock using jest, but ultimately that just moves the problem to another file that would still be untestable

How can I mock the values in my component or how could the code be refactored to be testable?

like image 771
Barnaby Avatar asked May 03 '19 11:05

Barnaby


1 Answers

The problem is that your const googleGlobal = window.google sentence is being executed before you introduce the mock in the test file.

Because of this, the googleGlobal constant is equal to undefined. A solution for this could be to define a method in your component that returns the global variable google, and obtain the reference by calling this method.

<script>
export default {
    name: 'Map',
    props: {
        name: {
            type: String,
            required: true
        }
    },
    mounted () {
        this.initMap()
    },
    methods: {
        getGoogle() {
            return window.google
        },
        initMap () {
            const googleGlobal = this.getGoogle()
            const mapElement = document.getElementById(this.mapName)
            this.map = new googleGlobal.maps.Map(mapElement)
        }
    }
}
</script>

Then, in your test file you can mock window.google like:

window.google = {
    maps: { Map: function() {} }
}
like image 64
mgarcia Avatar answered Nov 11 '22 15:11

mgarcia