|
1 | 1 | import { describe, it, expect, vi } from 'vitest' |
2 | | -import { reactive, ref, shallowRef, computed, nextTick, watchEffect } from 'vue' |
| 2 | +import { reactive, ref, shallowRef, markRaw, watch } from 'vue' |
3 | 3 | import { createPinia, defineStore, Pinia, setActivePinia } from '../src' |
| 4 | +import { mockWarn } from './vitest-mock-warn' |
4 | 5 |
|
5 | 6 | describe('store.$patch', () => { |
| 7 | + mockWarn() |
| 8 | + |
6 | 9 | const useStore = () => { |
7 | 10 | // create a new store |
8 | 11 | setActivePinia(createPinia()) |
@@ -223,123 +226,93 @@ describe('store.$patch', () => { |
223 | 226 | const counter = shallowRef({ count: 0 }) |
224 | 227 | const counter2 = shallowRef({ count: 0 }) |
225 | 228 | const counter3 = shallowRef({ count: 0 }) |
| 229 | + const markedRaw = ref({ |
| 230 | + marked: markRaw({ count: 0 }), |
| 231 | + }) |
226 | 232 | const nestedCounter = shallowRef({ |
227 | 233 | nested: { count: 0 }, |
228 | 234 | simple: 1, |
229 | 235 | }) |
230 | 236 |
|
231 | | - return { counter, counter2, counter3, nestedCounter } |
| 237 | + return { |
| 238 | + markedRaw, |
| 239 | + counter, |
| 240 | + counter2, |
| 241 | + counter3, |
| 242 | + nestedCounter, |
| 243 | + } |
232 | 244 | })() |
233 | 245 | } |
234 | 246 |
|
| 247 | + it('does not trigger reactivity when patching marked raw', async () => { |
| 248 | + const store = useShallowRefStore() |
| 249 | + const markedSpy = vi.fn() |
| 250 | + const nestedSpy = vi.fn() |
| 251 | + watch(() => store.markedRaw.marked, markedSpy, { |
| 252 | + flush: 'sync', |
| 253 | + deep: true, |
| 254 | + }) |
| 255 | + watch(() => store.markedRaw.marked.count, nestedSpy, { flush: 'sync' }) |
| 256 | + store.$patch({ markedRaw: { marked: { count: 1 } } }) |
| 257 | + expect(nestedSpy).toHaveBeenCalledTimes(0) |
| 258 | + expect(markedSpy).toHaveBeenCalledTimes(0) |
| 259 | + }) |
| 260 | + |
235 | 261 | it('triggers reactivity when patching shallowRef with object syntax', async () => { |
236 | 262 | const store = useShallowRefStore() |
237 | 263 | const watcherSpy = vi.fn() |
238 | 264 |
|
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 | | - }) |
| 265 | + watch(() => store.counter.count, watcherSpy, { flush: 'sync' }) |
246 | 266 |
|
247 | | - expect(watcherSpy).toHaveBeenCalledWith(0) |
248 | 267 | watcherSpy.mockClear() |
249 | | - |
250 | | - // Patch using object syntax - this should trigger reactivity |
251 | 268 | store.$patch({ counter: { count: 1 } }) |
252 | 269 |
|
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() |
| 270 | + expect(watcherSpy).toHaveBeenCalledTimes(1) |
260 | 271 | }) |
261 | 272 |
|
262 | 273 | it('triggers reactivity when patching nested properties in shallowRef', async () => { |
263 | 274 | const store = useShallowRefStore() |
264 | 275 | const watcherSpy = vi.fn() |
265 | 276 |
|
266 | | - const nestedCount = computed(() => store.nestedCounter.nested.count) |
267 | | - |
268 | | - const stopWatcher = watchEffect(() => { |
269 | | - watcherSpy(nestedCount.value) |
| 277 | + watch(() => store.nestedCounter.nested.count, watcherSpy, { |
| 278 | + flush: 'sync', |
270 | 279 | }) |
271 | 280 |
|
272 | | - expect(watcherSpy).toHaveBeenCalledWith(0) |
273 | 281 | watcherSpy.mockClear() |
274 | | - |
275 | | - // Patch nested properties |
276 | 282 | store.$patch({ |
277 | 283 | nestedCounter: { |
278 | 284 | nested: { count: 5 }, |
279 | 285 | simple: 2, |
280 | 286 | }, |
281 | 287 | }) |
282 | 288 |
|
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() |
| 289 | + expect(watcherSpy).toHaveBeenCalledTimes(1) |
291 | 290 | }) |
292 | 291 |
|
293 | 292 | it('works with function syntax (baseline test)', async () => { |
294 | 293 | const store = useShallowRefStore() |
295 | 294 | const watcherSpy = vi.fn() |
296 | 295 |
|
297 | | - const doubleCount = computed(() => store.counter2.count * 2) |
| 296 | + watch(() => store.counter2.count, watcherSpy, { flush: 'sync' }) |
298 | 297 |
|
299 | | - const stopWatcher = watchEffect(() => { |
300 | | - watcherSpy(doubleCount.value) |
301 | | - }) |
302 | | - |
303 | | - expect(watcherSpy).toHaveBeenCalledWith(0) |
304 | 298 | watcherSpy.mockClear() |
305 | | - |
306 | | - // Function syntax should work (this was already working) |
307 | 299 | store.$patch((state) => { |
308 | 300 | state.counter2 = { count: state.counter2.count + 1 } |
309 | 301 | }) |
310 | 302 |
|
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() |
| 303 | + expect(watcherSpy).toHaveBeenCalledTimes(1) |
318 | 304 | }) |
319 | 305 |
|
320 | 306 | it('works with direct assignment (baseline test)', async () => { |
321 | 307 | const store = useShallowRefStore() |
322 | 308 | const watcherSpy = vi.fn() |
323 | 309 |
|
324 | | - const doubleCount = computed(() => store.counter3.count * 2) |
| 310 | + watch(() => store.counter3.count, watcherSpy, { flush: 'sync' }) |
325 | 311 |
|
326 | | - const stopWatcher = watchEffect(() => { |
327 | | - watcherSpy(doubleCount.value) |
328 | | - }) |
329 | | - |
330 | | - expect(watcherSpy).toHaveBeenCalledWith(0) |
331 | 312 | watcherSpy.mockClear() |
332 | | - |
333 | | - // Direct assignment should work (this was already working) |
334 | 313 | store.counter3 = { count: 3 } |
335 | 314 |
|
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() |
| 315 | + expect(watcherSpy).toHaveBeenCalledTimes(1) |
343 | 316 | }) |
344 | 317 |
|
345 | 318 | it('handles partial updates correctly', async () => { |
@@ -368,35 +341,19 @@ describe('store.$patch', () => { |
368 | 341 | const watcherSpy1 = vi.fn() |
369 | 342 | const watcherSpy2 = vi.fn() |
370 | 343 |
|
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 | | - }) |
| 344 | + watch(() => store.counter.count, watcherSpy1, { flush: 'sync' }) |
| 345 | + watch(() => store.counter2.count, watcherSpy2, { flush: 'sync' }) |
381 | 346 |
|
382 | 347 | watcherSpy1.mockClear() |
383 | 348 | watcherSpy2.mockClear() |
384 | 349 |
|
385 | | - // Patch multiple shallowRefs at once |
386 | 350 | store.$patch({ |
387 | 351 | counter: { count: 10 }, |
388 | 352 | counter2: { count: 20 }, |
389 | 353 | }) |
390 | 354 |
|
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() |
| 355 | + expect(watcherSpy1).toHaveBeenCalledTimes(1) |
| 356 | + expect(watcherSpy2).toHaveBeenCalledTimes(1) |
400 | 357 | }) |
401 | 358 | }) |
402 | 359 | }) |
0 commit comments