Las partes principales por las que queremos pasar las unidades de prueba en Vuex son mutaciones y acciones.
Las mutaciones son muy fáciles de probar, ya que son sólo funciones que dependen completamente de sus argumentos. Un truco es que si estás usando módulos ES2015 y pones tus mutaciones dentro de tu archivo store.js
, en adición a la exportación por defecto, también puedes exportar las mutaciones como una exportación nombrada:
const state = { ... }
// exporta las mutaciones como una exportación nombrada
export const mutations = { ... }
export default new Vuex.Store({
state,
mutations
})
Ejemplo probando una mutación usando Mocha + Chai (puedes utilizar cualquier biblioteca/aserción que quieras):
// mutations.js
export const INCREMENT = state => state.count++
// mutations.spec.js
import { expect } from 'chai'
import { mutations } from './store'
// asignación mutaciones destructurada
const { INCREMENT } = mutations
describe('mutations', () => {
it('INCREMENT', () => {
// estado simulado
const state = { count: 0 }
// aplicar mutación
INCREMENT(state)
// asegurar resultado
expect(state.count).to.equal(1)
})
})
Las acciones pueden ser un poco más complejas ya que pueden llamar APIs externas. Cuando probamos acciones, por lo general tenemos que hacer un cierto nivel de simulación - por ejemplo, podemos abstraer las llamadas a la API en un servicio y simular ese servicio dentro de nuestras pruebas. Con el fin de simular fácilmente las dependencias, podemos utilizar Webpack e inject-loader para compilar nuestros archivos de pruebas.
Ejemplo probando una acción asíncrona:
// actions.js
import shop from '../api/shop'
export const getAllProducts = ({ dispatch }) => {
dispatch('REQUEST_PRODUCTS')
shop.getProducts(products => {
dispatch('RECEIVE_PRODUCTS', products)
})
}
// actions.spec.js
// usa la sintaxis 'require' para los cargadores en línea.
// con inject-loader, esto devuelve un 'module factory'
// que nos permite inyectar dependencias simuladas.
import { expect } from 'chai'
const actionsInjector = require('inject!./actions')
// crea el módulo con nuestras simulaciones
const actions = actionsInjector({
'../api/shop': {
getProducts (cb) {
setTimeout(() => {
cb([ /* mocked response */ ])
}, 100)
}
}
})
// helper para probar la acción con mutaciones esperadas
const testAction = (action, args, state, expectedMutations, done) => {
let count = 0
// simular despacho
const dispatch = (name, ...payload) => {
const mutation = expectedMutations[count]
expect(mutation.name).to.equal(name)
if (payload) {
expect(mutation.payload).to.deep.equal(payload)
}
count++
if (count >= expectedMutations.length) {
done()
}
}
// llama a la acción con almacén y argumentos simulados
action({dispatch, state}, ...args)
// comprobar si no deberían haber sido despachadas mutaciones
if (expectedMutations.length === 0) {
expect(count).to.equal(0)
done()
}
}
describe('actions', () => {
it('getAllProducts', done => {
testAction(actions.getAllProducts, [], {}, [
{ name: 'REQUEST_PRODUCTS' },
{ name: 'RECEIVE_PRODUCTS', payload: [ /* respuesta simulada */ ] }
], done)
})
})
Si tus mutaciones y acciones son correctamente escritos, las pruebas deberían no tener dependencia directa de las APIs de navegador después de una simulación apropiada. De esta manera puedes simplemente agrupar las pruebas con Webpack y ejecutarlas directamente en Node. Como alternativa, puedes usar mocha-loader
o Karma + karma-webpack
para ejecutar las pruebas en navegadores reales.
Crea la siguiente configuración webpack:
module.exports = {
entry: './test.js',
output: {
path: __dirname,
filename: 'test-bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/
}
]
},
babel: {
presets: ['es2015']
}
}
Entonces:
webpack
mocha test-bundle.js
mocha-loader
entry
de la configuración de Webpack anterior a 'mocha!babel!./test.js'
.webpack-dev-server
utilizando la configuraciónlocalhost:8080/webpack-dev-server/test-bundle
.Consulta la configuración en la documentación de vue-loader.