Skip to content

Commit c2086f4

Browse files
author
mcibique
committed
Added initial state testing examples
1 parent 22066bf commit c2086f4

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

README.md

+107
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ Topics already covered:
3434
* [Mocking store for a smart component](#mocking-store-for-a-smart-component)
3535
* [Mocking store for router](#mocking-store-for-router)
3636
* [Mocking actions, mutations and getters](#mocking-actions-mutations-and-getters)
37+
* [Setting up initial state in tests](#setting-up-initial-state-in-tests)
38+
+ [Using existing mutations to change initial state](#using-existing-mutations-to-change-initial-state)
39+
+ [Modifying the state directly](#modifying-the-state-directly)
3740
- [Testing v-model](#testing-v-model)
3841
- [Using flush-promises vs Vue.nextTick()](#using-flush-promises-vs-vuenexttick)
3942

@@ -1313,6 +1316,110 @@ beforeEach(function () {
13131316
```
13141317
You can see full implementation (including restoring mock back to original functionality) in [test/unit/utils/store.js](./test/unit/utils/store.js) file.
13151318

1319+
## Setting up initial state in tests
1320+
Let's say we need our store to start with different initial state than is specified in application's code. E.g. a store which holds information about what is the type of current user:
1321+
```js
1322+
// store.js
1323+
export default {
1324+
state: {
1325+
isVip: false
1326+
}
1327+
}
1328+
```
1329+
The problems starts when we want to test a component which uses the flag from store to determine what should be displayed:
1330+
```html
1331+
<template>
1332+
<section>
1333+
<h1 v-if="isVip" style="color: gold;" key="welcome-message">Welcome oh mighty user</h1>
1334+
<h1 v-else style="color: gray;" key="welcome-message">Welcome</h1>
1335+
</section>
1336+
<!-- SIDE NOTE: check out https://vuejs.org/v2/style-guide/#v-if-v-if-else-v-else-without-key-use-with-caution to understand why both h1 tags have the key property assigned -->
1337+
</template>
1338+
```
1339+
```js
1340+
class MyComponent extends Vue {
1341+
get isVip() {
1342+
return this.$store.state.isVip; // or map it using mapState or @State decorator
1343+
}
1344+
}
1345+
```
1346+
In test, we need to change the initial state before each test. We have two options how to do that:
1347+
### Using existing mutations to change initial state
1348+
```js
1349+
describe('when user is VIP', function () {
1350+
beforeEach(function () {
1351+
this.store = createStore();
1352+
this.store.commit('setVip', true); // setVip mutation must exist
1353+
});
1354+
1355+
it('should display warning welcome message');
1356+
});
1357+
1358+
describe('when user is non-VIP', function () {
1359+
beforeEach(function () {
1360+
this.store = createStore();
1361+
this.store.commit('setVip', false); // setVip mutation must exist
1362+
});
1363+
1364+
it('should display generic welcome message');
1365+
});
1366+
```
1367+
### Modifying the state directly
1368+
```js
1369+
describe('when user is VIP', function () {
1370+
beforeEach(function () {
1371+
this.store = createStore();
1372+
this.store.state.isVip = true; // no mutation required
1373+
});
1374+
1375+
it('should display warning welcome message');
1376+
});
1377+
1378+
describe('when user is non-VIP', function () {
1379+
beforeEach(function () {
1380+
this.store = createStore();
1381+
this.store.state.isVip = false; // no mutation required
1382+
});
1383+
1384+
it('should display generic welcome message');
1385+
});
1386+
```
1387+
There is no winner in this competition, both approaches does the work, it's up to you which one do you prefer. Few notes to consider:
1388+
1389+
The first approach uses existing functionality, that means if the logic in mutation changes, then you have to update the tests. It also might seem a little less readable.
1390+
1391+
The second approach doesn't require mutation to be defined (might be useful when an application doesn't need it, don't write a mutation only for using it in tests). Setting properties of the state works well only if you are setting primitive values. The `state` object is [reactive](https://vuejs.org/v2/guide/reactivity.html), that means if you reassign array or object in the `state`, you will disconnect the state and your component under the test:
1392+
```js
1393+
// !warning: this is wrong!
1394+
describe('when user has profile loaded', function () {
1395+
beforeEach(function () {
1396+
this.store = createStore();
1397+
this.store.state.profile = {
1398+
firstName: 'John',
1399+
lastName: 'Doe',
1400+
username: 'john.doe'
1401+
}; // please don't
1402+
this.myComponent = mount(MyComponent, { store: this.store })
1403+
});
1404+
1405+
it('should display full name in the welcome message', function () {
1406+
expect(this.myComponent.find('h1').text()).to.equal('Welcome John Doe'); // fail
1407+
});
1408+
});
1409+
// !warning: this is wrong!
1410+
```
1411+
If you try to use `firstName` or `lastName` in the template, you will only get undefined values, because these values were not reactified by the Vue. Vue cannot detect new or deleted properties, see [caveats of reactivity](https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats). However you can use `Vue.set()` to fix the problem:
1412+
```js
1413+
beforeEach(function () {
1414+
Vue.set(this.store.state, 'profile', {
1415+
firstName: 'John',
1416+
lastName: 'Doe',
1417+
username: 'john.doe'
1418+
});
1419+
});
1420+
```
1421+
And everything works fine again.
1422+
13161423
# Testing v-model
13171424
Let's test a custom component with v-model support, e.g. like this one
13181425
```html

0 commit comments

Comments
 (0)