Commit bdeadd69 authored by Mark Florian's avatar Mark Florian Committed by Andrew Fontaine

Address review feedback

- Don't document using `Vue.use(Vuex)` in store entry points (this harms
  testability)
- Add note about RFC to prefer named exports
- Don't document passing a store singleton to a component definition;
  this isn't what we do. Instead, just rely on a store being provided by
  an ancestor.
- Using `@vue/test-utils` for component test
- Document `localVue` usage
parent 20c359d2
...@@ -40,24 +40,25 @@ The following example shows an application that lists and adds users to the stat ...@@ -40,24 +40,25 @@ The following example shows an application that lists and adds users to the stat
This is the entry point for our store. You can use the following as a guide: This is the entry point for our store. You can use the following as a guide:
```javascript ```javascript
import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import * as actions from './actions'; import * as actions from './actions';
import * as getters from './getters'; import * as getters from './getters';
import mutations from './mutations'; import mutations from './mutations';
import state from './state'; import state from './state';
Vue.use(Vuex); export const createStore = () =>
new Vuex.Store({
export const createStore = () => new Vuex.Store({
actions, actions,
getters, getters,
mutations, mutations,
state, state,
}); });
export default createStore();
``` ```
_Note:_ Until this
[RFC](https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/20) is implemented,
the above will need to disable the `import/prefer-default-export` ESLint rule.
### `state.js` ### `state.js`
The first thing you should do before writing any code is to design the state. The first thing you should do before writing any code is to design the state.
...@@ -316,9 +317,12 @@ function when mounting your Vue component: ...@@ -316,9 +317,12 @@ function when mounting your Vue component:
// in the Vue app's initialization script (e.g. mount_show.js) // in the Vue app's initialization script (e.g. mount_show.js)
import Vue from 'vue'; import Vue from 'vue';
import createStore from './stores'; import Vuex from 'vuex';
import { createStore } from './stores';
import AwesomeVueApp from './components/awesome_vue_app.vue' import AwesomeVueApp from './components/awesome_vue_app.vue'
Vue.use(Vuex);
export default () => { export default () => {
const el = document.getElementById('js-awesome-vue-app'); const el = document.getElementById('js-awesome-vue-app');
...@@ -398,10 +402,8 @@ discussion](https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/56#note_3025148 ...@@ -398,10 +402,8 @@ discussion](https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/56#note_3025148
```javascript ```javascript
<script> <script>
import { mapActions, mapState, mapGetters } from 'vuex'; import { mapActions, mapState, mapGetters } from 'vuex';
import store from './store';
export default { export default {
store,
computed: { computed: {
...mapGetters([ ...mapGetters([
'getUsersWithPets' 'getUsersWithPets'
...@@ -417,12 +419,10 @@ export default { ...@@ -417,12 +419,10 @@ export default {
'fetchUsers', 'fetchUsers',
'addUser', 'addUser',
]), ]),
onClickAddUser(data) { onClickAddUser(data) {
this.addUser(data); this.addUser(data);
} }
}, },
created() { created() {
this.fetchUsers() this.fetchUsers()
} }
...@@ -485,55 +485,50 @@ In order to write unit tests for those components, we need to include the store ...@@ -485,55 +485,50 @@ In order to write unit tests for those components, we need to include the store
```javascript ```javascript
//component_spec.js //component_spec.js
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex';
import { mount, createLocalVue } from '@vue/test-utils';
import { createStore } from './store'; import { createStore } from './store';
import component from './component.vue' import Component from './component.vue'
const localVue = createLocalVue();
localVue.use(Vuex);
describe('component', () => { describe('component', () => {
let store; let store;
let vm; let wrapper;
let Component;
const createComponent = () => {
store = createStore();
wrapper = mount(Component, {
localVue,
store,
});
};
beforeEach(() => { beforeEach(() => {
Component = Vue.extend(issueActions); createComponent();
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
wrapper = null;
}); });
it('should show a user', () => { it('should show a user', async () => {
const user = { const user = {
name: 'Foo', name: 'Foo',
age: '30', age: '30',
}; };
store = createStore();
// populate the store // populate the store
store.dispatch('addUser', user); await store.dispatch('addUser', user);
vm = new Component({ expect(wrapper.text()).toContain(user.name);
store,
propsData: props,
}).$mount();
}); });
}); });
``` ```
#### Testing Vuex actions and getters
Because we're currently using [`babel-plugin-rewire`](https://github.com/speedskater/babel-plugin-rewire), you may encounter the following error when testing your Vuex actions and getters:
`[vuex] actions should be function or object with "handler" function`
To prevent this error from happening, you need to export an empty function as `default`:
```javascript
// getters.js or actions.js
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
```
### Two way data binding ### Two way data binding
When storing form data in Vuex, it is sometimes necessary to update the value stored. The store should never be mutated directly, and an action should be used instead. When storing form data in Vuex, it is sometimes necessary to update the value stored. The store should never be mutated directly, and an action should be used instead.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment