papillon
papillon

Reputation: 2053

How do I test a watcher on a tool that was imported in my component?

I use an instance of a class as a tool in one of my components. This component watches for changes in the class instance. However I fail at writing a test for that watcher.

I tried using jest.fn, spyOn and a setData, but none of these worked.

The class looks like this:

export default class myTool {
    constructor () {
        this._myData = null
    }

    get myData () {
        return this._myData
    }

    set myData (updatedMyData) {
        this._myData = updatedMyData
    }
}

And the component:

import myTool from '@/utils/myTool'
export default {
    ...
    data() {
        return {
            myTool: null
        }
    },
    methods: {
        handleMyDataUpdate(updatedMyData) {
            // do something
        }
    },
    mounted() {
        this.$watch('myTool.myData', (updatedMyData) => {
            this.handleMyDataUpdate(updatedMyData)
        })
        this.myTool = new myTool()
    }
    ...
}

1st attempt with jest.fn:

test:

it('should call handleMyDataUpdate on myData update.', () => {
    const wrapper = mountComponent()
    const handleMyDataUpdate = jest.fn()
    wrapper.setMethods({ handleMyDataUpdate })
    wrapper.vm.myTool.myData = 5
    expect(handleMyDataUpdate).toBeCalled()
})

2nd attempt with spyOn:

test:

it('should call handleMyDataUpdate on myData update.', () => {
    const wrapper = mountComponent()
    const spy = jest.spyOn(wrapper.vm, 'handleMyDataUpdate')
    wrapper.vm.myTool.myData = 5
    expect(spy).toBeCalled();
}

3rd attempt with setData:

test:

it('should call handleMyDataUpdate on myData update.', () => {
    const wrapper = mountComponent()
    const handleMyDataUpdate = jest.fn()
    wrapper.setMethods({ handleMyDataUpdate })
    wrapper.setData({
        myTool: {
            myData: 5
        }
    })
    expect(handleMyDataUpdate).toBeCalled()
}

Result: the 3 things I tried always fail with the following reason: Expected mock function to have been called., whether I comment the line where myData is updated or not.

Other things that I tried:

I tried wrapping the expect line within a $nextTick, but it doesn't work either:

wrapper.vm.$nextTick(() => {
    // expectation
    done()
})

The following error outputs and the test is always considered as "passed", whereas it should be "failed":

console.error node_modules/vue/dist/vue.runtime.common.js:1739
{ Error: expect(jest.fn()).toBeCalled()

Looking at line 1739 of vue.runtime.common.js didn't help.

So how do I do to test my watcher?

Upvotes: 2

Views: 571

Answers (1)

tony19
tony19

Reputation: 138226

The issue is your _myData in the myTool class is initially undefined, so it's not reactive. To resolve the issue, initialize _myData in myTool's constructor:

class myTool {
  constructor() {
    this._myData = null
  }
  // ...
}

Then, your "1st attempt" test should pass successfully.

demo

Upvotes: 1

Related Questions