I am trying to test a vue ponent that displays a google map
The google include script element is somewhere in a parent ponent and the ponent 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 ponent 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 ponent 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 ponent or how could the code be refactored to be testable?
I am trying to test a vue ponent that displays a google map
The google include script element is somewhere in a parent ponent and the ponent 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 ponent 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 ponent 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 ponent or how could the code be refactored to be testable?
Share Improve this question edited May 6, 2019 at 10:16 Barnaby asked May 3, 2019 at 11:03 BarnabyBarnaby 9771 gold badge15 silver badges24 bronze badges 4-
What is the error you are experiencing when you try the approach of setting
global.google
? – mgarcia Commented May 4, 2019 at 21:27 - Thanks for responding @mgarcia It just give the the same response as if the global was not there - its most frustrating! – Barnaby Commented May 5, 2019 at 13:54
-
So you are getting the same
TypeError
error when mockingglobal.google
? Could you share more code of your ponent? – mgarcia Commented May 6, 2019 at 8:32 - @mgarcia I have added a simplified version of the ponent as requested - the rest is mainly a search element and style. The point is that it had worked previously and my problem is mocking the constant for googleGlobal, which I don't think I can do or getting a mock function that will return it from window.google when it is called in the init function called when the ponent mounts. – Barnaby Commented May 6, 2019 at 10:21
3 Answers
Reset to default 5The 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 ponent 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() {} }
}
By trying above solution i was getting the error
> google.maps.map is not a constructor
But this mocking worked.
window.google = {
maps: {
Map: jest
.fn()
.mockImplementationOnce(success => Promise.resolve(success))
}
};
Before defining the wrapper for your ponent, add a property to the global object
let google = <some object>;
Object.defineProperty(global, 'google', {
value: google
})
const wrapper = ...