]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
fix(testing): override computed in setup stores
authorEduardo San Martin Morote <posva13@gmail.com>
Fri, 7 Apr 2023 12:36:01 +0000 (14:36 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Fri, 7 Apr 2023 12:36:01 +0000 (14:36 +0200)
Fix #2109

packages/testing/src/testing.spec.ts
packages/testing/src/testing.ts

index 6a3f2af2bb648ec7f8b87a55a087cc1b5d9c13c3..307cc901540af0d186c0ad49af15df4249bd6a7e 100644 (file)
@@ -226,6 +226,40 @@ describe('Testing', () => {
     expect(store.double).toBe(6)
   })
 
+  it('allows overriding computed properties in setup stores', () => {
+    const useStore = defineStore('computed', () => {
+      const n = ref(0)
+      const double = computed(() => n.value * 2)
+      const doublePlusOne = computed(() => double.value + 1)
+      return { n, double, doublePlusOne }
+    })
+    const pinia = createTestingPinia()
+    const store = useStore(pinia)
+
+    // console.log('is same', d === toRaw(store).double._computed)
+
+    store.n++
+    expect(store.double).toBe(2)
+    // once the getter is overridden, it stays
+    store.double = 3
+    expect(store.double).toBe(3)
+    expect(store.doublePlusOne).toBe(4)
+    store.n++
+    expect(store.double).toBe(3)
+    expect(store.doublePlusOne).toBe(4)
+    // it can be set to undefined again to reset
+    // @ts-expect-error
+    store.double = undefined
+    expect(store.n).toBe(2)
+    expect(store.double).toBe(4)
+    expect(store.doublePlusOne).toBe(5)
+    // it works again
+    store.n++
+    expect(store.n).toBe(3)
+    expect(store.double).toBe(6)
+    expect(store.doublePlusOne).toBe(7)
+  })
+
   it('actions are stubbed even when replaced by other plugins', () => {
     const spy = vi.fn()
     mount(Counter, {
index bdb4e47f3b2d27b75471a4dc05f02357c9ca47d7..b709bb6b03bd1ba847678370c3a63c637606d8f4 100644 (file)
@@ -7,6 +7,7 @@ import {
   isVue2,
   set,
   toRaw,
+  triggerRef,
 } from 'vue-demi'
 import type { ComputedRef, WritableComputedRef } from 'vue-demi'
 import {
@@ -205,17 +206,35 @@ function isComputed<T>(
 function WritableComputed({ store }: PiniaPluginContext) {
   const rawStore = toRaw(store)
   for (const key in rawStore) {
-    const value = rawStore[key]
-    if (isComputed(value)) {
+    const originalComputed = rawStore[key]
+    if (isComputed(originalComputed)) {
+      const originalFn = originalComputed.effect.fn
       rawStore[key] = customRef((track, trigger) => {
-        let internalValue: any
+        // override the computed with a new one
+        const overriddenFn = () =>
+          // @ts-expect-error: internal value
+          originalComputed._value
+        // originalComputed.effect.fn = overriddenFn
         return {
           get: () => {
             track()
-            return internalValue !== undefined ? internalValue : value.value
+            return originalComputed.value
           },
           set: (newValue) => {
-            internalValue = newValue
+            // reset the computed to its original value by setting it to its initial state
+            if (newValue === undefined) {
+              originalComputed.effect.fn = originalFn
+              // @ts-expect-error: private api to remove the current cached value
+              delete originalComputed._value
+              // @ts-expect-error: private api to force the recomputation
+              originalComputed._dirty = true
+            } else {
+              originalComputed.effect.fn = overriddenFn
+              // @ts-expect-error: private api
+              originalComputed._value = newValue
+            }
+            // this allows to trigger the original computed in setup stores
+            triggerRef(originalComputed)
             trigger()
           },
         }