How to create a reliable and well tested application effectively? Think Vue.js

WEDNESDAY, FEBRUARY 26, 2020 11:50 PM    

Utilizing vue-test-utils, as I was figuring out how to start my learning journey to make sense of UI component testing. You gradually become what you seek to achieve. If your goal is wrong, you will soon you find yourself in a place you do not want to be. That is the power of clarity.


In test, it is important for you to have a clear end goal in mind. In the realm of testing,there is a vast amount of test you can possibly do, that goal brings clarity on what tasks are meaningful for you. For UI Component testing, we seek for most effective methods to test (testing truly what is important) and least maintenance required.


From that angle, we do not seek to achieve line-by-line coverage; this will lead to brittle tests that requires high maintenance effort.


Assert component’s public interface, and treat the internals as a blackbox


Frontend Vue component unit testing


Reference: https://lmiller1990.github.io/vue-testing-handbook


Example


For example, if you have a counter component, your test case would simulate a button click to increment counter by 1, and assert that counter increased by 1. It should not be concerned by how the counter value was increment, only caring about input and output. The benefit of this approach is that as long as the public interface is correct, your test will pass however times the internal implementation may change.


Scope of component unit test


As much as possible, you wish to test only the component and not the child components within. Thus the type of tests can generally include:


  • Testing props

  • This can test that the component renders the correct elements BASED ON the prop that is passed in.

  • Testing computed properties

    • Test the computed properties, that rely on props (input), returns correctly ‘transformed’ data (output) - Remember, test the public interface (be concerned only about the input and output), not the internal implementations.

  • Simulating user inputs to get expected output messages or output behavior

  • Render other components (but NOT the logic of those child components - that is left to that component’s unit test)

  • Emitting the correct events with correct parameters

Testing computed properties


There are two ways to test computed properties:


  1. use the shallowmount text() method

    const wrapper = shallowMount(NumberRenderer, {

      propsData: {
        even: true
      }
    })

    expect(wrapper.text()).toBe("2, 4, 6, 8")

  1. use the call method

    it("renders odd numbers", () => {
      const localThis = { even: false }
    
      expect(NumberRenderer.computed.numbers.call(localThis)).toBe("1, 3, 5, 7, 9")
    })
    

    Upon a mount, Vue automatically binds props to this, but since we did not mount, there’s no binding. By using call,it lets us bind alternative this object to the prop that was passed through.


    You can use this method if you wish to avoid life-cycle method operations that are unnecessary for the test case at hand. Either that, if you wish to stub out the other values on this that are not needed.


Testing emitted events


2 ways to trigger an event emit:

  1. mount the component, and call emitEvent()

    it("emits an event with two arguments", () => {
      const wrapper = shallowMount(Emitter)
    
      wrapper.vm.emitEvent()
    
      console.log(wrapper.emitted())
    })
    
  2. call method.[method name].call function


Technicalities


Mocking global objects


  • They are often times when you need to reference these global objects for different purposes. You can add in global objects such as $store, $t, $router. Here’s an example below:

    const wrapper = shallowMount(Bilingual, {
      mocks: {
        $t: (msg) => msg
      }
    })
    

Shallow Rendering:

  • Difference between shallow mount and mount.

  • ShallowMount will stub all your child components within, lease you your unit tests are all parasite by your child components.

    • You should use shallowMount for your unit tests

  • Mount should only be used when you want to do end-2-end testing that will mount all your components in which is tested

There are many other aspects of testing Vue application such as Vuex, Vue Router. That will be for another time. I figure that an engineer that is unfamiliar with test will often struggle to make sense of component testing, but here’s an attempt to shine light into the unknown.


TL;DR:

Understand the scope of a comprehensive, flexible, and yet least maintenance effort test, and work with that goal in mind. Test the public interface of your component, and leave the internal implementation of the component as a blackbox.


Image source: medium




Here’s a video I find useful to have a deeper understanding of this topic: