Search code examples
javascriptvue.jsjestjsvue-test-utils

How should I correctly trigger a change event to fire a function in unit test?


I have a checkbox component and due to a Safari bug, I changed the

@input=input() to @change='input'

because Safari does not have an input event.

checkbox

<template>
  <div
    class="checkbox">
    <input
      ....
      @change="input">
  </div>
</template>

<script>
export default {
  ....
  methods: {
    input () {
      /**
       * Input event on change
       *
       * @event input
       * @type {Boolean}
       */
      this.$emit('input', this.$refs.checkbox.checked)
    }
  }
}
</script>

unit test

  describe('...', () => {
    beforeEach(async () => {
      const input = wrapper.find('input')

      jest.spyOn(wrapper.vm, 'input')
      input.trigger('change') // told this is incorrect

      jest.runAllTimers()
    })

    it('[positive] should emit an input event with the input\'s value', () => {
      expect(wrapper.emitted().input).toBeTruthy()
      expect(wrapper.emitted().input).toHaveLength(1)
      expect(wrapper.emitted().input[0]).toEqual([false])
    })

    it('[positive] should call the input() method with the target value', () => {

     // this is wrong also, because the expectation will always be true
     wrapper.vm.input() 
     expect(wrapper.vm.input).toHaveBeenCalled()
    })
  })

How should I correctly setup the second test? Why is input.trigger('change') wrong in the unit test?


Solution

  • My second test was setup to always be true. I call the function

    wrapper.vm.input()
    

    and then make the assertion that it will be called, this will aways be true so it was a bad test.

    input.trigger('change')
    

    ...is correct, it was just where I had it. Here is my refactored test:

      describe('when the checkbox state is changed', () => {
        let input
        beforeEach(() => {
          input = wrapper.find('input')
          jest.spyOn(wrapper.vm, 'input')
          jest.runAllTimers()
        })
    
        it('[positive] should emit an input event with the input\'s value', () => {
          input.trigger('change')
          expect(wrapper.emitted().input).toBeTruthy()
          expect(wrapper.emitted().input).toHaveLength(1)
          expect(wrapper.emitted().input[0]).toEqual([false])
        })
        it('[negative] should not emit an input event with the input\'s value', () => {
          input.trigger('input')
          expect(wrapper.emitted().input).toBeFalsy()
        })
      })