diff --git a/src/helpers.js b/src/helpers.js index 5922eb8b5..8f97840ff 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1,3 +1,5 @@ +import { isObject } from './util' + /** * Reduce the code which written in Vue.js for getting the state. * @param {String} [namespace] - Module's namespace @@ -6,6 +8,9 @@ */ export const mapState = normalizeNamespace((namespace, states) => { const res = {} + if (process.env.NODE_ENV !== 'production' && !isValidMap(states)) { + console.error('[vuex] states parameter must be either an Array/Object') + } normalizeMap(states).forEach(({ key, val }) => { res[key] = function mappedState () { let state = this.$store.state @@ -36,6 +41,9 @@ export const mapState = normalizeNamespace((namespace, states) => { */ export const mapMutations = normalizeNamespace((namespace, mutations) => { const res = {} + if (process.env.NODE_ENV !== 'production' && !isValidMap(mutations)) { + console.error('[vuex] mutations parameter must be either an Array/Object') + } normalizeMap(mutations).forEach(({ key, val }) => { res[key] = function mappedMutation (...args) { // Get the commit method from store @@ -63,6 +71,9 @@ export const mapMutations = normalizeNamespace((namespace, mutations) => { */ export const mapGetters = normalizeNamespace((namespace, getters) => { const res = {} + if (process.env.NODE_ENV !== 'production' && !isValidMap(getters)) { + console.error('[vuex] getters parameter must be either an Array/Object') + } normalizeMap(getters).forEach(({ key, val }) => { // The namespace has been mutated by normalizeNamespace val = namespace + val @@ -90,6 +101,9 @@ export const mapGetters = normalizeNamespace((namespace, getters) => { */ export const mapActions = normalizeNamespace((namespace, actions) => { const res = {} + if (process.env.NODE_ENV !== 'production' && !isValidMap(actions)) { + console.error('[vuex] actions parameter must be either an Array/Object') + } normalizeMap(actions).forEach(({ key, val }) => { res[key] = function mappedAction (...args) { // get dispatch function from store @@ -129,11 +143,23 @@ export const createNamespacedHelpers = (namespace) => ({ * @return {Object} */ function normalizeMap (map) { + if (!isValidMap(map)) { + return [] + } return Array.isArray(map) ? map.map(key => ({ key, val: key })) : Object.keys(map).map(key => ({ key, val: map[key] })) } +/** + * Validate whether given map is valid or not + * @param {*} map + * @return {Boolean} + */ +function isValidMap (map) { + return Array.isArray(map) || isObject(map) +} + /** * Return a function expect two param contains namespace and map. it will normalize the namespace and then the param's function will handle the new namespace and the map. * @param {Function} fn diff --git a/test/unit/helpers.spec.js b/test/unit/helpers.spec.js index 1bc0fc409..f1689f622 100644 --- a/test/unit/helpers.spec.js +++ b/test/unit/helpers.spec.js @@ -94,6 +94,22 @@ describe('Helpers', () => { expect(vm.value.b).toBeUndefined() }) + it('mapState (with undefined states)', () => { + const store = new Vuex.Store({ + modules: { + foo: { + namespaced: true, + state: { a: 1 } + } + } + }) + const vm = new Vue({ + store, + computed: mapState('foo') + }) + expect(vm.a).toBeUndefined() + }) + it('mapMutations (array)', () => { const store = new Vuex.Store({ state: { count: 0 }, @@ -206,6 +222,27 @@ describe('Helpers', () => { expect(store.state.foo.count).toBe(43) }) + it('mapMutations (with undefined mutations)', () => { + const store = new Vuex.Store({ + modules: { + foo: { + namespaced: true, + state: { count: 0 }, + mutations: { + inc: state => state.count++, + dec: state => state.count-- + } + } + } + }) + const vm = new Vue({ + store, + methods: mapMutations('foo') + }) + expect(vm.inc).toBeUndefined() + expect(vm.dec).toBeUndefined() + }) + it('mapGetters (array)', () => { const store = new Vuex.Store({ state: { count: 0 }, @@ -351,6 +388,31 @@ describe('Helpers', () => { expect(vm.count).toBe(9) }) + it('mapGetters (with undefined getters)', () => { + const store = new Vuex.Store({ + modules: { + foo: { + namespaced: true, + state: { count: 0 }, + mutations: { + inc: state => state.count++, + dec: state => state.count-- + }, + getters: { + hasAny: ({ count }) => count > 0, + negative: ({ count }) => count < 0 + } + } + } + }) + const vm = new Vue({ + store, + computed: mapGetters('foo') + }) + expect(vm.a).toBeUndefined() + expect(vm.b).toBeUndefined() + }) + it('mapActions (array)', () => { const a = jasmine.createSpy() const b = jasmine.createSpy() @@ -461,6 +523,26 @@ describe('Helpers', () => { expect(a.calls.argsFor(0)[1]).toBe('foobar') }) + it('mapActions (with undefined actions)', () => { + const a = jasmine.createSpy() + const store = new Vuex.Store({ + modules: { + foo: { + namespaced: true, + actions: { + a + } + } + } + }) + const vm = new Vue({ + store, + methods: mapActions('foo/') + }) + expect(vm.a).toBeUndefined() + expect(a).not.toHaveBeenCalled() + }) + it('createNamespacedHelpers', () => { const actionA = jasmine.createSpy() const actionB = jasmine.createSpy()