Search code examples
javascriptvue.jsjestjsvue-test-utils

Correctly testing an event handler in Vue component


I have a component with an anchor tag with an associated handler, onSelectLink().

<a
  :href="$t('footer.termsUrl')"
  target="_blank"
  name="termsAndConditions"
  @click="onSelectLink($event.target.name)">{{ $t('terms') }}</a>

The onSelectLink() function...

onSelectLink (buttonName) {
      buttonName === 'termsAndConditions'
        ? this.logButtonClick(ANALYTICS.TERMS_AND_CONDITIONS)
        : this.logButtonClick(ANALYTICS.PRIVACY_POLICY)
    }

My unit test

describe('onSelectLink()', () => {
    it('[positive] should track analytics when user selects `Terms and Conditions` link', () => {
      const buttonName = 'termsAndConditions'
      jest.spyOn(wrapper.vm, 'onSelectLink')

      wrapper.find('a').trigger('click')
      wrapper.vm.onSelectLink(buttonName)

      expect(wrapper.vm.logButtonClick).toHaveBeenCalledWith(ANALYTICS.TERMS_AND_CONDITIONS)
    })

    it('[positive] should track analytics when user selects `Privacy Policy` link', () => {
      const buttonName = 'privacyPolicy'
      jest.spyOn(wrapper.vm, 'onSelectLink')

      wrapper.find('a').trigger('click')
      wrapper.vm.onSelectLink(buttonName)

      expect(wrapper.vm.logButtonClick).toHaveBeenCalledWith(ANALYTICS.PRIVACY_POLICY)
    })

My questions are:

  1. Are these tests each invoking onSelectLink() twice?

  2. Do I actually need to use "wrapper.find('a').trigger('click')"

  3. Is this a good/robust test to make sure onSelectLink() is called with right argument?

When I comment out "wrapper.find('a').trigger('click')" the test still seem to pass. I thought I had to trigger the DOM event and then call the handler.


Solution

  • You're currently triggering the onSelectLink twice in each test.

    Once by

    wrapper.find('a').trigger('click') // normal flow
    

    and once by

    wrapper.vm.onSelectLink(buttonName) // you run `onSelectionLink` directly on vm
    

    The second one is wrong, in principle. You don't want to trigger the method by calling it directly on vm, because your users can't do that.
    The only way they can do it is by clicking the link and that's what you should test.

    const logger = jest.spyOn(wrapper.vm, 'logButtonClick')
    expect(logger).not.toHaveBeenCalled();
    wrapper.find('a[name="termsAndConditions"]').trigger('click')
    expect(logger).toHaveBeenCalledWith(ANALYTICS.TERMS_AND_CONDITIONS);
    

    Remember you can always use console.log() in your tests and you'll see the logged values in CLI and figure out what's going on.