import { describe, expect, it, vi } from 'vitest'
import { createTestingPinia, TestingOptions } from './testing'
-import { createPinia, defineStore, setActivePinia } from 'pinia'
+import { createPinia, defineStore, setActivePinia, storeToRefs } from 'pinia'
import { mount } from '@vue/test-utils'
import { defineComponent, ref, computed } from 'vue'
describe('Testing', () => {
const useCounter = defineStore('counter', {
- state: () => ({ n: 0 }),
+ state: () => ({ n: 0, doubleComputedCallCount: 0 }),
getters: {
- double: (state) => state.n * 2,
+ double: (state) => {
+ // NOTE: not supposed to be done in a getter...
+ state.doubleComputedCallCount++
+ return state.n * 2
+ },
doublePlusOne(): number {
return this.double + 1
},
const useCounterSetup = defineStore('counter-setup', () => {
const n = ref(0)
- const double = computed(() => n.value * 2)
+ const doubleComputedCallCount = ref(0)
+ const double = computed(() => {
+ doubleComputedCallCount.value++
+ return n.value * 2
+ })
const doublePlusOne = computed(() => double.value + 1)
function increment(amount = 1) {
n.value += amount
n.value = 0
}
- return { n, double, doublePlusOne, increment, $reset }
+ return {
+ n,
+ doubleComputedCallCount,
+ double,
+ doublePlusOne,
+ increment,
+ $reset,
+ }
})
type CounterStore =
expect(store.doublePlusOne).toBe(7)
})
})
+
+ // https://github.com/vuejs/pinia/issues/2913
+ it('does not compute getters immediately with storeToRefs', () => {
+ const pinia = createTestingPinia()
+ const store = useStore(pinia)
+
+ expect(store.doubleComputedCallCount).toBe(0)
+ storeToRefs(store)
+ expect(store.doubleComputedCallCount).toBe(0)
+ })
}
it('works with no actions', () => {
-import { createApp, customRef, isReactive, isRef, toRaw, triggerRef } from 'vue'
+import { computed, createApp, isReactive, isRef, toRaw, triggerRef } from 'vue'
import type { App, ComputedRef, WritableComputedRef } from 'vue'
import {
Pinia,
_DeepPartial,
PiniaPluginContext,
} from 'pinia'
+// NOTE: the implementation type is correct and contains up to date types
+// while the other types hide internal properties
+import type { ComputedRefImpl } from '@vue/reactivity'
export interface TestingOptions {
/**
function isComputed<T>(
v: ComputedRef<T> | WritableComputedRef<T> | unknown
-): v is ComputedRef<T> | WritableComputedRef<T> {
+): v is (ComputedRef<T> | WritableComputedRef<T>) & ComputedRefImpl<T> {
return !!v && isRef(v) && 'effect' in v
}
for (const key in rawStore) {
const originalComputed = rawStore[key]
if (isComputed(originalComputed)) {
- const originalFn = originalComputed.effect.fn
- rawStore[key] = customRef((track, trigger) => {
- // override the computed with a new one
- const overriddenFn = () =>
- // @ts-expect-error: internal value
- originalComputed._value
- // originalComputed.effect.fn = overriddenFn
- return {
- get: () => {
- track()
- return originalComputed.value
- },
- set: (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()
- },
- }
+ const originalFn = originalComputed.fn
+ // override the computed with a new one
+ const overriddenFn = () =>
+ // @ts-expect-error: internal cached value
+ originalComputed._value
+ // originalComputed.fn = overriddenFn
+
+ rawStore[key] = computed<unknown>({
+ get() {
+ return originalComputed.value
+ },
+ set(newValue) {
+ // reset the computed to its original value by setting it to its initial state
+ if (newValue === undefined) {
+ originalComputed.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.fn = overriddenFn
+ // @ts-expect-error: private api
+ originalComputed._value = newValue
+ }
+ // this allows to trigger the original computed in setup stores
+ triggerRef(originalComputed)
+ },
})
}
}