The steps below outline how to get from the base Webpack template to the completed example project included in this repo. Walking through them will allow you to try out component composition, testing, and state management with Vuex.
brew install node
npm install -g vue-cli
vue init webpack my-project
cd my-project
npm install
npm run dev
# or, when ready...
npm run build
<template>
<li>{{ todo.text }}</li>
</template>
<script>
export default {
name: 'todo-item',
props: ['todo']
}
</script>
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<input v-model="nextItem" placeholder="edit me">
<button v-on:click="addItem">Submit</button>
<p>Item: {{ nextItem }}</p>
<ol>
<todo-item
v-for="item in itemList"
:key="item.id"
:todo="item">
</todo-item>
</ol>
</div>
</template>
<script>
import TodoItem from './TodoItem.vue'
export default {
name: 'HelloWorld',
components: {
TodoItem
},
data () {
return {
msg: 'Welcome to Your Vue.js App',
itemList: [
{ id: 0, text: 'Vegetables' },
{ id: 1, text: 'Cheese' },
{ id: 2, text: 'Whatever else humans are supposed to eat' }
],
nextItem: ''
}
},
methods: {
addItem: function () {
let item = { id: this.itemList.length, text: this.nextItem }
this.itemList.push(item)
}
}
}
</script>
npm run unit
- Unit tests run in JSDOM with Jest, or in PhantomJS with Karma + Mocha + karma-webpack.
"unit": "jest --watchAll --config test/unit/jest.conf.js --coverage",
// add to describe('HelloWorld.vue' ...
it('can add an item to a list', () => {
const Constructor = Vue.extend(HelloWorld)
const vm = new Constructor().$mount()
let nextID = vm.itemList.length
vm.nextItem = 'foo'
vm.addItem()
expect(vm.itemList.pop()).toEqual({ id: nextID, text: 'foo' })
})
npm run e2e
- End-to-end tests with Nightwatch.
- Run tests in multiple browsers in parallel.
- Works with one command out of the box:
- Selenium and chromedriver dependencies automatically handled.
- Automatically spawns the Selenium server.
npm install vuex --save
- Inspired by Flux, Redux and The Elm Architecture.
- Passing props can be tedious for deeply nested components, and simply doesn't work for sibling components.
- Allows multiple components to share the same state in a global singleton.
- Works with vue-devtools to allow time travel debugging:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
itemList: [
{ id: 0, text: 'chloe' },
{ id: 1, text: 'Cheese' },
{ id: 2, text: 'Whatever else humans are supposed to eat' }
]
}
export const mutations = {
addItem (state, item) {
state.itemList.push(item)
}
}
const actions = {} // side-effecting or async functions
const getters = {} // normal functions
export default new Vuex.Store({
state,
getters,
actions,
mutations
})
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
data () {
return {
msg: 'Welcome to Your Vue.js App',
nextItem: ''
}
},
computed: {
itemList () {
return this.$store.state.itemList
}
},
methods: {
addItem: function () {
let item = { id: this.itemList.length, text: this.nextItem }
this.$store.commit('addItem', item)
}
}
Unit testing mutations is easy...
import { mutations } from '@/store.js'
describe('addItem', () => {
it('can add an item to a list', () => {
const state = { itemList: [] }
let item = { id: 0, text: 'foo' }
mutations.addItem(state, item)
expect(state.itemList.pop()).toEqual(item)
})
})
...but when testing components, the store must be mocked. Mocking the store is beyond the scope of this guide, but this article covers it nicely.
- Webpack template repo
- Registering components
- Composing with components
- Input handling
- What is Vuex?
- Super-simple Vuex implementation
- Official guide
- Vue JS intro on CSS-Tricks.com