]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
feat(warn): incorrect state value #641 (#646)
authorRichard Banks <rbanks54@users.noreply.github.com>
Wed, 29 Sep 2021 10:12:17 +0000 (20:12 +1000)
committerGitHub <noreply@github.com>
Wed, 29 Sep 2021 10:12:17 +0000 (12:12 +0200)
* docs: Add notes on mapState and undefined properties. #641

* feat: warn when constructor call detected in state initialization function

* refactor: revise regex used to detect constructor calls

* feat: warn when a class is used to intialize store state

* feat: warn when a class is used to intialize store state

* feat: warn when a class is used to intialize store state

* Apply suggestions from code review

Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com>
packages/pinia/__tests__/store.spec.ts
packages/pinia/src/store.ts

index 825926887e54e171e7604b3641cb51a8aa07e28b..88cbe4b924fd3873bfba69056601737bea941395 100644 (file)
@@ -1,8 +1,11 @@
 import { createPinia, defineStore, setActivePinia } from '../src'
 import { mount } from '@vue/test-utils'
 import { defineComponent, getCurrentInstance, nextTick, watch } from 'vue'
+import { mockWarn } from 'jest-mock-warn'
 
 describe('Store', () => {
+  mockWarn()
+
   beforeEach(() => {
     setActivePinia(createPinia())
   })
@@ -330,4 +333,34 @@ describe('Store', () => {
 
     expect(useStore()).not.toBe(store)
   })
+
+  it('warns when state is created with a class constructor', () => {
+    class MyState {}
+
+    const useMyStore = defineStore({
+      id: 'store',
+      state: () => new MyState(),
+    })
+    useMyStore()
+    expect('Detected constructor usage').toHaveBeenWarned()
+  })
+
+  it('only warns about constructors when store is initially created', () => {
+    class MyState {}
+    const useMyStore = defineStore({
+      id: 'arrowInit',
+      state: () => new MyState(),
+    });
+    useMyStore()
+    expect('Detected constructor usage').toHaveBeenWarnedTimes(1)
+  })
+
+  it('does not warn when state is created with a plain object', () => {
+    const useMyStore = defineStore({
+      id: 'poInit',
+      state: () => ({ someValue: undefined })
+    })
+    useMyStore()
+    expect('Detected constructor usage').toHaveBeenWarnedTimes(0)
+  })
 })
index 1082d91bfaf226a9c0d017238a4835569a9918f6..f4f10e29da4a839c164a2fdc48baf5d900f0b333 100644 (file)
@@ -673,6 +673,18 @@ function createSetupStore<
     }
   })
 
+  if (
+    __DEV__ &&
+    store.$state &&
+    typeof store.$state === 'object' &&
+    typeof store.$state.constructor === 'function' &&
+    !store.$state.constructor.toString().includes('[native code]')
+  ) {
+    console.warn(
+      `[🍍]: The "state" must be a plain object. It cannot be\n\tstate: () => new MyClass()` 
+    )
+  }
+
   // only apply hydrate to option stores with an initial state in pinia
   if (initialState && buildState) {
     ;(options.hydrate || innerPatch)(store, initialState)