]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
fix(testing): Vue 2 initial state reactive (#1165)
authorBlake Newman <blake.newman@askattest.com>
Thu, 31 Mar 2022 09:52:32 +0000 (10:52 +0100)
committerGitHub <noreply@github.com>
Thu, 31 Mar 2022 09:52:32 +0000 (11:52 +0200)
packages/testing/src/testing.ts

index 2317d481466b10ea896e38f19aef9f405dfb430f..cef0bb333a1f10db772655b6a99ab9417eaeecf7 100644 (file)
@@ -1,10 +1,11 @@
-import { App, createApp } from 'vue-demi'
+import { App, createApp, isReactive, isRef, isVue2, set } from 'vue-demi'
 import {
   Pinia,
   PiniaPlugin,
   setActivePinia,
   createPinia,
   StateTree,
+  _DeepPartial,
 } from 'pinia'
 
 export interface TestingOptions {
@@ -89,7 +90,7 @@ export function createTestingPinia({
 
   pinia.use(({ store }) => {
     if (initialState[store.$id]) {
-      store.$patch(initialState[store.$id])
+      mergeReactiveObjects(store.$state, initialState[store.$id])
     }
   })
 
@@ -131,3 +132,44 @@ export function createTestingPinia({
 
   return pinia as TestingPinia
 }
+
+function mergeReactiveObjects<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] = mergeReactiveObjects(targetValue, subPatch)
+    } else {
+      if (isVue2) {
+        set(target, key, subPatch)
+      } else {
+        // @ts-expect-error: subPatch is a valid value
+        target[key] = subPatch
+      }
+    }
+  }
+
+  return target
+}
+
+function isPlainObject<S extends StateTree>(value: S | unknown): value is S
+function isPlainObject(
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  o: any
+): o is StateTree {
+  return (
+    o &&
+    typeof o === 'object' &&
+    Object.prototype.toString.call(o) === '[object Object]' &&
+    typeof o.toJSON !== 'function'
+  )
+}