|
1 |
| -import { describe, it, expect } from 'vitest' |
2 |
| -import { reactive, ref } from 'vue' |
| 1 | +import { describe, it, expect, vi } from 'vitest' |
| 2 | +import { reactive, ref, shallowRef, computed, nextTick, watchEffect } from 'vue' |
3 | 3 | import { createPinia, defineStore, Pinia, setActivePinia } from '../src'
|
4 | 4 |
|
5 | 5 | describe('store.$patch', () => {
|
@@ -215,4 +215,188 @@ describe('store.$patch', () => {
|
215 | 215 | expect(store.item).toEqual({ a: 1, b: 1 })
|
216 | 216 | })
|
217 | 217 | })
|
| 218 | + |
| 219 | + describe('shallowRef reactivity', () => { |
| 220 | + const useShallowRefStore = () => { |
| 221 | + setActivePinia(createPinia()) |
| 222 | + return defineStore('shallowRef', () => { |
| 223 | + const counter = shallowRef({ count: 0 }) |
| 224 | + const counter2 = shallowRef({ count: 0 }) |
| 225 | + const counter3 = shallowRef({ count: 0 }) |
| 226 | + const nestedCounter = shallowRef({ |
| 227 | + nested: { count: 0 }, |
| 228 | + simple: 1, |
| 229 | + }) |
| 230 | + |
| 231 | + return { counter, counter2, counter3, nestedCounter } |
| 232 | + })() |
| 233 | + } |
| 234 | + |
| 235 | + it('triggers reactivity when patching shallowRef with object syntax', async () => { |
| 236 | + const store = useShallowRefStore() |
| 237 | + const watcherSpy = vi.fn() |
| 238 | + |
| 239 | + // Create a computed that depends on the shallowRef |
| 240 | + const doubleCount = computed(() => store.counter.count * 2) |
| 241 | + |
| 242 | + // Watch the computed to verify reactivity |
| 243 | + const stopWatcher = watchEffect(() => { |
| 244 | + watcherSpy(doubleCount.value) |
| 245 | + }) |
| 246 | + |
| 247 | + expect(watcherSpy).toHaveBeenCalledWith(0) |
| 248 | + watcherSpy.mockClear() |
| 249 | + |
| 250 | + // Patch using object syntax - this should trigger reactivity |
| 251 | + store.$patch({ counter: { count: 1 } }) |
| 252 | + |
| 253 | + await nextTick() |
| 254 | + |
| 255 | + expect(store.counter.count).toBe(1) |
| 256 | + expect(doubleCount.value).toBe(2) |
| 257 | + expect(watcherSpy).toHaveBeenCalledWith(2) |
| 258 | + |
| 259 | + stopWatcher() |
| 260 | + }) |
| 261 | + |
| 262 | + it('triggers reactivity when patching nested properties in shallowRef', async () => { |
| 263 | + const store = useShallowRefStore() |
| 264 | + const watcherSpy = vi.fn() |
| 265 | + |
| 266 | + const nestedCount = computed(() => store.nestedCounter.nested.count) |
| 267 | + |
| 268 | + const stopWatcher = watchEffect(() => { |
| 269 | + watcherSpy(nestedCount.value) |
| 270 | + }) |
| 271 | + |
| 272 | + expect(watcherSpy).toHaveBeenCalledWith(0) |
| 273 | + watcherSpy.mockClear() |
| 274 | + |
| 275 | + // Patch nested properties |
| 276 | + store.$patch({ |
| 277 | + nestedCounter: { |
| 278 | + nested: { count: 5 }, |
| 279 | + simple: 2, |
| 280 | + }, |
| 281 | + }) |
| 282 | + |
| 283 | + await nextTick() |
| 284 | + |
| 285 | + expect(store.nestedCounter.nested.count).toBe(5) |
| 286 | + expect(store.nestedCounter.simple).toBe(2) |
| 287 | + expect(nestedCount.value).toBe(5) |
| 288 | + expect(watcherSpy).toHaveBeenCalledWith(5) |
| 289 | + |
| 290 | + stopWatcher() |
| 291 | + }) |
| 292 | + |
| 293 | + it('works with function syntax (baseline test)', async () => { |
| 294 | + const store = useShallowRefStore() |
| 295 | + const watcherSpy = vi.fn() |
| 296 | + |
| 297 | + const doubleCount = computed(() => store.counter2.count * 2) |
| 298 | + |
| 299 | + const stopWatcher = watchEffect(() => { |
| 300 | + watcherSpy(doubleCount.value) |
| 301 | + }) |
| 302 | + |
| 303 | + expect(watcherSpy).toHaveBeenCalledWith(0) |
| 304 | + watcherSpy.mockClear() |
| 305 | + |
| 306 | + // Function syntax should work (this was already working) |
| 307 | + store.$patch((state) => { |
| 308 | + state.counter2 = { count: state.counter2.count + 1 } |
| 309 | + }) |
| 310 | + |
| 311 | + await nextTick() |
| 312 | + |
| 313 | + expect(store.counter2.count).toBe(1) |
| 314 | + expect(doubleCount.value).toBe(2) |
| 315 | + expect(watcherSpy).toHaveBeenCalledWith(2) |
| 316 | + |
| 317 | + stopWatcher() |
| 318 | + }) |
| 319 | + |
| 320 | + it('works with direct assignment (baseline test)', async () => { |
| 321 | + const store = useShallowRefStore() |
| 322 | + const watcherSpy = vi.fn() |
| 323 | + |
| 324 | + const doubleCount = computed(() => store.counter3.count * 2) |
| 325 | + |
| 326 | + const stopWatcher = watchEffect(() => { |
| 327 | + watcherSpy(doubleCount.value) |
| 328 | + }) |
| 329 | + |
| 330 | + expect(watcherSpy).toHaveBeenCalledWith(0) |
| 331 | + watcherSpy.mockClear() |
| 332 | + |
| 333 | + // Direct assignment should work (this was already working) |
| 334 | + store.counter3 = { count: 3 } |
| 335 | + |
| 336 | + await nextTick() |
| 337 | + |
| 338 | + expect(store.counter3.count).toBe(3) |
| 339 | + expect(doubleCount.value).toBe(6) |
| 340 | + expect(watcherSpy).toHaveBeenCalledWith(6) |
| 341 | + |
| 342 | + stopWatcher() |
| 343 | + }) |
| 344 | + |
| 345 | + it('handles partial updates correctly', async () => { |
| 346 | + const store = useShallowRefStore() |
| 347 | + |
| 348 | + // Set initial state with multiple properties |
| 349 | + store.nestedCounter = { |
| 350 | + nested: { count: 10 }, |
| 351 | + simple: 20, |
| 352 | + } |
| 353 | + |
| 354 | + // Patch only one property |
| 355 | + store.$patch({ |
| 356 | + nestedCounter: { |
| 357 | + nested: { count: 15 }, |
| 358 | + // Note: simple is not included, should remain unchanged |
| 359 | + }, |
| 360 | + }) |
| 361 | + |
| 362 | + expect(store.nestedCounter.nested.count).toBe(15) |
| 363 | + expect(store.nestedCounter.simple).toBe(20) // Should remain unchanged |
| 364 | + }) |
| 365 | + |
| 366 | + it('works with multiple shallowRefs in single patch', async () => { |
| 367 | + const store = useShallowRefStore() |
| 368 | + const watcherSpy1 = vi.fn() |
| 369 | + const watcherSpy2 = vi.fn() |
| 370 | + |
| 371 | + const count1 = computed(() => store.counter.count) |
| 372 | + const count2 = computed(() => store.counter2.count) |
| 373 | + |
| 374 | + const stopWatcher1 = watchEffect(() => { |
| 375 | + watcherSpy1(count1.value) |
| 376 | + }) |
| 377 | + |
| 378 | + const stopWatcher2 = watchEffect(() => { |
| 379 | + watcherSpy2(count2.value) |
| 380 | + }) |
| 381 | + |
| 382 | + watcherSpy1.mockClear() |
| 383 | + watcherSpy2.mockClear() |
| 384 | + |
| 385 | + // Patch multiple shallowRefs at once |
| 386 | + store.$patch({ |
| 387 | + counter: { count: 10 }, |
| 388 | + counter2: { count: 20 }, |
| 389 | + }) |
| 390 | + |
| 391 | + await nextTick() |
| 392 | + |
| 393 | + expect(store.counter.count).toBe(10) |
| 394 | + expect(store.counter2.count).toBe(20) |
| 395 | + expect(watcherSpy1).toHaveBeenCalledWith(10) |
| 396 | + expect(watcherSpy2).toHaveBeenCalledWith(20) |
| 397 | + |
| 398 | + stopWatcher1() |
| 399 | + stopWatcher2() |
| 400 | + }) |
| 401 | + }) |
218 | 402 | })
|
0 commit comments