Kevin T.
Kevin T.

Reputation: 758

How to mock a plugin in Jest

My unit test is not setup properly, meaning that I am not correctly mocking my imported plugin function.

How do I correctly mock my logData function? In the plugin the function returns undefined and that is by choice. I just need to make sure I console.log whatever is passed to it.

The current error I get is "Cannot spy the logData property because it is not a function; undefined given instead"

logData.js - the plugin (just a wrapper around console.log statements)

export function logData (dataToLog) {
  const isLoggingData = localStorage.getItem('isLoggingData')
  if (isLoggingData) {
    console.log(dataToLog)
  }
}

export default {
  install: function (Vue) {
    Vue.prototype.$logData = logData
  }
}

logData.spec.js - I mocked localStorage but I need to mock the plugin logData

import Vue from 'vue'
import { createLocalVue } from '@vue/test-utils'
import logData from './logData'

class LocalStorageMock {
  constructor () {
    this.store = {}
  }
  getItem (key) {
    return this.store[key] || null
  }
  setItem (key, value) {
    this.store[key] = value.toString()
  }
  removeItem (key) {
    delete this.store[key]
  }
}

global.localStorage = new LocalStorageMock()

const localVue = createLocalVue()
const dataToLog = 'data to be logged'
localVue.use(logData)

const mockLogDataFunction = jest.spyOn(localVue.prototype, 'logData')

describe('logData plugin', () => {
  // PASSES
  it('adds a $logData method to the Vue prototype', () => {
    console.log(wrapper.vm.$logData)
    expect(Vue.prototype.$logData).toBeUndefined()
    expect(typeof localVue.prototype.$logData).toBe('function')
  })
  // Now passes
  it('[positive] console.logs data passed to it', () => {
    global.localStorage.setItem('isLoggingData', true)
    const spy = jest.spyOn(global.console, 'log')
    localVue.prototype.$logData('data to be logged')
    expect(spy).toHaveBeenCalledWith(dataToLog)
    // expect(mockLogDataFunction).toHaveBeenCalled()
    // console.log(localVue)
    // expect(localVue.prototype.$logData(dataToLog)).toMatch('data to be logged')
  })
  // PASSES
  it('[negative] does not console.log data passed to it', () => {
    const spy = jest.spyOn(global.console, 'log')
    global.localStorage.removeItem('isLoggingData')
    localVue.prototype.$logData(dataToLog)
    expect(spy).not.toHaveBeenCalled()

    // const spy = jest.spyOn(this.$logData, 'console')
    // expect(localVue.prototype.$logData(dataToLog)).toBe(und efined)
    // expect(spy).toBe(undefined)
  })
})

Upvotes: 2

Views: 4249

Answers (1)

Andrew Vasylchuk
Andrew Vasylchuk

Reputation: 4779

You are doing things wrong.

  1. jest.spyOn(object, methodName). You need to pass localVue.prototype and 'logData', as arguments, to track if this method was called.

Creates a mock function similar to jest.fn but also tracks calls to object[methodName]. Returns a Jest mock function.

  1. To check if method was called – expect(spy).toHaveBeenCalled().

So change some lines of your code:

const mockLogDataFunction = jest.spyOn(localVue.prototype, '$logData')
// invoke it and then ensure that that method is really called
localVue.prototype.$logData('foo')
expect(mockLogDataFunction).toHaveBeenCalled()

Upvotes: 1

Related Questions