With apps getting more complex than ever, it’s important to test them automatically. We can do this with unit tests, and then we don’t have to test everything by hand.
In this article, we’ll look at how to test Vue 3 apps by writing a simple app and testing it.
Testing Vuex
We can test apps with a Vuex store.
For example, if we have the following app:
import { mount } from '@vue/test-utils'
import { createStore } from 'vuex'
const store = createStore({
state() {
return {
count: 0
}
},
mutations: {
increment(state) {
state.count += 1
}
}
})
const App = {
template: `
<div>
<button @click="increment" />
Count: {{ count }}
</div>
`,
computed: {
count() {
return this.$store.state.count
}
},
methods: {
increment() {
this.$store.commit('increment')
}
}
}
const app = createApp(App)
app.use(store)
We can test it with the real Vuex store.
For example, we can add the test by writing:
import { mount } from '@vue/test-utils'
import { createApp } from 'vue'
import { createStore } from 'vuex'
const store = createStore({
state() {
return {
count: 0
}
},
mutations: {
increment(state) {
state.count += 1
}
}
})
const App = {
template: `
<div>
<button @click="increment" />
Count: {{ count }}
</div>
`,
computed: {
count() {
return this.$store.state.count
}
},
methods: {
increment() {
this.$store.commit('increment')
}
}
}
const app = createApp(App)
app.use(store)
test('vuex', async () => {
const wrapper = mount(App, {
global: {
plugins: [store]
}
})
await wrapper.find('button').trigger('click')
expect(wrapper.html()).toContain('Count: 1')
})
We pass in our store into the array we set for the plugins property.
Then when we click on the button in App , the real store’s state is updated.
Testing with a Mock Store
We can also test the app with a mock store.
For example, we can write:
import { mount } from '@vue/test-utils'
import { createApp } from 'vue'
import { createStore } from 'vuex'
const store = createStore({
state() {
return {
count: 0
}
},
mutations: {
increment(state) {
state.count += 1
}
}
})
const App = {
template: `
<div>
<button @click="increment" />
Count: {{ count }}
</div>
`,
computed: {
count() {
return this.$store.state.count
}
},
methods: {
increment() {
this.$store.commit('increment')
}
}
}
const app = createApp(App)
app.use(store)
test('vuex using a mock store', async () => {
const $store = {
state: {
count: 25
},
commit: jest.fn()
}
const wrapper = mount(App, {
global: {
mocks: {
$store
}
}
})
expect(wrapper.html()).toContain('Count: 25')
await wrapper.find('button').trigger('click')
expect($store.commit).toHaveBeenCalled()
})
We create our $store object with the commit method being a mocked function.
Then we get the rendered state.
And we click the button and check that $store.commit is called.
This is convenient since we don’t have any external dependencies in our mounted component.
However, if we break the Vuex store, then we don’t have any warnings.
Conclusion
We can test components that are connected to a Vuex store with Vue 3’s Vue Test Utils.