Skip to content

Commit 17e4bd1

Browse files
committed
test: clean up test comments and remove redundant on-demand tests
- Remove "bug" references from proxy test comments - Remove on-demand syncMode tests from optimistic-action.test.ts that were always passing (the actual fix was in proxy.ts array iteration handling)
1 parent 74277a0 commit 17e4bd1

2 files changed

Lines changed: 2 additions & 359 deletions

File tree

packages/db/tests/optimistic-action.test.ts

Lines changed: 0 additions & 352 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { describe, expect, expectTypeOf, it, vi } from "vitest"
22
import { createCollection, createOptimisticAction } from "../src"
3-
import { createLiveQueryCollection, eq } from "../src/query"
43
import type {
54
MutationFnParams,
65
Transaction,
@@ -208,357 +207,6 @@ describe(`createOptimisticAction`, () => {
208207
expectTypeOf(userAction).returns.toEqualTypeOf<Transaction>()
209208
})
210209

211-
// Test with syncMode "on-demand"
212-
it(`should call mutationFn when using syncMode on-demand`, async () => {
213-
// This test reproduces the bug where mutationFn is not called
214-
// when the collection is configured with syncMode: "on-demand"
215-
// Bug report: https://discord.com/channels/...
216-
// - onMutate runs but mutationFn never runs
217-
// - works with eager mode but not on-demand
218-
219-
const onMutateMock = vi.fn()
220-
const mutationFnMock = vi.fn().mockResolvedValue({ success: true })
221-
222-
// Create a collection with syncMode: "on-demand"
223-
// This requires a loadSubset handler
224-
const collection = createCollection<{ id: string; text: string }>({
225-
id: `on-demand-collection`,
226-
getKey: (item) => item.id,
227-
syncMode: `on-demand`,
228-
sync: {
229-
sync: ({ markReady }) => {
230-
// For on-demand mode, we mark ready immediately but don't load data
231-
// Data is loaded on-demand via loadSubset
232-
markReady()
233-
234-
return {
235-
loadSubset: () => {
236-
// No-op for testing - just return true to indicate sync
237-
return true
238-
},
239-
}
240-
},
241-
},
242-
})
243-
244-
// Create an optimistic action
245-
const addTodo = createOptimisticAction<string>({
246-
onMutate: (text) => {
247-
collection.insert({ id: `1`, text })
248-
onMutateMock(text)
249-
},
250-
mutationFn: async (text, params) => {
251-
return Promise.resolve(mutationFnMock(text, params))
252-
},
253-
})
254-
255-
// Execute the optimistic action
256-
const transaction = addTodo(`Test Todo`)
257-
258-
// Verify onMutate was called
259-
expect(onMutateMock).toHaveBeenCalledWith(`Test Todo`)
260-
261-
// Verify the optimistic update was applied to the collection
262-
expect(collection.get(`1`)).toEqual({ id: `1`, text: `Test Todo` })
263-
264-
// Wait for the mutation to complete
265-
await transaction.isPersisted.promise
266-
267-
// BUG: mutationFn should be called but it's not!
268-
expect(mutationFnMock).toHaveBeenCalledTimes(1)
269-
})
270-
271-
// Test with syncMode "on-demand" where collection has NOT started sync yet
272-
it(`should call mutationFn when collection is not started (idle)`, async () => {
273-
// This test checks if mutationFn is called when the collection hasn't started sync
274-
const onMutateMock = vi.fn()
275-
const mutationFnMock = vi.fn().mockResolvedValue({ success: true })
276-
277-
// Create a collection that doesn't start sync automatically
278-
const collection = createCollection<{ id: string; text: string }>({
279-
id: `idle-collection`,
280-
getKey: (item) => item.id,
281-
startSync: false,
282-
sync: {
283-
sync: () => {
284-
// No-op sync for testing
285-
},
286-
},
287-
})
288-
289-
// Create an optimistic action
290-
const addTodo = createOptimisticAction<string>({
291-
onMutate: (text) => {
292-
collection.insert({ id: `1`, text })
293-
onMutateMock(text)
294-
},
295-
mutationFn: async (text, params) => {
296-
return Promise.resolve(mutationFnMock(text, params))
297-
},
298-
})
299-
300-
// Execute the optimistic action (collection is in idle state)
301-
const transaction = addTodo(`Test Todo`)
302-
303-
// Verify onMutate was called
304-
expect(onMutateMock).toHaveBeenCalledWith(`Test Todo`)
305-
306-
// Verify the optimistic update was applied
307-
expect(collection.get(`1`)).toEqual({ id: `1`, text: `Test Todo` })
308-
309-
// Wait for the mutation to complete
310-
await transaction.isPersisted.promise
311-
312-
// mutationFn should be called
313-
expect(mutationFnMock).toHaveBeenCalledTimes(1)
314-
})
315-
316-
// Test with syncMode "on-demand" where sync is in loading state (not ready yet)
317-
it(`should call mutationFn when collection is loading (not ready)`, async () => {
318-
// This test checks if mutationFn is called when the collection is still loading
319-
const onMutateMock = vi.fn()
320-
const mutationFnMock = vi.fn().mockResolvedValue({ success: true })
321-
322-
// Create a collection that starts sync but doesn't call markReady
323-
const collection = createCollection<{ id: string; text: string }>({
324-
id: `loading-collection`,
325-
getKey: (item) => item.id,
326-
startSync: true,
327-
sync: {
328-
sync: () => {
329-
// Intentionally don't call markReady - collection stays in "loading" state
330-
return () => {}
331-
},
332-
},
333-
})
334-
335-
// Create an optimistic action
336-
const addTodo = createOptimisticAction<string>({
337-
onMutate: (text) => {
338-
collection.insert({ id: `1`, text })
339-
onMutateMock(text)
340-
},
341-
mutationFn: async (text, params) => {
342-
return Promise.resolve(mutationFnMock(text, params))
343-
},
344-
})
345-
346-
// Execute the optimistic action (collection is in loading state)
347-
const transaction = addTodo(`Test Todo`)
348-
349-
// Verify onMutate was called
350-
expect(onMutateMock).toHaveBeenCalledWith(`Test Todo`)
351-
352-
// Verify the optimistic update was applied
353-
expect(collection.get(`1`)).toEqual({ id: `1`, text: `Test Todo` })
354-
355-
// Wait for the mutation to complete
356-
await transaction.isPersisted.promise
357-
358-
// mutationFn should be called
359-
expect(mutationFnMock).toHaveBeenCalledTimes(1)
360-
})
361-
362-
// Test with on-demand collection and a live query with filters - the reported scenario
363-
it(`should call mutationFn with on-demand collection and live query filter`, async () => {
364-
// This test attempts to reproduce the exact bug scenario:
365-
// - Base collection with syncMode: "on-demand"
366-
// - Live query collection with filters on top
367-
// - createOptimisticAction used to mutate the base collection
368-
// - Bug: onMutate runs but mutationFn never runs
369-
370-
const onMutateMock = vi.fn()
371-
const mutationFnMock = vi.fn().mockResolvedValue({ success: true })
372-
373-
// Create a base collection with syncMode: "on-demand"
374-
type Todo = { id: string; text: string; status: string }
375-
const baseCollection = createCollection<Todo>({
376-
id: `on-demand-base-collection`,
377-
getKey: (item) => item.id,
378-
syncMode: `on-demand`,
379-
startSync: true,
380-
sync: {
381-
sync: ({ markReady, begin, write, commit }) => {
382-
// Simulate on-demand mode: mark ready immediately, load data on demand
383-
markReady()
384-
385-
// Pre-populate with some data
386-
begin()
387-
write({
388-
type: `insert`,
389-
value: { id: `1`, text: `Existing todo`, status: `active` },
390-
})
391-
commit()
392-
393-
return {
394-
loadSubset: () => {
395-
return true
396-
},
397-
}
398-
},
399-
},
400-
})
401-
402-
// Create a live query collection with a filter on status
403-
const activeTodos = createLiveQueryCollection({
404-
id: `active-todos-query`,
405-
startSync: true,
406-
query: (q) =>
407-
q
408-
.from({ todo: baseCollection })
409-
.where(({ todo }) => eq(todo.status, `active`))
410-
.select(({ todo }) => ({ todo })),
411-
})
412-
413-
// Wait for the live query to be ready
414-
await activeTodos.preload()
415-
416-
// Verify initial state
417-
expect([...activeTodos.values()].length).toBe(1)
418-
expect([...activeTodos.values()][0]?.todo.text).toBe(`Existing todo`)
419-
420-
// Create an optimistic action to INSERT a new todo
421-
const addTodo = createOptimisticAction<{ text: string }>({
422-
onMutate: (input) => {
423-
baseCollection.insert({ id: `2`, text: input.text, status: `active` })
424-
onMutateMock(input)
425-
},
426-
mutationFn: async (input, params) => {
427-
return Promise.resolve(mutationFnMock(input, params))
428-
},
429-
})
430-
431-
// Execute the optimistic action
432-
const transaction = addTodo({ text: `New todo` })
433-
434-
// Verify onMutate was called
435-
expect(onMutateMock).toHaveBeenCalledWith({ text: `New todo` })
436-
437-
// Verify the optimistic update was applied to the base collection
438-
expect(baseCollection.get(`2`)).toEqual({
439-
id: `2`,
440-
text: `New todo`,
441-
status: `active`,
442-
})
443-
444-
// Wait for the mutation to complete
445-
await transaction.isPersisted.promise
446-
447-
// BUG: mutationFn should be called!
448-
expect(mutationFnMock).toHaveBeenCalledTimes(1)
449-
})
450-
451-
// Test UPDATE scenario which might have different behavior
452-
it(`should call mutationFn when UPDATE is performed on on-demand collection`, async () => {
453-
const onMutateMock = vi.fn()
454-
const mutationFnMock = vi.fn().mockResolvedValue({ success: true })
455-
456-
type Todo = { id: string; text: string; status: string }
457-
const collection = createCollection<Todo>({
458-
id: `on-demand-update-collection`,
459-
getKey: (item) => item.id,
460-
syncMode: `on-demand`,
461-
startSync: true,
462-
sync: {
463-
sync: ({ markReady, begin, write, commit }) => {
464-
markReady()
465-
466-
// Pre-populate with data
467-
begin()
468-
write({
469-
type: `insert`,
470-
value: { id: `1`, text: `Original text`, status: `active` },
471-
})
472-
commit()
473-
474-
return {
475-
loadSubset: () => true,
476-
}
477-
},
478-
},
479-
})
480-
481-
// Create an optimistic action to UPDATE an existing todo
482-
const updateTodo = createOptimisticAction<{ id: string; text: string }>({
483-
onMutate: (input) => {
484-
collection.update(input.id, (draft) => {
485-
draft.text = input.text
486-
})
487-
onMutateMock(input)
488-
},
489-
mutationFn: async (input, params) => {
490-
return Promise.resolve(mutationFnMock(input, params))
491-
},
492-
})
493-
494-
// Execute the optimistic action
495-
const transaction = updateTodo({ id: `1`, text: `Updated text` })
496-
497-
// Verify onMutate was called
498-
expect(onMutateMock).toHaveBeenCalledWith({ id: `1`, text: `Updated text` })
499-
500-
// Verify the optimistic update was applied
501-
expect(collection.get(`1`)?.text).toBe(`Updated text`)
502-
503-
// Wait for the mutation to complete
504-
await transaction.isPersisted.promise
505-
506-
// mutationFn should be called
507-
expect(mutationFnMock).toHaveBeenCalledTimes(1)
508-
})
509-
510-
// Debug test: verify mutations array is populated correctly
511-
it(`should have mutations in the transaction after onMutate completes`, async () => {
512-
const onMutateMock = vi.fn()
513-
const mutationFnMock = vi.fn().mockResolvedValue({ success: true })
514-
515-
// Create an on-demand collection with live query filter
516-
type Todo = { id: string; text: string; status: string }
517-
const baseCollection = createCollection<Todo>({
518-
id: `debug-collection`,
519-
getKey: (item) => item.id,
520-
syncMode: `on-demand`,
521-
startSync: true,
522-
sync: {
523-
sync: ({ markReady }) => {
524-
markReady()
525-
return {
526-
loadSubset: () => true,
527-
}
528-
},
529-
},
530-
})
531-
532-
// Track mutations count at mutationFn call time
533-
let mutationsAtMutationFn: number | undefined
534-
535-
const addTodo = createOptimisticAction<{ text: string }>({
536-
onMutate: (input) => {
537-
baseCollection.insert({ id: `1`, text: input.text, status: `active` })
538-
onMutateMock(input)
539-
},
540-
mutationFn: async (input, params) => {
541-
// Record the number of mutations at this point
542-
mutationsAtMutationFn = params.transaction.mutations.length
543-
return Promise.resolve(mutationFnMock(input, params))
544-
},
545-
})
546-
547-
const transaction = addTodo({ text: `Test` })
548-
549-
// Verify onMutate was called
550-
expect(onMutateMock).toHaveBeenCalled()
551-
552-
// Wait for the transaction to complete
553-
await transaction.isPersisted.promise
554-
555-
// Verify mutationFn was called
556-
expect(mutationFnMock).toHaveBeenCalledTimes(1)
557-
558-
// Verify there was at least one mutation
559-
expect(mutationsAtMutationFn).toBeGreaterThan(0)
560-
})
561-
562210
// Test error handling
563211
it(`should handle errors in mutationFn correctly`, async () => {
564212
// Setup a mock collection

packages/db/tests/proxy.test.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,9 +1654,7 @@ describe(`Proxy Library`, () => {
16541654
expect(obj.date).toEqual(originalDate)
16551655
})
16561656

1657-
// BUG: Array.find() returns unproxied items, so changes to them aren't tracked
1658-
// This is the root cause of the createOptimisticAction bug where mutationFn
1659-
// is never called when modifying nested array items via .find()
1657+
// Test that array iteration methods return proxied elements for change tracking
16601658
it(`should track changes when modifying array items retrieved via find()`, () => {
16611659
const obj = {
16621660
job: {
@@ -1668,22 +1666,19 @@ describe(`Proxy Library`, () => {
16681666
}
16691667
const { proxy, getChanges } = createChangeProxy(obj)
16701668

1671-
// This is the exact pattern from the user's reproduction:
1672-
// Using .find() to get an array item and then modifying it
1669+
// Use find() to get an array item and modify it
16731670
const order = proxy.job.orders.find(
16741671
(order) => order.orderId === `order-1`
16751672
)
16761673
if (order) {
16771674
order.orderBinInt = 99
16781675
}
16791676

1680-
// The changes should be tracked - this currently fails
16811677
const changes = getChanges()
16821678
expect(Object.keys(changes).length).toBeGreaterThan(0)
16831679
expect(changes.job?.orders?.[0]?.orderBinInt).toBe(99)
16841680
})
16851681

1686-
// Additional tests for other array iteration methods that should track changes
16871682
it(`should track changes when modifying array items via forEach`, () => {
16881683
const obj = {
16891684
items: [

0 commit comments

Comments
 (0)