Skip to content

test(solid-query): use fake timers for useMutation.test.tsx #9081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
test(solid-query): use fake timers for useMutation.test.tsx
  • Loading branch information
manudeli committed Apr 29, 2025
commit 7a77af9d88a93b10f457f3a6b6637dca6fc9a1df
134 changes: 67 additions & 67 deletions packages/solid-query/src/__tests__/useMutation.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { describe, expect, it, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import {
ErrorBoundary,
createEffect,
createRenderEffect,
createSignal,
} from 'solid-js'
import { fireEvent, render, waitFor } from '@solidjs/testing-library'
import { fireEvent, render } from '@solidjs/testing-library'
import { MutationCache, QueryCache, QueryClientProvider, useMutation } from '..'
import {
createQueryClient,
Expand All @@ -17,6 +17,14 @@ import {
import type { UseMutationResult } from '../types'

describe('useMutation', () => {
beforeEach(() => {
vi.useFakeTimers()
})

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

const queryCache = new QueryCache()
const mutationCache = new MutationCache()
const queryClient = createQueryClient({ queryCache, mutationCache })
Expand Down Expand Up @@ -46,15 +54,14 @@ describe('useMutation', () => {

fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))

await waitFor(() => {
await vi.waitFor(() => {
expect(rendered.getByRole('heading').textContent).toBe('mutation')
})

fireEvent.click(rendered.getByRole('button', { name: /reset/i }))

await waitFor(() => {
expect(rendered.getByRole('heading').textContent).toBe('empty')
})
await vi.waitFor(() => {})
expect(rendered.getByRole('heading').textContent).toBe('empty')
})

it('should be able to reset `error`', async () => {
Expand Down Expand Up @@ -86,21 +93,19 @@ describe('useMutation', () => {
</QueryClientProvider>
))

await waitFor(() => {
expect(rendered.queryByRole('heading')).toBeNull()
})
expect(rendered.queryByRole('heading')).toBeNull()

fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))

await waitFor(() => {
await vi.waitFor(() => {
expect(rendered.getByRole('heading').textContent).toBe(
'Expected mock error. All is well!',
)
})

fireEvent.click(rendered.getByRole('button', { name: /reset/i }))

await waitFor(() => {
await vi.waitFor(() => {
expect(rendered.queryByRole('heading')).toBeNull()
})

Expand Down Expand Up @@ -150,19 +155,19 @@ describe('useMutation', () => {
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))

await waitFor(() => {
await vi.waitFor(() => {
expect(rendered.getByRole('heading').textContent).toBe('3')
})

await waitFor(() => {
await vi.waitFor(() => {
expect(onSuccessMock).toHaveBeenCalledTimes(3)
})

expect(onSuccessMock).toHaveBeenCalledWith(1)
expect(onSuccessMock).toHaveBeenCalledWith(2)
expect(onSuccessMock).toHaveBeenCalledWith(3)

await waitFor(() => {
await vi.waitFor(() => {
expect(onSettledMock).toHaveBeenCalledTimes(3)
})

Expand All @@ -177,14 +182,11 @@ describe('useMutation', () => {

const mutateFn = vi.fn<(value: Value) => Promise<Value>>()

mutateFn.mockImplementationOnce(() => {
return Promise.reject(new Error('Error test Jonas'))
})
mutateFn.mockImplementationOnce(() =>
Promise.reject(new Error('Error test Jonas')),
)

mutateFn.mockImplementation(async (value) => {
await sleep(10)
return Promise.resolve(value)
})
mutateFn.mockImplementation((value) => sleep(10).then(() => value))

function Page() {
const mutation = useMutation(() => ({
Expand Down Expand Up @@ -215,20 +217,22 @@ describe('useMutation', () => {
</QueryClientProvider>
))

await waitFor(() => rendered.getByText('Data'))
rendered.getByText('Data')

fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
await waitFor(() => rendered.getByText('Data'))
await waitFor(() => rendered.getByText('Status error'))
await waitFor(() => rendered.getByText('Failed 1 times'))
await waitFor(() => rendered.getByText('Failed because Error test Jonas'))
rendered.getByText('Data')
await vi.waitFor(() => rendered.getByText('Status error'))
await vi.waitFor(() => rendered.getByText('Failed 1 times'))
await vi.waitFor(() =>
rendered.getByText('Failed because Error test Jonas'),
)

fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
await waitFor(() => rendered.getByText('Status pending'))
await waitFor(() => rendered.getByText('Status success'))
await waitFor(() => rendered.getByText('Data 2'))
await waitFor(() => rendered.getByText('Failed 0 times'))
await waitFor(() => rendered.getByText('Failed because null'))
await vi.waitFor(() => rendered.getByText('Status pending'))
await vi.waitFor(() => rendered.getByText('Status success'))
await vi.waitFor(() => rendered.getByText('Data 2'))
await vi.waitFor(() => rendered.getByText('Failed 0 times'))
await vi.waitFor(() => rendered.getByText('Failed because null'))
})

it('should be able to call `onError` and `onSettled` after each failed mutate', async () => {
Expand Down Expand Up @@ -280,11 +284,11 @@ describe('useMutation', () => {
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))

await waitFor(() => {
await vi.waitFor(() => {
expect(rendered.getByRole('heading').textContent).toBe('3')
})

await waitFor(() => {
await vi.waitFor(() => {
expect(onErrorMock).toHaveBeenCalledTimes(3)
})
expect(onErrorMock).toHaveBeenCalledWith(
Expand All @@ -297,7 +301,7 @@ describe('useMutation', () => {
'Expected mock error. All is well! 3',
)

await waitFor(() => {
await vi.waitFor(() => {
expect(onSettledMock).toHaveBeenCalledTimes(3)
})
expect(onSettledMock).toHaveBeenCalledWith(
Expand Down Expand Up @@ -351,7 +355,7 @@ describe('useMutation', () => {
</QueryClientProvider>
))

await sleep(100)
await vi.advanceTimersByTimeAsync(10)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Strictly but not flaky

expect(callbacks).toEqual([
'useMutation.onSuccess',
Expand All @@ -367,7 +371,7 @@ describe('useMutation', () => {

function Page() {
const mutation = useMutation(() => ({
mutationFn: async (_text: string) => Promise.reject(new Error('oops')),
mutationFn: (_text: string) => Promise.reject(new Error('oops')),

onError: () => {
callbacks.push('useMutation.onError')
Expand Down Expand Up @@ -404,7 +408,7 @@ describe('useMutation', () => {
</QueryClientProvider>
))

await sleep(100)
await vi.advanceTimersByTimeAsync(10)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Strictly but not flaky

expect(callbacks).toEqual([
'useMutation.onError',
Expand All @@ -419,10 +423,7 @@ describe('useMutation', () => {
const key = queryKey()

queryClient.setMutationDefaults(key, {
mutationFn: async (text: string) => {
await sleep(10)
return text
},
mutationFn: (text: string) => sleep(10).then(() => text),
})

const states: Array<UseMutationResult<any, any, any, any>> = []
Expand Down Expand Up @@ -452,7 +453,7 @@ describe('useMutation', () => {
</QueryClientProvider>
))

await sleep(100)
await vi.advanceTimersByTimeAsync(20)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Strictly but not flaky

expect(states.length).toBe(3)
expect(states[0]).toMatchObject({ data: undefined, isPending: false })
Expand Down Expand Up @@ -489,7 +490,7 @@ describe('useMutation', () => {
</QueryClientProvider>
))

await sleep(100)
await vi.advanceTimersByTimeAsync(20)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Strictly but not flaky

expect(count).toBe(2)
})
Expand Down Expand Up @@ -529,34 +530,27 @@ describe('useMutation', () => {
</QueryClientProvider>
))

await waitFor(() => {
expect(
rendered.getByText('error: null, status: idle, isPaused: false'),
).toBeInTheDocument()
})
expect(
rendered.getByText('error: null, status: idle, isPaused: false'),
).toBeInTheDocument()

window.dispatchEvent(new Event('offline'))

fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))

await waitFor(() => {
expect(
rendered.getByText('error: null, status: pending, isPaused: true'),
).toBeInTheDocument()
})
expect(
rendered.getByText('error: null, status: pending, isPaused: true'),
).toBeInTheDocument()

expect(count).toBe(0)

onlineMock.mockRestore()
window.dispatchEvent(new Event('online'))

await sleep(100)

await waitFor(() => {
expect(
rendered.getByText('error: oops, status: error, isPaused: false'),
).toBeInTheDocument()
})
await vi.advanceTimersByTimeAsync(5)
expect(
rendered.getByText('error: oops, status: error, isPaused: false'),
).toBeInTheDocument()

expect(count).toBe(2)
})
Expand Down Expand Up @@ -607,6 +601,7 @@ describe('useMutation', () => {
onlineMock.mockRestore()
window.dispatchEvent(new Event('online'))

await vi.advanceTimersByTimeAsync(10)
await rendered.findByText('data: 1, status: success, isPaused: false')

expect(onMutate).toHaveBeenCalledTimes(1)
Expand Down Expand Up @@ -661,6 +656,7 @@ describe('useMutation', () => {
onlineMock.mockReturnValue(true)
window.dispatchEvent(new Event('online'))

await vi.advanceTimersByTimeAsync(10)
await rendered.findByText('data: 1, status: success, isPaused: false')

onlineMock.mockRestore()
Expand Down Expand Up @@ -707,7 +703,7 @@ describe('useMutation', () => {
</QueryClientProvider>
))

await sleep(50)
await vi.advanceTimersByTimeAsync(16)

expect(states.length).toBe(4)
expect(states[0]).toMatchObject({
Expand Down Expand Up @@ -738,7 +734,7 @@ describe('useMutation', () => {
onlineMock.mockRestore()
window.dispatchEvent(new Event('online'))

await sleep(50)
await vi.advanceTimersByTimeAsync(1)

expect(states.length).toBe(6)
expect(states[4]).toMatchObject({
Expand Down Expand Up @@ -818,7 +814,7 @@ describe('useMutation', () => {

fireEvent.click(rendered.getByText('mutate'))

await waitFor(() => {
await vi.waitFor(() => {
expect(rendered.queryByText('error')).not.toBeNull()
})

Expand Down Expand Up @@ -868,13 +864,13 @@ describe('useMutation', () => {

// first error goes to component
fireEvent.click(rendered.getByText('mutate'))
await waitFor(() => {
await vi.waitFor(() => {
expect(rendered.queryByText('mock error')).not.toBeNull()
})

// second error goes to boundary
fireEvent.click(rendered.getByText('mutate'))
await waitFor(() => {
await vi.waitFor(() => {
expect(rendered.queryByText('error boundary')).not.toBeNull()
})

Expand Down Expand Up @@ -930,7 +926,7 @@ describe('useMutation', () => {
fireEvent.click(rendered.getByText('succeed'))
fireEvent.click(rendered.getByText('error'))

await waitFor(() => {
await vi.waitFor(() => {
expect(rendered.queryByText('successTest')).not.toBeNull()
expect(rendered.queryByText('errorTest')).not.toBeNull()
})
Expand Down Expand Up @@ -1003,7 +999,7 @@ describe('useMutation', () => {
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
fireEvent.click(rendered.getByRole('button', { name: /hide/i }))

await waitFor(() => {
await vi.waitFor(() => {
expect(
queryClient.getMutationCache().findAll({ mutationKey: mutationKey }),
).toHaveLength(0)
Expand Down Expand Up @@ -1065,6 +1061,7 @@ describe('useMutation', () => {
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))
fireEvent.click(rendered.getByRole('button', { name: /mutate/i }))

await vi.advanceTimersByTimeAsync(10)
await rendered.findByText('data: result2, status: success')

expect(count).toBe(2)
Expand Down Expand Up @@ -1114,6 +1111,7 @@ describe('useMutation', () => {

rendered.getByRole('button', { name: /mutate/i }).click()

await vi.advanceTimersByTimeAsync(10)
await rendered.findByText('status: error')

expect(onError).toHaveBeenCalledWith(error, 'todo', undefined)
Expand Down Expand Up @@ -1154,6 +1152,7 @@ describe('useMutation', () => {

rendered.getByRole('button', { name: /mutate/i }).click()

await vi.advanceTimersByTimeAsync(10)
await rendered.findByText('error: mutateFnError, status: error')
})

Expand Down Expand Up @@ -1194,6 +1193,7 @@ describe('useMutation', () => {

rendered.getByRole('button', { name: /mutate/i }).click()

await vi.advanceTimersByTimeAsync(10)
await rendered.findByText('error: mutateFnError, status: error')

expect(onError).toHaveBeenCalledWith(mutateFnError, 'todo', undefined)
Expand Down
Loading