Mocking methods on a Vue instance during TDD Mocking methods on a Vue instance during TDD vue.js vue.js

Mocking methods on a Vue instance during TDD


Solution 1: jest.spyOn(Component.methods, 'METHOD_NAME')

You could use jest.spyOn to mock the component method before mounting:

import MyComponent from '@/components/MyComponent.vue'describe('MyComponent', () => {  it('click does something', async () => {    const mockMethod = jest.spyOn(MyComponent.methods, 'doSomething')    await shallowMount(MyComponent).find('button').trigger('click')    expect(mockMethod).toHaveBeenCalled()  })})

Solution 2: Move methods into separate file that could be mocked

The official recommendation is to "abstract the hard parts away", and use Jest's various mocking mechanisms to mock the abstracted module invoked by the component under test.

For example, to verify a click-handler is invoked:

  1. Move the click-handler's body into a shared JavaScript file.
  2. Import the shared module into the component under test and in your tests (make sure to use the same import path in both cases).
  3. Call jest.mock() to mock the exported functions of the shared module.
  4. Reset the mock in your test suite's beforeEach(). This might only be necessary when there are multiple tests in the suite.
// @/components/MyComponent/utils.jsexport function doSomething() { /*...*/ } //1️⃣// @/components/MyComponent/MyComponent.vue (<script>)import { doSomething } from '@/components/MyComponent/utils' //2️⃣export default {  methods: {    onClick() {      doSomething() //1️⃣    }  }}// @/test/MyComponent.spec.jsimport { doSomething } from '@/components/MyComponent/utils' //2️⃣jest.mock('@/components/MyComponent/utils') //3️⃣describe('MyComponent', () => {  beforeEach(() => doSomething.mockClear()) //4️⃣  it('click does something', async () => {    await shallowMount(MyComponent).find('button').trigger('click')    expect(doSomething).toHaveBeenCalled()  })})

Solution 3: setMethods() (pre v1.0)

Use setMethods() (deprecated as of v1.0) to overwrite a component method:

describe('MyComponent', () => {  it('click does something', async () => {    // Option A:    const mockMethod = jest.fn()    const wrapper = shallowMount(MyComponent)    wrapper.setMethods({ doSomething: mockMethod })    await wrapper.find('button').trigger('click')    expect(mockMethod).toHaveBeenCalled()    // Option B:    const mockMethod = jest.fn()    const wrapper = shallowMount(MyComponent, {      methods: {        doSomething: mockMethod      }    })    await wrapper.find('button').trigger('click')    expect(mockMethod).toHaveBeenCalled()  })})

demo


As tony19 mentioned, using the spyOn method will work for you. I have also found that I need to add parentheses () to the method in the template in order for it to be picked up. I got the tests to pass with the following files:

ButtonComponent.vue

<template>  <button @click="method()">Click me</button></template><script>export default {  methods: {    method() {      // Have I been called?    }  }}</script>

ButtonComponent.spec.js

import ButtonComponent from '@/components/ButtonComponent'import { shallowMount } from '@vue/test-utils'it('will call the method when clicked', () => {  const wrapper = shallowMount(ButtonComponent)  const mockMethod = jest.spyOn(wrapper.vm, 'method')  const button = wrapper.find('button')  button.trigger('click')  expect(mockMethod).toHaveBeenCalled()  // passes})