Unit testing your “vuex-module-decorators” state
Do you know the vuex-module-decorators
package? If not, read about it here. It provides a number of TypeScript decorators to manage your Vuex state in a more classy way, literally. Instead of modelling your vuex modules as objects, you just write classes with attributes and methods. If you come from another field of programming such as Java, or you want to include people in your project who do, this helps to make building up a Vuex state a lot easier.
I also use vuex-module-decorators
in my project, and I recently developed a testing strategy for unit testing my Vuex modules. State management concepts, which Vuex is one of, are predestined to be unit tested. As you know, every mutation in Vuex should meet these requirements:
- synchronous: Mutations should be executed in one thread, without any asynchronous behaviour like promises.
- pure: Mutations should never trigger any side effects.
- deterministic: With the same preconditions, a mutation should always produce exactly the same result, without any random values or external influences.
Sounds like a perfect environment for unit tests, eh? So let me show you what I came up with to test a Vuex store module effectively.
Test utilities
We need some helper functions to make the actual writing of test cases as straight forward as possible. I provided these functions in the gist below:
cloneState
creates a deep copy of the current state.stateDiff
determines the differences between the new and the initial state.sleep
helps to wait for a given number of seconds.
Testing
I will not specify any test frameworks to use here, so choose any test runner and assertion library you want. Mocha/Chai or Jest is fine, you will recognize the syntax below right away.
See the gist at the end of the article for the coding examples.
Testing mutations
As already mentioned, mutations always produce the same result, i.e. the same changes in the state, for the same prerequisites, i.e. the same initial state and same input payload. So to test a mutation, we only need 3 easy steps:
- Snapshot the initial state using
cloneState
- Execute the mutation
- Assert the expected changes in the new state with
stateDiff
Note that we do not only assert that expected changes happened, but also that unexpected changes did not happen. This is why we check the differences between the entire previous and current state, and not only certain state attributes.
Testing actions
Actions can execute multiple mutations and can run asynchronously. Apart from that, we can test them just as we tested actions:
- Snapshot the initial state using
cloneState
- Execute (and await) the action
- Assert the expected changes in the new state with
stateDiff
When your action accesses external services, e.g. making API calls, you will need to mock these to produce deterministic results. For example you could use Jest for mocking.
Testing getters
Getters are the easiest parts for unit tests, since a getter has only one job: to return a value based on the state. So we just need to:
- Prepare the state
- Assert the getter’s return value
Be sure to test every type of situation that could affect your getter, like
null
values.
And there you have it
I hope you like my test strategy. Look at some code examples to see it in action: