From 192dd2c4dd0e18cd58e53cede07b4659fe935ace Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 26 Nov 2025 19:28:08 +0000 Subject: [PATCH 1/6] fix: auto-start sync for on-demand collections to enable write operations On-demand collections were throwing SyncNotInitializedError when users tried to call writeUpsert or other write operations. This happened because the sync function was only invoked when startSync: true was explicitly set, but write operations require the sync infrastructure to be initialized. For on-demand collections, starting sync is cheap (no data is fetched until loadSubset is called), so we now automatically start sync when syncMode is 'on-demand'. This ensures write operations work immediately while maintaining the on-demand loading behavior. Fixes the issue where users with on-demand collections could not manually insert related records using writeUpsert. --- packages/db/src/collection/index.ts | 7 +- .../query-db-collection/tests/query.test.ts | 64 +++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/packages/db/src/collection/index.ts b/packages/db/src/collection/index.ts index 5616a8ceb..ff0bdc3d9 100644 --- a/packages/db/src/collection/index.ts +++ b/packages/db/src/collection/index.ts @@ -310,8 +310,11 @@ export class CollectionImpl< events: this._events, }) - // Only start sync immediately if explicitly enabled - if (config.startSync === true) { + // Start sync immediately if: + // 1. Explicitly enabled via startSync: true + // 2. Collection uses on-demand sync mode - sync must be started for write + // operations to work, but no data will be fetched until loadSubset is called + if (config.startSync === true || config.syncMode === `on-demand`) { this._sync.startSync() } } diff --git a/packages/query-db-collection/tests/query.test.ts b/packages/query-db-collection/tests/query.test.ts index 0c4408646..b552fefb9 100644 --- a/packages/query-db-collection/tests/query.test.ts +++ b/packages/query-db-collection/tests/query.test.ts @@ -1622,6 +1622,70 @@ describe(`QueryCollection`, () => { expect(collection.has(`1`)).toBe(false) }) + it(`should allow write operations on on-demand collections without startSync`, async () => { + // This test verifies that on-demand collections can perform write operations + // even when startSync is not explicitly set to true. + // See: https://github.com/TanStack/db/issues/xyz - SyncNotInitializedError + // was thrown when trying to writeUpsert on on-demand collections + + const queryKey = [`on-demand-write-test`] + const queryFn = vi.fn().mockResolvedValue([]) + + const config: QueryCollectionConfig = { + id: `on-demand-write-collection`, + queryClient, + queryKey, + queryFn, + getKey, + syncMode: `on-demand`, + // Note: startSync is NOT set to true - this was the bug scenario + } + + const options = queryCollectionOptions(config) + const collection = createCollection(options) + + // On-demand collections should be ready immediately + await vi.waitFor(() => { + expect(collection.status).toBe(`ready`) + }) + + // Write operations should work without throwing SyncNotInitializedError + const newItem: TestItem = { id: `1`, name: `Item 1`, value: 10 } + collection.utils.writeInsert(newItem) + + expect(collection.size).toBe(1) + expect(collection.get(`1`)).toEqual(newItem) + + // Test writeUpsert (the specific operation from the bug report) + collection.utils.writeUpsert({ id: `2`, name: `Item 2`, value: 20 }) + + expect(collection.size).toBe(2) + expect(collection.get(`2`)).toEqual({ + id: `2`, + name: `Item 2`, + value: 20, + }) + + // Test writeUpdate + collection.utils.writeUpdate({ id: `1`, name: `Updated Item 1` }) + expect(collection.get(`1`)?.name).toBe(`Updated Item 1`) + + // Test writeDelete + collection.utils.writeDelete(`1`) + expect(collection.size).toBe(1) + expect(collection.has(`1`)).toBe(false) + + // Test writeBatch + collection.utils.writeBatch(() => { + collection.utils.writeInsert({ id: `3`, name: `Item 3`, value: 30 }) + collection.utils.writeUpsert({ id: `4`, name: `Item 4`, value: 40 }) + }) + + expect(collection.size).toBe(3) + expect(collection.get(`3`)?.name).toBe(`Item 3`) + expect(collection.get(`4`)?.name).toBe(`Item 4`) + }) + it(`should handle sync method errors appropriately`, async () => { const queryKey = [`sync-error-test`] const initialItems: Array = [{ id: `1`, name: `Item 1` }] From c3ecea979d4c3b8d91cf169853b615e92208baa2 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 26 Nov 2025 19:37:45 +0000 Subject: [PATCH 2/6] chore: add changeset for on-demand write operations fix --- .changeset/fix-on-demand-write-operations.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-on-demand-write-operations.md diff --git a/.changeset/fix-on-demand-write-operations.md b/.changeset/fix-on-demand-write-operations.md new file mode 100644 index 000000000..94cfe18c6 --- /dev/null +++ b/.changeset/fix-on-demand-write-operations.md @@ -0,0 +1,5 @@ +--- +"@tanstack/db": patch +--- + +Fixed `SyncNotInitializedError` being thrown when calling write operations (`writeUpsert`, `writeInsert`, etc.) on collections with `syncMode: 'on-demand'`. Previously, write operations required `startSync: true` to be explicitly set, even though on-demand collections don't fetch data automatically. Now, sync is automatically started for on-demand collections, enabling write operations to work immediately while maintaining the on-demand loading behavior. From bcaa1382d7d7c123ff8aed546781a8428f24cf5d Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 26 Nov 2025 19:55:27 +0000 Subject: [PATCH 3/6] test: update on-demand preload test to reflect auto-start sync behavior On-demand collections now start in 'ready' status immediately since sync is auto-started to enable write operations. Updated the test to expect 'ready' instead of 'idle' initial status while still verifying no data is loaded until loadSubset is called. --- packages/query-db-collection/tests/query.test.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/query-db-collection/tests/query.test.ts b/packages/query-db-collection/tests/query.test.ts index b552fefb9..d1c9248f4 100644 --- a/packages/query-db-collection/tests/query.test.ts +++ b/packages/query-db-collection/tests/query.test.ts @@ -3006,17 +3006,16 @@ describe(`QueryCollection`, () => { const options = queryCollectionOptions(config) const collection = createCollection(options) - // Collection should be idle initially - expect(collection.status).toBe(`idle`) + // On-demand collections are ready immediately (sync auto-starts for write support) + // but no data is loaded until loadSubset is called + expect(collection.status).toBe(`ready`) expect(queryFn).not.toHaveBeenCalled() expect(collection.size).toBe(0) - // Preload should resolve immediately without calling queryFn - // since there's no initial query in on-demand mode + // Preload is a no-op for on-demand collections (logs a warning) await collection.preload() - // After preload, collection should be ready - // but queryFn should NOT have been called and collection should still be empty + // Collection should still be ready with no data loaded expect(collection.status).toBe(`ready`) expect(queryFn).not.toHaveBeenCalled() expect(collection.size).toBe(0) From b3057d6f363cd97e3d0532fc5c90b1daaa699523 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 3 Dec 2025 15:38:08 +0000 Subject: [PATCH 4/6] fix: auto-start sync for write operations on idle collections Instead of only auto-starting sync for on-demand collections, we now auto-start sync whenever any write operation is called on a collection that hasn't been initialized yet. This provides a more general solution that works for both eager and on-demand collections. Changes: - Modified QueryCollectionUtilsImpl to store a collection reference - Write methods now call _ensureSyncStarted() before executing - Collection passes its reference to utils via _setCollection() - Updated tests to verify sync auto-starts on first write operation --- .changeset/fix-on-demand-write-operations.md | 3 +- packages/db/src/collection/index.ts | 12 +-- packages/query-db-collection/src/query.ts | 79 ++++++++++++++++--- .../query-db-collection/tests/query.test.ts | 35 ++++---- 4 files changed, 98 insertions(+), 31 deletions(-) diff --git a/.changeset/fix-on-demand-write-operations.md b/.changeset/fix-on-demand-write-operations.md index 94cfe18c6..dd12d5179 100644 --- a/.changeset/fix-on-demand-write-operations.md +++ b/.changeset/fix-on-demand-write-operations.md @@ -1,5 +1,6 @@ --- "@tanstack/db": patch +"@tanstack/query-db-collection": patch --- -Fixed `SyncNotInitializedError` being thrown when calling write operations (`writeUpsert`, `writeInsert`, etc.) on collections with `syncMode: 'on-demand'`. Previously, write operations required `startSync: true` to be explicitly set, even though on-demand collections don't fetch data automatically. Now, sync is automatically started for on-demand collections, enabling write operations to work immediately while maintaining the on-demand loading behavior. +Fixed `SyncNotInitializedError` being thrown when calling write operations (`writeUpsert`, `writeInsert`, etc.) on collections before sync is started. Previously, write operations required `startSync: true` to be explicitly set or `preload()` to be called first. Now, sync is automatically started when any write operation is called on an idle collection, enabling write operations to work immediately without explicit initialization. diff --git a/packages/db/src/collection/index.ts b/packages/db/src/collection/index.ts index ff0bdc3d9..40ffbce79 100644 --- a/packages/db/src/collection/index.ts +++ b/packages/db/src/collection/index.ts @@ -310,13 +310,15 @@ export class CollectionImpl< events: this._events, }) - // Start sync immediately if: - // 1. Explicitly enabled via startSync: true - // 2. Collection uses on-demand sync mode - sync must be started for write - // operations to work, but no data will be fetched until loadSubset is called - if (config.startSync === true || config.syncMode === `on-demand`) { + // Only start sync immediately if explicitly enabled + if (config.startSync === true) { this._sync.startSync() } + + // Allow utils to trigger sync start for write operations + if (typeof config.utils?._setCollection === `function`) { + config.utils._setCollection(this) + } } /** diff --git a/packages/query-db-collection/src/query.ts b/packages/query-db-collection/src/query.ts index 8b98ec570..3e9a6f4cd 100644 --- a/packages/query-db-collection/src/query.ts +++ b/packages/query-db-collection/src/query.ts @@ -212,6 +212,15 @@ interface QueryCollectionState { > } +/** + * Minimal interface for collection reference needed by utils + * to auto-start sync when write operations are called + */ +interface CollectionRef { + status: `idle` | `loading` | `ready` | `error` | `cleaned-up` + startSyncImmediate: () => void +} + /** * Implementation class for QueryCollectionUtils with explicit dependency injection * for better testability and architectural clarity @@ -219,14 +228,11 @@ interface QueryCollectionState { class QueryCollectionUtilsImpl { private state: QueryCollectionState private refetchFn: RefetchFn + private _writeUtils: ReturnType + private _collection: CollectionRef | null = null // Write methods public refetch: RefetchFn - public writeInsert: any - public writeUpdate: any - public writeDelete: any - public writeUpsert: any - public writeBatch: any constructor( state: QueryCollectionState, @@ -235,14 +241,67 @@ class QueryCollectionUtilsImpl { ) { this.state = state this.refetchFn = refetch + this._writeUtils = writeUtils // Initialize methods to use passed dependencies this.refetch = refetch - this.writeInsert = writeUtils.writeInsert - this.writeUpdate = writeUtils.writeUpdate - this.writeDelete = writeUtils.writeDelete - this.writeUpsert = writeUtils.writeUpsert - this.writeBatch = writeUtils.writeBatch + } + + /** + * Called by the collection after creation to allow utils to trigger sync start. + * This enables write operations to work even before sync is explicitly started. + * @internal + */ + public _setCollection(collection: CollectionRef): void { + this._collection = collection + } + + /** + * Ensures sync is started before write operations. + * This allows writes to work on collections that haven't been explicitly preloaded. + */ + private _ensureSyncStarted(): void { + if (this._collection) { + const status = this._collection.status + if (status === `idle` || status === `cleaned-up`) { + this._collection.startSyncImmediate() + } + } + } + + public writeInsert( + ...args: Parameters[`writeInsert`]> + ) { + this._ensureSyncStarted() + return this._writeUtils.writeInsert(...args) + } + + public writeUpdate( + ...args: Parameters[`writeUpdate`]> + ) { + this._ensureSyncStarted() + return this._writeUtils.writeUpdate(...args) + } + + public writeDelete( + ...args: Parameters[`writeDelete`]> + ) { + this._ensureSyncStarted() + return this._writeUtils.writeDelete(...args) + } + + public writeUpsert( + ...args: Parameters[`writeUpsert`]> + ) { + this._ensureSyncStarted() + return this._writeUtils.writeUpsert(...args) + } + + public writeBatch( + ...args: Parameters[`writeBatch`]> + ) { + this._ensureSyncStarted() + return this._writeUtils.writeBatch(...args) } public async clearError() { diff --git a/packages/query-db-collection/tests/query.test.ts b/packages/query-db-collection/tests/query.test.ts index d1c9248f4..d260d918c 100644 --- a/packages/query-db-collection/tests/query.test.ts +++ b/packages/query-db-collection/tests/query.test.ts @@ -1622,11 +1622,11 @@ describe(`QueryCollection`, () => { expect(collection.has(`1`)).toBe(false) }) - it(`should allow write operations on on-demand collections without startSync`, async () => { - // This test verifies that on-demand collections can perform write operations + it(`should auto-start sync when write operations are called on idle collections`, async () => { + // This test verifies that write operations automatically start sync // even when startSync is not explicitly set to true. - // See: https://github.com/TanStack/db/issues/xyz - SyncNotInitializedError - // was thrown when trying to writeUpsert on on-demand collections + // This fixes SyncNotInitializedError when trying to writeUpsert on + // collections that haven't been preloaded yet. const queryKey = [`on-demand-write-test`] const queryFn = vi.fn().mockResolvedValue([]) @@ -1638,21 +1638,22 @@ describe(`QueryCollection`, () => { queryFn, getKey, syncMode: `on-demand`, - // Note: startSync is NOT set to true - this was the bug scenario + // Note: startSync is NOT set to true - sync should auto-start on write } const options = queryCollectionOptions(config) const collection = createCollection(options) - // On-demand collections should be ready immediately - await vi.waitFor(() => { - expect(collection.status).toBe(`ready`) - }) + // Collection starts in idle state (sync not started yet) + expect(collection.status).toBe(`idle`) + expect(queryFn).not.toHaveBeenCalled() - // Write operations should work without throwing SyncNotInitializedError + // Write operation should auto-start sync and work without error const newItem: TestItem = { id: `1`, name: `Item 1`, value: 10 } collection.utils.writeInsert(newItem) + // After write, collection should be ready (sync was auto-started) + expect(collection.status).toBe(`ready`) expect(collection.size).toBe(1) expect(collection.get(`1`)).toEqual(newItem) @@ -1684,6 +1685,9 @@ describe(`QueryCollection`, () => { expect(collection.size).toBe(3) expect(collection.get(`3`)?.name).toBe(`Item 3`) expect(collection.get(`4`)?.name).toBe(`Item 4`) + + // queryFn should still not be called since no data was loaded via loadSubset + expect(queryFn).not.toHaveBeenCalled() }) it(`should handle sync method errors appropriately`, async () => { @@ -3006,16 +3010,17 @@ describe(`QueryCollection`, () => { const options = queryCollectionOptions(config) const collection = createCollection(options) - // On-demand collections are ready immediately (sync auto-starts for write support) - // but no data is loaded until loadSubset is called - expect(collection.status).toBe(`ready`) + // Collection should be idle initially + expect(collection.status).toBe(`idle`) expect(queryFn).not.toHaveBeenCalled() expect(collection.size).toBe(0) - // Preload is a no-op for on-demand collections (logs a warning) + // Preload should resolve immediately without calling queryFn + // since there's no initial query in on-demand mode await collection.preload() - // Collection should still be ready with no data loaded + // After preload, collection should be ready + // but queryFn should NOT have been called and collection should still be empty expect(collection.status).toBe(`ready`) expect(queryFn).not.toHaveBeenCalled() expect(collection.size).toBe(0) From 0c76796b9f5389280cd77006febc727a631e326a Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 3 Dec 2025 15:46:40 +0000 Subject: [PATCH 5/6] fix: auto-start sync for mutations and write operations on idle collections Extended the auto-start sync behavior to cover both mutations and write operations: 1. Mutations (insert, update, delete) - handled by adding 'idle' to the validateCollectionUsable() switch case in lifecycle.ts 2. Write operations (writeInsert, writeUpsert, etc.) - handled by passing the collection reference to utils via _setCollection() so they can call startSyncImmediate() when needed This ensures both types of write operations work on collections that haven't been explicitly preloaded, fixing SyncNotInitializedError. --- .changeset/fix-on-demand-write-operations.md | 2 +- packages/db/src/collection/index.ts | 9 ++++----- packages/db/src/collection/lifecycle.ts | 3 ++- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.changeset/fix-on-demand-write-operations.md b/.changeset/fix-on-demand-write-operations.md index dd12d5179..28d741e92 100644 --- a/.changeset/fix-on-demand-write-operations.md +++ b/.changeset/fix-on-demand-write-operations.md @@ -3,4 +3,4 @@ "@tanstack/query-db-collection": patch --- -Fixed `SyncNotInitializedError` being thrown when calling write operations (`writeUpsert`, `writeInsert`, etc.) on collections before sync is started. Previously, write operations required `startSync: true` to be explicitly set or `preload()` to be called first. Now, sync is automatically started when any write operation is called on an idle collection, enabling write operations to work immediately without explicit initialization. +Fixed `SyncNotInitializedError` being thrown when calling write operations (`writeUpsert`, `writeInsert`, etc.) or mutations (`insert`, `update`, `delete`) on collections before sync is started. Previously, these operations required `startSync: true` to be explicitly set or `preload()` to be called first. Now, sync is automatically started when any write operation or mutation is called on an idle collection, enabling these operations to work immediately without explicit initialization. diff --git a/packages/db/src/collection/index.ts b/packages/db/src/collection/index.ts index 40ffbce79..3f9913aef 100644 --- a/packages/db/src/collection/index.ts +++ b/packages/db/src/collection/index.ts @@ -193,6 +193,10 @@ export function createCollection( // Attach utils to collection if (options.utils) { collection.utils = options.utils + // Allow utils to trigger sync start for write operations + if (typeof options.utils._setCollection === `function`) { + options.utils._setCollection(collection) + } } else { collection.utils = {} } @@ -314,11 +318,6 @@ export class CollectionImpl< if (config.startSync === true) { this._sync.startSync() } - - // Allow utils to trigger sync start for write operations - if (typeof config.utils?._setCollection === `function`) { - config.utils._setCollection(this) - } } /** diff --git a/packages/db/src/collection/lifecycle.ts b/packages/db/src/collection/lifecycle.ts index 5181ab216..a4a04390e 100644 --- a/packages/db/src/collection/lifecycle.ts +++ b/packages/db/src/collection/lifecycle.ts @@ -129,8 +129,9 @@ export class CollectionLifecycleManager< switch (this.status) { case `error`: throw new CollectionInErrorStateError(operation, this.id) + case `idle`: case `cleaned-up`: - // Automatically restart the collection when operations are called on cleaned-up collections + // Automatically start sync when operations are called on idle/cleaned-up collections this.sync.startSync() break } From 13c731477c61e4628aed3f0e41e5939d64bfa704 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 3 Dec 2025 15:57:13 +0000 Subject: [PATCH 6/6] refactor: simplify auto-start sync by using utils getter Instead of passing collection reference via _setCollection, make utils a getter that calls validateCollectionUsable() before returning. This auto-starts sync when any util method is accessed, without needing special internal APIs. Changes: - Made utils a getter/setter in CollectionImpl that validates on access - Removed _setCollection and _ensureSyncStarted from QueryCollectionUtilsImpl - Updated test to reflect new auto-start behavior when accessing utils --- packages/db/src/collection/index.ts | 18 +++-- packages/query-db-collection/src/query.ts | 79 +++---------------- .../query-db-collection/tests/query.test.ts | 12 ++- 3 files changed, 30 insertions(+), 79 deletions(-) diff --git a/packages/db/src/collection/index.ts b/packages/db/src/collection/index.ts index 3f9913aef..9fa67717e 100644 --- a/packages/db/src/collection/index.ts +++ b/packages/db/src/collection/index.ts @@ -193,10 +193,6 @@ export function createCollection( // Attach utils to collection if (options.utils) { collection.utils = options.utils - // Allow utils to trigger sync start for write operations - if (typeof options.utils._setCollection === `function`) { - options.utils._setCollection(collection) - } } else { collection.utils = {} } @@ -214,9 +210,17 @@ export class CollectionImpl< public id: string public config: CollectionConfig - // Utilities namespace - // This is populated by createCollection - public utils: Record = {} + // Utilities namespace - stored privately, accessed via getter that validates collection state + private _utils: Record = {} + + public get utils(): Record { + this._lifecycle.validateCollectionUsable(`utils`) + return this._utils + } + + public set utils(value: Record) { + this._utils = value + } // Managers private _events: CollectionEventsManager diff --git a/packages/query-db-collection/src/query.ts b/packages/query-db-collection/src/query.ts index 3e9a6f4cd..8b98ec570 100644 --- a/packages/query-db-collection/src/query.ts +++ b/packages/query-db-collection/src/query.ts @@ -212,15 +212,6 @@ interface QueryCollectionState { > } -/** - * Minimal interface for collection reference needed by utils - * to auto-start sync when write operations are called - */ -interface CollectionRef { - status: `idle` | `loading` | `ready` | `error` | `cleaned-up` - startSyncImmediate: () => void -} - /** * Implementation class for QueryCollectionUtils with explicit dependency injection * for better testability and architectural clarity @@ -228,11 +219,14 @@ interface CollectionRef { class QueryCollectionUtilsImpl { private state: QueryCollectionState private refetchFn: RefetchFn - private _writeUtils: ReturnType - private _collection: CollectionRef | null = null // Write methods public refetch: RefetchFn + public writeInsert: any + public writeUpdate: any + public writeDelete: any + public writeUpsert: any + public writeBatch: any constructor( state: QueryCollectionState, @@ -241,67 +235,14 @@ class QueryCollectionUtilsImpl { ) { this.state = state this.refetchFn = refetch - this._writeUtils = writeUtils // Initialize methods to use passed dependencies this.refetch = refetch - } - - /** - * Called by the collection after creation to allow utils to trigger sync start. - * This enables write operations to work even before sync is explicitly started. - * @internal - */ - public _setCollection(collection: CollectionRef): void { - this._collection = collection - } - - /** - * Ensures sync is started before write operations. - * This allows writes to work on collections that haven't been explicitly preloaded. - */ - private _ensureSyncStarted(): void { - if (this._collection) { - const status = this._collection.status - if (status === `idle` || status === `cleaned-up`) { - this._collection.startSyncImmediate() - } - } - } - - public writeInsert( - ...args: Parameters[`writeInsert`]> - ) { - this._ensureSyncStarted() - return this._writeUtils.writeInsert(...args) - } - - public writeUpdate( - ...args: Parameters[`writeUpdate`]> - ) { - this._ensureSyncStarted() - return this._writeUtils.writeUpdate(...args) - } - - public writeDelete( - ...args: Parameters[`writeDelete`]> - ) { - this._ensureSyncStarted() - return this._writeUtils.writeDelete(...args) - } - - public writeUpsert( - ...args: Parameters[`writeUpsert`]> - ) { - this._ensureSyncStarted() - return this._writeUtils.writeUpsert(...args) - } - - public writeBatch( - ...args: Parameters[`writeBatch`]> - ) { - this._ensureSyncStarted() - return this._writeUtils.writeBatch(...args) + this.writeInsert = writeUtils.writeInsert + this.writeUpdate = writeUtils.writeUpdate + this.writeDelete = writeUtils.writeDelete + this.writeUpsert = writeUtils.writeUpsert + this.writeBatch = writeUtils.writeBatch } public async clearError() { diff --git a/packages/query-db-collection/tests/query.test.ts b/packages/query-db-collection/tests/query.test.ts index d260d918c..db0c7f434 100644 --- a/packages/query-db-collection/tests/query.test.ts +++ b/packages/query-db-collection/tests/query.test.ts @@ -2541,7 +2541,7 @@ describe(`QueryCollection`, () => { await collection.cleanup() }) - it(`should be no-op when sync has not started (no observer created)`, async () => { + it(`should auto-start sync when utils are accessed`, async () => { const queryKey = [`refetch-test-no-sync`] const queryFn = vi.fn().mockResolvedValue([{ id: `1`, name: `A` }]) @@ -2556,9 +2556,15 @@ describe(`QueryCollection`, () => { }) ) - // Refetch should be no-op because observer doesn't exist yet + // Collection starts idle + expect(collection.status).toBe(`idle`) + + // Accessing utils auto-starts sync, so refetch will work await collection.utils.refetch() - expect(queryFn).not.toHaveBeenCalled() + + // Sync was started and queryFn was called + expect(collection.status).toBe(`ready`) + expect(queryFn).toHaveBeenCalled() await collection.cleanup() })