Search code examples
javascriptunit-testingsinonbootstrap-vuevue-test-utils

How to test if a function is called when I submit a form with sinon?


intro:

I want to test that if I click on the submit button, the onSubmit function is called. I assume this is possible from what I understand when I read the documentation:

  1. https://sinonjs.org/releases/v6.1.5/spies/
  2. https://vue-test-utils.vuejs.org/guides/#testing-key-mouse-and-other-dom-events

expected output:

  • get the test to run and show me either pass or fail

actual output:

  • none, I'm currently stuck at the following:

context:

in my test:

import NavBar from '@/components/layout/NavBar.vue'

in that component I have a (simplified version here) form:

<b-nav-form @submit="onSubmit"> <b-form-input /> <b-button type="submit">Search</b-button> </b-nav-form>

I want to test that if I click on the submit button, the onSubmit function is called.

My setup is Vue, BootstrapVue and Sinon. I understand I have to setup a spy that listens to a function being called.

This is the actual script in my component if that is helpful:

<script>
  export default {
    data () {
      return {
        query: ''
      }
    },
    methods: {
      onSubmit () {...}
    }
  }
</script>

example that I understand:

it('a true example', () => {
    var f = {
      onSubmit: function(query) {
        this.query = query;
      }
    }
    var onSubmitSpy = sinon.spy(f, 'onSubmit');
    f.onSubmit('Club')

    console.log(onSubmitSpy.callCount); // is 1
    onSubmitSpy.restore();
  })

But this is not connected to for example clicking on the button in the form.

Please advise


Solution

  • The idea to test functions of vue components to have been called is to:

    1. Create testing components with vue-test-utils mount or shallowMount.

    2. Pass a methods param in the options to provide spies.

    3. Perform actions in the component that calls the spied method, then assert the method was really called.

    I don't have sinon experience, am only used to test vue components with jest, but the thing should be something like the following:

      import NavBar from '@/components/layout/NavBar.vue'
      import {shallowMount} from 'vue-test-utils';
    
      it('asserting onSubmit calls', () => {
    
        // given
    
        var onSubmit = sinon.spy();
        var wrapper = shallowMount(NavBar, {
          methods: {
            onSubmit();
          }
        });
        var vm = wrapper.vm;
    
        // when
        vm.onSubmit();
    
        // then (I dont really dont know if this is valid sinon syntax)
        assertTrue(onSubmit.called);
        // or, with jest syntax:
        // expect(onSubmit).toHaveBeenCalled(); 
    
      })
    

    Now, the code snippet should work, but there are problems with this test: we are asserting that when we call the component onSubmit, the onSubmit spy gets called. This is not the great thing.

    Your test would probably need to assert somehing like: when the <b-nav-form> component emits a submit event, then the onSubmit spy gets called.

    That would be a more complex test, for two reasons:

    1. Because a child component is involved. To really render child components in a vue-test-utils test, you need to use mount instead of shallowMount. This is difficult as you need to provided childs props and dependencies, so get used to the shallowMount and mount differences.

    2. When you start testing events, chances are some synchrony is involved, so you need to wait for the event to propagate and get your component method called. This usually involves to pass done callback to it() blocks.