最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to mock window.google in a vue.js unit test - Stack Overflow

programmeradmin0浏览0评论

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 mocking global.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
Add a ment  | 

3 Answers 3

Reset to default 5

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 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 = ...
发布评论

评论列表(0)

  1. 暂无评论