如何在 vue.js 单元测试中模拟 window.google
How to mock window.google in a vue.js unit test
我正在尝试测试显示 google 地图的 vue 组件
google include 脚本元素位于父组件中的某处,我尝试测试的组件是全局引用它的:
const googleInstance = window.google
当我看到它是全球性的时,我的警钟响了,但这是我得到的代码,我需要提高我的覆盖率!
组件中的代码在此处获取实例:
this.map = new googleInstance.maps.Map(mapElement, this.options)
我收到很多错误开头:
TypeError: Cannot read property 'maps' of undefined
我尝试在浅安装包装器时将 googleInstance 和 google 添加到 mocks 参数
const wrapper = shallowMount(Map, {
mocks: {
google: {
maps: () => {}
}
}
})
都没有用,我得到了相同的回复:
TypeError: Cannot read property 'maps' of undefined
我试过了:
global.google = {
maps: () => {}
}
那也没用
这是我要测试的地图组件的简化版本:
<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>
代码已经重构,之前 google 实例来自 Vuex 商店,我的测试有效
我的另一个想法是 return google从一个单独的文件实例化,然后我可以使用 jest 模拟它,但最终这只会将问题转移到另一个仍然无法测试的文件
如何模拟组件中的值或如何重构代码以使其可测试?
问题是你的const googleGlobal = window.google
语句在你引入测试文件中的mock之前就被执行了
因此,googleGlobal
常量等于 undefined
。一个解决方案是在您的组件中定义一个方法,该方法 returns 全局变量 google
,并通过调用此方法获取引用。
<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>
然后,在您的测试文件中,您可以像这样模拟 window.google
:
window.google = {
maps: { Map: function() {} }
}
通过尝试上述解决方案,我遇到了错误
> google.maps.map 不是构造函数
但是这个嘲讽奏效了。
window.google = {
maps: {
Map: jest
.fn()
.mockImplementationOnce(success => Promise.resolve(success))
}
};
在为您的组件定义包装器之前,将 属性 添加到全局对象
let google = <some object>;
Object.defineProperty(global, 'google', {
value: google
})
const wrapper = ...
我正在尝试测试显示 google 地图的 vue 组件
google include 脚本元素位于父组件中的某处,我尝试测试的组件是全局引用它的:
const googleInstance = window.google
当我看到它是全球性的时,我的警钟响了,但这是我得到的代码,我需要提高我的覆盖率!
组件中的代码在此处获取实例:
this.map = new googleInstance.maps.Map(mapElement, this.options)
我收到很多错误开头:
TypeError: Cannot read property 'maps' of undefined
我尝试在浅安装包装器时将 googleInstance 和 google 添加到 mocks 参数
const wrapper = shallowMount(Map, {
mocks: {
google: {
maps: () => {}
}
}
})
都没有用,我得到了相同的回复:
TypeError: Cannot read property 'maps' of undefined
我试过了:
global.google = {
maps: () => {}
}
那也没用
这是我要测试的地图组件的简化版本:
<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>
代码已经重构,之前 google 实例来自 Vuex 商店,我的测试有效
我的另一个想法是 return google从一个单独的文件实例化,然后我可以使用 jest 模拟它,但最终这只会将问题转移到另一个仍然无法测试的文件
如何模拟组件中的值或如何重构代码以使其可测试?
问题是你的const googleGlobal = window.google
语句在你引入测试文件中的mock之前就被执行了
因此,googleGlobal
常量等于 undefined
。一个解决方案是在您的组件中定义一个方法,该方法 returns 全局变量 google
,并通过调用此方法获取引用。
<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>
然后,在您的测试文件中,您可以像这样模拟 window.google
:
window.google = {
maps: { Map: function() {} }
}
通过尝试上述解决方案,我遇到了错误
> google.maps.map 不是构造函数
但是这个嘲讽奏效了。
window.google = {
maps: {
Map: jest
.fn()
.mockImplementationOnce(success => Promise.resolve(success))
}
};
在为您的组件定义包装器之前,将 属性 添加到全局对象
let google = <some object>;
Object.defineProperty(global, 'google', {
value: google
})
const wrapper = ...