Browse Source

fix: Should vuex mapState print error message #1093 (#1297)

EdyHartono 5 years ago
parent
commit
e5ca2d52e8
2 changed files with 108 additions and 0 deletions
  1. 26 0
      src/helpers.js
  2. 82 0
      test/unit/helpers.spec.js

+ 26 - 0
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

+ 82 - 0
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()