Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
queryKey: ['test'],
queryFn: async () => {
states.current.push('fetching')
await sleep(5)
await sleep(10)
states.current.push('fetched')
return 'fetched'
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
<script lang="ts">
import { createQuery } from '@tanstack/svelte-query'
import { sleep } from '@tanstack/query-test-utils'
import type { StatelessRef, StatusResult } from '../utils.svelte.js'

let {
states,
onFetch,
}: {
states: StatelessRef<Array<StatusResult<string>>>
onFetch: () => void
} = $props()

const query = createQuery(() => ({
queryKey: ['test'],
queryFn: () => Promise.resolve('fetched'),

queryFn: () =>
sleep(10).then(() => {
onFetch()
return 'fetched'
}),
staleTime: Infinity,
}))

Expand All @@ -22,5 +28,5 @@
})
</script>

<div>data: {query.data ?? 'undefined'}</div>
<div>data: {query.data ?? 'null'}</div>
<div>fetchStatus: {query.fetchStatus}</div>
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
queryClient: QueryClient
persistOptions: OmitKeyof<PersistQueryClientOptions, 'queryClient'>
states: StatelessRef<Array<StatusResult<string>>>
onFetch: () => void
}

let { queryClient, persistOptions, states }: Props = $props()
let { queryClient, persistOptions, states, onFetch }: Props = $props()
</script>

<PersistQueryClientProvider client={queryClient} {persistOptions}>
<FreshData {states} />
<FreshData {states} {onFetch} />
</PersistQueryClientProvider>
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@
const query = createQuery(() => ({
queryKey: ['test'],
queryFn: async () => {
await sleep(5)
return 'fetched'
},
queryFn: () => sleep(10).then(() => 'fetched'),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this better than await ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TkDodo

In my opinion, sleep().then() is more concise than async/await. There's no functional difference, but it avoids the async keyword and extra braces, and makes the timer-to-callback dependency explicit in a single line. I discussed this with @manudeli.

// await: 4 lines
async () => {
  await sleep(10)
  return 'fetched'
}

// then: 1 line
() => sleep(10).then(() => 'fetched')

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay but we have over 350 instances of await sleep(...) and I think it’s unnecessary to refactor them β€œjust because”. This is also only true if you have a single await statement, we also sometimes have:

mutationFn: async () => {
  results.push('start-A')
  await sleep(10)
  results.push('finish-A')
  return 'a'
}

which is much more readable with async/await.

If it’s all the same, I’d like to keep it as-is.

Copy link
Contributor Author

@sukvvon sukvvon Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the .then() ones from the fake timers PRs that already got merged stay put, use .then() for single-statement cases as I suggested, and keep await otherwise from now on?

initialData: 'initial',
// make sure that initial data is older than the hydration data
// otherwise initialData would be newer and takes precedence
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script lang="ts">
import { createQuery } from '@tanstack/svelte-query'
import { sleep } from '@tanstack/query-test-utils'

const query = createQuery(() => ({
queryKey: ['test'],
queryFn: () => Promise.resolve('fetched'),
queryFn: () => sleep(10).then(() => 'fetched'),
}))
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { render, waitFor } from '@testing-library/svelte'
import { describe, expect, test, vi } from 'vitest'
import { render } from '@testing-library/svelte'
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
import { QueryClient } from '@tanstack/svelte-query'
import { persistQueryClientSave } from '@tanstack/query-persist-client-core'
import { sleep } from '@tanstack/query-test-utils'
Expand All @@ -17,6 +17,14 @@ import type {
} from '@tanstack/query-persist-client-core'
import type { StatusResult } from './utils.svelte.js'

beforeEach(() => {
vi.useFakeTimers()
})

afterEach(() => {
vi.useRealTimers()
})

const createMockPersister = (): Persister => {
let storedState: PersistedClient | undefined

Expand All @@ -25,7 +33,7 @@ const createMockPersister = (): Persister => {
storedState = persistClient
},
async restoreClient() {
return Promise.resolve(storedState)
return sleep(10).then(() => storedState)
},
removeClient() {
storedState = undefined
Expand All @@ -44,7 +52,7 @@ const createMockErrorPersister = (
// noop
},
async restoreClient() {
return Promise.reject(error)
return sleep(10).then(() => Promise.reject(error))
},
removeClient,
},
Expand All @@ -56,14 +64,16 @@ describe('PersistQueryClientProvider', () => {
const states = new StatelessRef<Array<StatusResult<string>>>([])

const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryClient.prefetchQuery({
queryKey: ['test'],
queryFn: () => Promise.resolve('hydrated'),
queryFn: () => sleep(10).then(() => 'hydrated'),
})
await vi.advanceTimersByTimeAsync(10)

const persister = createMockPersister()

await persistQueryClientSave({ queryClient, persister })
persistQueryClientSave({ queryClient, persister })
await vi.advanceTimersByTimeAsync(0)

queryClient.clear()

Expand All @@ -75,9 +85,11 @@ describe('PersistQueryClientProvider', () => {
},
})

await waitFor(() => rendered.getByText('fetchStatus: idle'))
await waitFor(() => rendered.getByText('hydrated'))
await waitFor(() => rendered.getByText('fetched'))
expect(rendered.getByText('fetchStatus: idle')).toBeInTheDocument()
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('hydrated')).toBeInTheDocument()
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('fetched')).toBeInTheDocument()

expect(states.current).toHaveLength(3)

Expand All @@ -104,14 +116,16 @@ describe('PersistQueryClientProvider', () => {
const states = new StatelessRef<Array<StatusResult<string>>>([])

const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryClient.prefetchQuery({
queryKey: ['test'],
queryFn: () => Promise.resolve('hydrated'),
queryFn: () => sleep(10).then(() => 'hydrated'),
})
await vi.advanceTimersByTimeAsync(10)

const persister = createMockPersister()

await persistQueryClientSave({ queryClient, persister })
persistQueryClientSave({ queryClient, persister })
await vi.advanceTimersByTimeAsync(0)

queryClient.clear()

Expand All @@ -123,9 +137,11 @@ describe('PersistQueryClientProvider', () => {
},
})

await waitFor(() => rendered.getByText('fetchStatus: idle'))
await waitFor(() => rendered.getByText('hydrated'))
await waitFor(() => rendered.getByText('fetched'))
expect(rendered.getByText('fetchStatus: idle')).toBeInTheDocument()
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('hydrated')).toBeInTheDocument()
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('fetched')).toBeInTheDocument()

expect(states.current).toHaveLength(3)

Expand All @@ -152,14 +168,16 @@ describe('PersistQueryClientProvider', () => {
const states = new StatelessRef<Array<StatusResult<string>>>([])

const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryClient.prefetchQuery({
queryKey: ['test'],
queryFn: () => Promise.resolve('hydrated'),
queryFn: () => sleep(10).then(() => 'hydrated'),
})
await vi.advanceTimersByTimeAsync(10)

const persister = createMockPersister()

await persistQueryClientSave({ queryClient, persister })
persistQueryClientSave({ queryClient, persister })
await vi.advanceTimersByTimeAsync(0)

queryClient.clear()

Expand All @@ -171,9 +189,11 @@ describe('PersistQueryClientProvider', () => {
},
})

await waitFor(() => rendered.getByText('initial'))
await waitFor(() => rendered.getByText('hydrated'))
await waitFor(() => rendered.getByText('fetched'))
expect(rendered.getByText('initial')).toBeInTheDocument()
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('hydrated')).toBeInTheDocument()
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('fetched')).toBeInTheDocument()

expect(states.current).toHaveLength(3)

Expand All @@ -200,35 +220,42 @@ describe('PersistQueryClientProvider', () => {
const states = new StatelessRef<Array<StatusResult<string>>>([])

const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryClient.prefetchQuery({
queryKey: ['test'],
queryFn: () => Promise.resolve('hydrated'),
queryFn: () => sleep(10).then(() => 'hydrated'),
})
await vi.advanceTimersByTimeAsync(10)

const persister = createMockPersister()

await persistQueryClientSave({ queryClient, persister })
persistQueryClientSave({ queryClient, persister })
await vi.advanceTimersByTimeAsync(0)

queryClient.clear()

let fetched = false

const rendered = render(FreshData, {
props: {
queryClient,
persistOptions: { persister },
states,
onFetch: () => {
fetched = true
},
},
})

await waitFor(() => rendered.getByText('data: undefined'))
await waitFor(() => rendered.getByText('data: hydrated'))
await expect(
waitFor(() => rendered.getByText('data: fetched'), {
timeout: 100,
}),
).rejects.toThrowError()
expect(rendered.getByText('data: null')).toBeInTheDocument()
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('data: hydrated')).toBeInTheDocument()
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('data: hydrated')).toBeInTheDocument()

expect(states.current).toHaveLength(2)

expect(fetched).toBe(false)

expect(states.current[0]).toMatchObject({
status: 'pending',
fetchStatus: 'idle',
Expand All @@ -244,14 +271,16 @@ describe('PersistQueryClientProvider', () => {

test('should call onSuccess after successful restoring', async () => {
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryClient.prefetchQuery({
queryKey: ['test'],
queryFn: () => Promise.resolve('hydrated'),
queryFn: () => sleep(10).then(() => 'hydrated'),
})
await vi.advanceTimersByTimeAsync(10)

const persister = createMockPersister()

await persistQueryClientSave({ queryClient, persister })
persistQueryClientSave({ queryClient, persister })
await vi.advanceTimersByTimeAsync(0)

queryClient.clear()

Expand All @@ -266,21 +295,25 @@ describe('PersistQueryClientProvider', () => {
})

expect(onSuccess).toHaveBeenCalledTimes(0)
await waitFor(() => rendered.getByText('hydrated'))
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('hydrated')).toBeInTheDocument()
expect(onSuccess).toHaveBeenCalledTimes(1)
await waitFor(() => rendered.getByText('fetched'))
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('fetched')).toBeInTheDocument()
})

test('should await onSuccess after successful restoring', async () => {
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryClient.prefetchQuery({
queryKey: ['test'],
queryFn: () => Promise.resolve('hydrated'),
queryFn: () => sleep(10).then(() => 'hydrated'),
})
await vi.advanceTimersByTimeAsync(10)

const persister = createMockPersister()

await persistQueryClientSave({ queryClient, persister })
persistQueryClientSave({ queryClient, persister })
await vi.advanceTimersByTimeAsync(0)

queryClient.clear()

Expand All @@ -299,8 +332,10 @@ describe('PersistQueryClientProvider', () => {
},
})

await waitFor(() => rendered.getByText('hydrated'))
await waitFor(() => rendered.getByText('fetched'))
await vi.advanceTimersByTimeAsync(15)
expect(rendered.getByText('hydrated')).toBeInTheDocument()
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('fetched')).toBeInTheDocument()

expect(states.current).toEqual([
'onSuccess',
Expand Down Expand Up @@ -329,7 +364,9 @@ describe('PersistQueryClientProvider', () => {
props: { queryClient, persistOptions: { persister }, onError, onSuccess },
})

await waitFor(() => rendered.getByText('fetched'))
await vi.advanceTimersByTimeAsync(10)
await vi.advanceTimersByTimeAsync(10)
expect(rendered.getByText('fetched')).toBeInTheDocument()
expect(removeClient).toHaveBeenCalledTimes(1)
expect(onSuccess).toHaveBeenCalledTimes(0)
expect(onError).toHaveBeenCalledTimes(1)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script lang="ts">
import { createQuery } from '@tanstack/svelte-query'
import { sleep } from '@tanstack/query-test-utils'

const query = createQuery(() => ({
queryKey: ['test'],
queryFn: () => Promise.resolve('fetched'),
queryFn: () => sleep(10).then(() => 'fetched'),
}))
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<script lang="ts">
import { createQuery } from '@tanstack/svelte-query'
import { sleep } from '@tanstack/query-test-utils'
import type { StatelessRef, StatusResult } from '../utils.svelte.js'

let { states }: { states: StatelessRef<Array<StatusResult<string>>> } =
$props()

const query = createQuery(() => ({
queryKey: ['test'],
queryFn: async () => Promise.resolve('fetched'),
queryFn: () => sleep(10).then(() => 'fetched'),
}))

$effect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { createQueries } from '@tanstack/svelte-query'
import { sleep } from '@tanstack/query-test-utils'
import type { StatelessRef, StatusResult } from '../utils.svelte.js'

let { states }: { states: StatelessRef<Array<StatusResult<string>>> } =
Expand All @@ -9,7 +10,7 @@
queries: [
{
queryKey: ['test'],
queryFn: () => Promise.resolve('fetched'),
queryFn: () => sleep(10).then(() => 'fetched'),
},
],
}))
Expand Down
Loading