Skip to content

Commit 5fde81f

Browse files
authored
docs: add details on testing Vuex store to docs (#368)
* docs: add details on testing Vuex store to docs * docs: use lowercase username in URL
1 parent 29f53db commit 5fde81f

File tree

1 file changed

+128
-3
lines changed

1 file changed

+128
-3
lines changed

Diff for: docs/en/guides/using-with-vuex.md

+128-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# Using with Vuex
22

3-
In this guide, we'll see how to test Vuex in components with `vue-test-utils`.
3+
In this guide, we'll see how to test Vuex in components with `vue-test-utils`, and how to approach testing a Vuex store.
44

5-
## Mocking Actions
5+
## Testing Vuex in components
6+
7+
### Mocking Actions
68

79
Let’s look at some code.
810

@@ -259,8 +261,131 @@ describe('Modules.vue', () => {
259261
})
260262
```
261263

264+
## Testing a Vuex Store
265+
266+
There are two approaches to testing a Vuex store. The first approach is to unit test the getters, mutations, and actions separately. The second approach is to create a store and test against that. We'll look at both approaches.
267+
268+
To see how to test a Vuex store, we're going to create a simple counter store. The store will have an `increment` mutation and a `counter` getter.
269+
270+
```js
271+
// mutations.js
272+
export default {
273+
increment (state) {
274+
state.count++
275+
}
276+
}
277+
278+
```
279+
280+
```js
281+
// getters.js
282+
export default {
283+
evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'
284+
}
285+
```
286+
287+
### Testing getters, mutations, and actions separately
288+
289+
Getters, mutations, and actions are all JavaScript functions, so we can test them without using `vue-test-utils` or Vuex.
290+
291+
The benefit to testing getters, mutations, and actions separately is that your unit tests are detailed. When they fail, you know exactly what is wrong with your code. The downside is that you will need to mock Vuex funtions, like `commit` and `dispatch`. This can lead to a situation where your unit tests pass, but your production code fails because your mocks are incorrect.
292+
293+
We'll create two test files, mutations.spec.js and getters.spec.js:
294+
295+
First, let's test the `increment` mutations:
296+
297+
```js
298+
// mutations.spec.js
299+
300+
import mutations from './mutations'
301+
302+
test('increment increments state.count by 1', () => {
303+
const state = {
304+
count: 0
305+
}
306+
mutations.increment(state)
307+
expect(state.count).toBe(1)
308+
})
309+
```
310+
311+
Now let's test the `evenOrOdd` getter. We can test it by creating a mock `state`, calling the getter with the `state` and checking it returns the correct value.
312+
313+
```js
314+
// getters.spec.js
315+
316+
import getters from './getters'
317+
318+
test('evenOrOdd returns even if state.count is even', () => {
319+
const state = {
320+
count: 2
321+
}
322+
expect(getters.evenOrOdd(state)).toBe('even')
323+
})
324+
325+
test('evenOrOdd returns odd if state.count is even', () => {
326+
const state = {
327+
count: 1
328+
}
329+
expect(getters.evenOrOdd(state)).toBe('odd')
330+
})
331+
332+
```
333+
334+
### Testing a running store
335+
336+
Anopther approach to testing a Vuex store is to create a running store using the store config.
337+
338+
The benefit of testing creating a running store instance is we don't have to mock any Vuex functions.
339+
340+
The downside is that when a test breaks, it can be difficult to find where the problem is.
341+
342+
Let's write a test. When we create a store, we'll use `localVue` to avoid polluting the Vue base constructor. The test creates a store using the store-config.js export:
343+
344+
```js
345+
import mutations from './mutations'
346+
import getters from './getters'
347+
348+
export default {
349+
state: {
350+
count: 0
351+
},
352+
mutations,
353+
getters
354+
}
355+
```
356+
357+
```js
358+
// store-config.spec.js
359+
360+
import { createLocalVue } from '@vue/test-utils'
361+
import Vuex from 'vuex'
362+
import storeConfig from './store-config'
363+
import { cloneDeep } from 'lodash'
364+
365+
test('increments count value when increment is commited', () => {
366+
const localVue = createLocalVue()
367+
localVue.use(Vuex)
368+
const store = new Vuex.Store(cloneDeep(storeConfig))
369+
expect(store.state.count).toBe(0)
370+
store.commit('increment')
371+
expect(store.state.count).toBe(1)
372+
})
373+
374+
test('updates evenOrOdd getter when increment is commited', () => {
375+
const localVue = createLocalVue()
376+
localVue.use(Vuex)
377+
const store = new Vuex.Store(cloneDeep(storeConfig))
378+
expect(store.getters.evenOrOdd).toBe('even')
379+
store.commit('increment')
380+
expect(store.getters.evenOrOdd).toBe('odd')
381+
})
382+
```
383+
384+
Notice that we use `cloneDeep` to clone the store config before creating a store with it. This is because Vuex mutates the options object used to create the store. To make sure we have a clean store in each test, we need to clone the `storeConfig` object.
385+
262386
### Resources
263387

264-
- [Example project for this guide](https://github.com/eddyerburgh/vue-test-utils-vuex-example)
388+
- [Example project for testing the components](https://github.com/eddyerburgh/vue-test-utils-vuex-example)
389+
- [Example project for testing the store](https://github.com/eddyerburgh/testing-vuex-store-example)
265390
- [`localVue`](../api/options.md#localvue)
266391
- [`createLocalVue`](../api/createLocalVue.md)

0 commit comments

Comments
 (0)