]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
test: fix tests
authorEduardo San Martin Morote <posva13@gmail.com>
Fri, 9 Jul 2021 16:45:42 +0000 (18:45 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Mon, 19 Jul 2021 09:51:12 +0000 (11:51 +0200)
__tests__/mapHelpers.spec.ts
__tests__/state.spec.ts
__tests__/store.patch.spec.ts
__tests__/storePlugins.spec.ts
src/mapHelpers.ts
src/rootStore.ts
src/store.ts
src/types.ts

index d917e446be56c1702961f8e8ed5625717635ab5b..a0b74be9148c35d46e50bc708142f4a67f74f9bc 100644 (file)
@@ -13,7 +13,6 @@ import { nextTick, defineComponent } from 'vue'
 import { mockWarn } from 'jest-mock-warn'
 
 describe('Map Helpers', () => {
-  const useCartStore = defineStore({ id: 'cart' })
   const useStore = defineStore({
     id: 'main',
     state: () => ({
@@ -41,62 +40,6 @@ describe('Map Helpers', () => {
 
   describe('mapStores', () => {
     mockWarn()
-    it('mapStores computes only once when mapping one store', async () => {
-      const pinia = createPinia()
-      const fromStore = jest.fn(function () {
-        // @ts-ignore
-        return this.mainStore
-      })
-      const Component = defineComponent({
-        template: `<p @click="fromStore.n++">{{ fromStore.n }}</p>`,
-        computed: {
-          ...mapStores(useStore),
-          fromStore,
-        },
-      })
-
-      const wrapper = mount(Component, { global: { plugins: [pinia] } })
-      // const store = useStore()
-      // const other = useCartStore()
-      expect(wrapper.vm.mainStore).toBeDefined()
-      expect(wrapper.text()).toBe('0')
-      await nextTick()
-      expect(fromStore).toHaveBeenCalledTimes(1)
-
-      await wrapper.trigger('click')
-      expect(wrapper.text()).toBe('1')
-      expect(fromStore).toHaveBeenCalledTimes(1)
-      await wrapper.trigger('click')
-      expect(wrapper.text()).toBe('2')
-      expect(fromStore).toHaveBeenCalledTimes(1)
-    })
-
-    it('mapStores computes only once when mapping multiple stores', async () => {
-      const pinia = createPinia()
-      const fromStore = jest.fn(function () {
-        // @ts-ignore
-        return this.mainStore
-      })
-      const Component = defineComponent({
-        template: `<p @click="fromStore.n++">{{ mainStore.n }} {{ fromStore.n }} {{ cartStore.$id }}</p>`,
-        computed: {
-          ...mapStores(useStore, useCartStore),
-          fromStore,
-        },
-      })
-
-      const wrapper = mount(Component, { global: { plugins: [pinia] } })
-      expect(wrapper.text()).toBe('0 0 cart')
-      await nextTick()
-      expect(fromStore).toHaveBeenCalledTimes(1)
-
-      await wrapper.trigger('click')
-      expect(wrapper.text()).toBe('1 1 cart')
-      expect(fromStore).toHaveBeenCalledTimes(1)
-      await wrapper.trigger('click')
-      expect(wrapper.text()).toBe('2 2 cart')
-      expect(fromStore).toHaveBeenCalledTimes(1)
-    })
 
     it('can set custom suffix', async () => {
       const pinia = createPinia()
@@ -110,7 +53,6 @@ describe('Map Helpers', () => {
 
       const wrapper = mount(Component, { global: { plugins: [pinia] } })
       // const store = useStore()
-      // const other = useCartStore()
       // @ts-expect-error: by default this shouldn't exist
       expect(wrapper.vm.main).toBeDefined()
       expect(wrapper.vm.mainStore).not.toBeDefined()
index a69460a48e9625ecd4255803dc346b08802375f8..3f3e6e0ea8b052eaa1f3685f79ce061fbdc9dd8d 100644 (file)
@@ -1,15 +1,16 @@
-import { createPinia, defineStore, setActivePinia } from '../src'
+import { createPinia, defineStore, Pinia, setActivePinia } from '../src'
 import { computed, nextTick, ref, watch } from 'vue'
 
 describe('State', () => {
-  const useStore = () => {
+  const useStore = (pinia?: Pinia) => {
     // create a new store
-    setActivePinia(createPinia())
+    setActivePinia(pinia || createPinia())
     return defineStore({
       id: 'main',
       state: () => ({
         name: 'Eduardo',
         counter: 0,
+        nested: { n: 0 },
       }),
     })()
   }
@@ -29,6 +30,72 @@ describe('State', () => {
     expect(upperCased.value).toBe('ED')
   })
 
+  it('can be set with patch', () => {
+    const pinia = createPinia()
+    const store = useStore(pinia)
+
+    store.$patch({ name: 'a' })
+
+    expect(store.name).toBe('a')
+    expect(store.$state.name).toBe('a')
+    expect(pinia.state.value.main.name).toBe('a')
+  })
+
+  it('can be set on store', () => {
+    const pinia = createPinia()
+    const store = useStore(pinia)
+
+    store.name = 'a'
+
+    expect(store.name).toBe('a')
+    expect(store.$state.name).toBe('a')
+    expect(pinia.state.value.main.name).toBe('a')
+  })
+
+  it('can be set on store.$state', () => {
+    const pinia = createPinia()
+    const store = useStore(pinia)
+
+    store.$state.name = 'a'
+
+    expect(store.name).toBe('a')
+    expect(store.$state.name).toBe('a')
+    expect(pinia.state.value.main.name).toBe('a')
+  })
+
+  it('can be nested set with patch', () => {
+    const pinia = createPinia()
+    const store = useStore(pinia)
+
+    store.$patch({ nested: { n: 3 } })
+
+    expect(store.nested.n).toBe(3)
+    expect(store.$state.nested.n).toBe(3)
+    expect(pinia.state.value.main.nested.n).toBe(3)
+  })
+
+  it('can be nested set on store', () => {
+    const pinia = createPinia()
+    const store = useStore(pinia)
+
+    store.nested.n = 3
+
+    expect(store.nested.n).toBe(3)
+    expect(store.$state.nested.n).toBe(3)
+    expect(pinia.state.value.main.nested.n).toBe(3)
+  })
+
+  it('can be nested set on store.$state', () => {
+    const pinia = createPinia()
+    const store = useStore(pinia)
+
+    store.$state.nested.n = 3
+
+    expect(store.nested.n).toBe(3)
+    expect(store.$state.nested.n).toBe(3)
+    expect(pinia.state.value.main.nested.n).toBe(3)
+  })
+
   // it('watch', () => {
   //   setActivePinia(createPinia())
   //   defineStore({
@@ -50,6 +117,27 @@ describe('State', () => {
     expect(spy).toHaveBeenCalledTimes(1)
   })
 
+  it('can be given a ref', () => {
+    const pinia = createPinia()
+    const store = useStore(pinia)
+
+    // If the ref is directly set to the store, it won't work,
+    // it must be set into the `store.$state` so it connects to pinia
+    // store.name = ref('Ed')
+
+    // @ts-expect-error
+    store.$state.name = ref('Ed')
+
+    expect(store.name).toBe('Ed')
+    expect(store.$state.name).toBe('Ed')
+    expect(pinia.state.value.main.name).toBe('Ed')
+
+    store.name = 'Other'
+    expect(store.name).toBe('Other')
+    expect(store.$state.name).toBe('Other')
+    expect(pinia.state.value.main.name).toBe('Other')
+  })
+
   it('unwraps refs', () => {
     const name = ref('Eduardo')
     const counter = ref(0)
index 8e6c157987d6637ee2f88b95042f8a239d06c51a..f6c8037729b56384026c3021f6d74ec08b8b40a1 100644 (file)
@@ -1,10 +1,5 @@
 import { reactive, ref } from 'vue'
-import {
-  createPinia,
-  defineSetupStore,
-  defineStore,
-  setActivePinia,
-} from '../src'
+import { createPinia, defineStore, Pinia, setActivePinia } from '../src'
 
 describe('store.$patch', () => {
   const useStore = () => {
@@ -89,26 +84,57 @@ describe('store.$patch', () => {
   })
 
   describe('skipping nested objects', () => {
-    const useStore = () => {
+    const useStore = (pinia?: Pinia) => {
       // create a new store
-      setActivePinia(createPinia())
+      setActivePinia(pinia || createPinia())
       return defineStore({
         id: 'main',
         state: () => ({
           arr: [] as any[],
+          name: 'Eduardo',
           item: { a: 0, b: 0 } as null | { a: number; b?: number },
         }),
       })()
     }
+    // const useStore = (pinia?: Pinia) => {
+    //   // create a new store
+    //   setActivePinia(pinia || createPinia())
+    //   return defineSetupStore('main', () => {
+    //     const arr = ref([] as any[])
+    //     const item = ref({ a: 0, b: 0 } as null | { a: number; b?: number })
 
-    it('ref', () => {
-      const store = useStore()
+    //     return { arr, item }
+    //   })()
+    // }
+
+    it('ref of primitive', () => {
+      const pinia = createPinia()
+      const store = useStore(pinia)
+      const name = ref('Edu')
+      // @ts-expect-error: because it's a ref
+      store.$patch({ name })
+      expect(pinia.state.value.main.name).toEqual('Edu')
+      expect(store.$state.name).toEqual('Edu')
+      expect(store.name).toEqual('Edu')
+    })
+
+    it('ref of object', () => {
+      const pinia = createPinia()
+      const store = useStore(pinia)
       const item = ref({ a: 1, b: 1 })
       const oldItem = store.item
       // @ts-expect-error: because it's a ref
-      store.$patch({ item })
+      store.$state.item = item
       expect(oldItem).toEqual({ a: 0, b: 0 })
+      expect(pinia.state.value.main.item).toEqual({ a: 1, b: 1 })
+      expect(store.$state.item).toEqual({ a: 1, b: 1 })
       expect(store.item).toEqual({ a: 1, b: 1 })
+
+      // @ts-expect-error: because it's a ref
+      store.$patch({ item: ref({ a: 2, b: 2 }) })
+      expect(pinia.state.value.main.item).toEqual({ a: 2, b: 2 })
+      expect(store.$state.item).toEqual({ a: 2, b: 2 })
+      expect(store.item).toEqual({ a: 2, b: 2 })
     })
 
     it('nested ref', () => {
index 747518755cc4365bdf97895880806a97378a2cd2..89621e49ae2241bc6712bb2bb010294c12c3a0ef 100644 (file)
@@ -10,7 +10,6 @@ declare module '../src' {
     idFromPlugin: Id
     globalA: string
     globalB: string
-    notShared: number
     shared: number
   }
 
@@ -134,8 +133,6 @@ describe('store plugins', () => {
         store.$state.shared = ref(20)
       }
       // @ts-expect-error: TODO: allow setting refs
-      store.notShared = ref(10)
-      // @ts-expect-error: TODO: allow setting refs
       store.shared = toRef(store.$state, 'shared')
     })
 
@@ -158,11 +155,5 @@ describe('store plugins', () => {
     expect(store.shared).toBe(1)
     expect(store2.$state.shared).toBe(1)
     expect(store2.shared).toBe(1)
-
-    store.notShared = 5
-    expect(store.$state).not.toHaveProperty('notShared')
-    expect(store.notShared).toBe(5)
-    expect(store2.$state).not.toHaveProperty('notShared')
-    expect(store2.notShared).toBe(10)
   })
 })
index 47f976773c7db242b8a0ab5d34235ae8c16e596a..5f04f0e8cb1b6415ee1f08a16e98f55cf64596a9 100644 (file)
@@ -5,7 +5,6 @@ import {
   StateTree,
   Store,
   StoreDefinition,
-  ActionsTree,
 } from './types'
 
 /**
@@ -55,26 +54,6 @@ export type _Spread<A extends readonly any[]> = A extends [infer L, ...infer R]
   ? _StoreObject<L> & _Spread<R>
   : unknown
 
-function getCachedStore<
-  Id extends string = string,
-  S extends StateTree = StateTree,
-  G extends GettersTree<S> = GettersTree<S>,
-  A /* extends ActionsTree */ = ActionsTree
->(
-  vm: ComponentPublicInstance,
-  useStore: StoreDefinition<Id, S, G, A>
-): Store<Id, S, G, A> {
-  const cache = '_pStores' in vm ? vm._pStores! : (vm._pStores = {})
-  const id = useStore.$id
-  return (cache[id] ||
-    (cache[id] = useStore(vm.$pinia) as unknown as Store)) as unknown as Store<
-    Id,
-    S,
-    G,
-    A
-  >
-}
-
 export let mapStoreSuffix = 'Store'
 
 /**
@@ -131,8 +110,10 @@ export function mapStores<Stores extends any[]>(
 
   return stores.reduce((reduced, useStore) => {
     // @ts-ignore: $id is added by defineStore
-    reduced[useStore.$id + mapStoreSuffix] = function (this: Vue) {
-      return getCachedStore(this, useStore)
+    reduced[useStore.$id + mapStoreSuffix] = function (
+      this: ComponentPublicInstance
+    ) {
+      return useStore(this.$pinia)
     }
     return reduced
   }, {} as _Spread<Stores>)
@@ -280,13 +261,13 @@ export function mapState<
     ? keysOrMapper.reduce((reduced, key) => {
         reduced[key] = function (this: ComponentPublicInstance) {
           // @ts-expect-error
-          return getCachedStore(this, useStore)[key]
+          return useStore(this.$pinia)[key]
         } as () => any
         return reduced
       }, {} as _MapStateReturn<S, G>)
     : Object.keys(keysOrMapper).reduce((reduced, key: keyof KeyMapper) => {
         reduced[key] = function (this: ComponentPublicInstance) {
-          const store = getCachedStore(this, useStore)
+          const store = useStore(this.$pinia)
           const storeKey = keysOrMapper[key]
           // for some reason TS is unable to infer the type of storeKey to be a
           // function
@@ -411,7 +392,7 @@ export function mapActions<
           ...args: any[]
         ) {
           // @ts-expect-error
-          return (getCachedStore(this, useStore)[key] as _Method)(...args)
+          return (useStore(this.$pinia)[key] as _Method)(...args)
         }
         return reduced
       }, {} as _MapActionsReturn<A>)
@@ -422,7 +403,7 @@ export function mapActions<
           ...args: any[]
         ) {
           // @ts-expect-error
-          return getCachedStore(this, useStore)[keysOrMapper[key]](...args)
+          return useStore(this.$pinia)[keysOrMapper[key]](...args)
         }
         return reduced
       }, {} as _MapActionsObjectReturn<A, KeyMapper>)
@@ -510,12 +491,12 @@ export function mapWritableState<
         reduced[key] = {
           get(this: ComponentPublicInstance) {
             // @ts-expect-error
-            return getCachedStore(this, useStore)[key]
+            return useStore(this.$pinia)[key]
           },
           set(this: ComponentPublicInstance, value) {
             // it's easier to type it here as any
             // @ts-expect-error
-            return (getCachedStore(this, useStore)[key] = value as any)
+            return (useStore(this.$pinia)[key] = value as any)
           },
         }
         return reduced
@@ -525,13 +506,12 @@ export function mapWritableState<
         reduced[key] = {
           get(this: ComponentPublicInstance) {
             // @ts-expect-error
-            return getCachedStore(this, useStore)[keysOrMapper[key]]
+            return useStore(this.$pinia)[keysOrMapper[key]]
           },
           set(this: ComponentPublicInstance, value) {
             // it's easier to type it here as any
             // @ts-expect-error
-            return (getCachedStore(this, useStore)[keysOrMapper[key]] =
-              value as any)
+            return (useStore(this.$pinia)[keysOrMapper[key]] = value as any)
           },
         }
         return reduced
index cd6b08353f67ad1e77f40338641a83e32183237e..a5d276f9260716be60647769f42b39d4d4575d4a 100644 (file)
@@ -122,8 +122,8 @@ declare module '@vue/runtime-core' {
     $pinia: Pinia
 
     /**
-     * Cache of stores instantiated by the current instance. Used by map
-     * helpers.
+     * Cache of stores instantiated by the current instance. Used by devtools to
+     * list currently used stores.
      *
      * @internal
      */
index 72a95f9af3f4d3de722714d7363188d9ee2c1b3b..4a21dfcb419ef732211c2ee3d5f0b28f9f93f75c 100644 (file)
@@ -43,34 +43,10 @@ import {
 } from './rootStore'
 import { IS_CLIENT } from './env'
 
-function innerPatch<T extends StateTree>(
-  target: T,
-  patchToApply: DeepPartial<T>
-): T {
-  // TODO: get all keys like symbols as well
-  for (const key in patchToApply) {
-    const subPatch = patchToApply[key]
-    const targetValue = target[key]
-    if (
-      isPlainObject(targetValue) &&
-      isPlainObject(subPatch) &&
-      !isRef(subPatch) &&
-      !isReactive(subPatch)
-    ) {
-      target[key] = innerPatch(targetValue, subPatch)
-    } else {
-      // @ts-ignore
-      target[key] = subPatch
-    }
-  }
-
-  return target
-}
-
-const { assign } = Object
-
 /**
- * Create an object of computed properties referring to
+ * Create an object of computed properties referring to the root state. This
+ * allows direct modification of `store.state` while still changing the root
+ * state.
  *
  * @param rootStateRef - pinia.state
  * @param id - unique name
@@ -95,6 +71,32 @@ function computedFromState<T, Id extends string>(
   return reactiveObject
 }
 
+function innerPatch<T extends StateTree>(
+  target: T,
+  patchToApply: DeepPartial<T>
+): T {
+  // no need to go through symbols because they cannot be serialized anyway
+  for (const key in patchToApply) {
+    const subPatch = patchToApply[key]
+    const targetValue = target[key]
+    if (
+      isPlainObject(targetValue) &&
+      isPlainObject(subPatch) &&
+      !isRef(subPatch) &&
+      !isReactive(subPatch)
+    ) {
+      target[key] = innerPatch(targetValue, subPatch)
+    } else {
+      // @ts-ignore
+      target[key] = subPatch
+    }
+  }
+
+  return target
+}
+
+const { assign } = Object
+
 export interface DefineSetupStoreOptions<
   Id extends string,
   S extends StateTree,
index 3598bdacf183ac9b223c5378e6b50a53c857d2fe..d1eff336cb02e1384475730d294c9e2b6eba8b9d 100644 (file)
@@ -286,14 +286,6 @@ export interface StoreWithState<
    */
   $subscribe(callback: SubscriptionCallback<S>): () => void
 
-  /**
-   * Array of registered action subscriptions.Set without the generics to avoid
-   * errors between the generic version of Store and specific stores.
-   *
-   * @internal
-   */
-  _as: StoreOnActionListener[]
-
   /**
    * @alpha Please send feedback at https://github.com/posva/pinia/issues/240
    * Setups a callback to be called every time an action is about to get