Skip to content
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

test(query-core): use fake timers for mutationObserver.test.tsx #8805

Merged
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
148 changes: 66 additions & 82 deletions packages/query-core/src/__tests__/mutationObserver.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
import { waitFor } from '@testing-library/dom'
import { MutationObserver } from '..'
import { createQueryClient, queryKey, sleep } from './utils'
import type { QueryClient } from '..'
Expand All @@ -8,20 +7,19 @@ describe('mutationObserver', () => {
let queryClient: QueryClient

beforeEach(() => {
vi.useFakeTimers()
queryClient = createQueryClient()
queryClient.mount()
})

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

test('onUnsubscribe should not remove the current mutation observer if there is still a subscription', async () => {
const mutation = new MutationObserver(queryClient, {
mutationFn: async (text: string) => {
await sleep(20)
return text
},
mutationFn: (text: string) => sleep(20).then(() => text),
})

const subscription1Handler = vi.fn()
Expand All @@ -34,7 +32,7 @@ describe('mutationObserver', () => {

unsubscribe1()

await waitFor(() => {
await vi.waitFor(() => {
// 1 call: loading
expect(subscription1Handler).toBeCalledTimes(1)
// 2 calls: loading, success
Expand All @@ -47,48 +45,44 @@ describe('mutationObserver', () => {

test('unsubscribe should remove observer to trigger GC', async () => {
const mutation = new MutationObserver(queryClient, {
mutationFn: async (text: string) => {
await sleep(5)
return text
},
mutationFn: (text: string) => sleep(5).then(() => text),
gcTime: 10,
})

const subscriptionHandler = vi.fn()

const unsubscribe = mutation.subscribe(subscriptionHandler)

await mutation.mutate('input')

expect(queryClient.getMutationCache().findAll()).toHaveLength(1)
mutation.mutate('input')
await vi.waitFor(() =>
expect(queryClient.getMutationCache().findAll()).toHaveLength(1),
)

unsubscribe()

await waitFor(() =>
await vi.waitFor(() =>
expect(queryClient.getMutationCache().findAll()).toHaveLength(0),
)
})

test('reset should remove observer to trigger GC', async () => {
const mutation = new MutationObserver(queryClient, {
mutationFn: async (text: string) => {
await sleep(5)
return text
},
mutationFn: (text: string) => sleep(5).then(() => text),
gcTime: 10,
})

const subscriptionHandler = vi.fn()

const unsubscribe = mutation.subscribe(subscriptionHandler)

await mutation.mutate('input')

expect(queryClient.getMutationCache().findAll()).toHaveLength(1)
mutation.mutate('input')
await vi.waitFor(() =>
expect(queryClient.getMutationCache().findAll()).toHaveLength(1),
)

mutation.reset()

await waitFor(() =>
await vi.waitFor(() =>
expect(queryClient.getMutationCache().findAll()).toHaveLength(0),
)

Expand All @@ -99,22 +93,21 @@ describe('mutationObserver', () => {
const key = queryKey()
const mutation = new MutationObserver(queryClient, {
mutationKey: [...key, '1'],
mutationFn: async (text: string) => {
await sleep(5)
return text
},
mutationFn: (text: string) => sleep(5).then(() => text),
})

const subscriptionHandler = vi.fn()

const unsubscribe = mutation.subscribe(subscriptionHandler)

await mutation.mutate('input')
mutation.mutate('input')

expect(mutation.getCurrentResult()).toMatchObject({
status: 'success',
data: 'input',
})
await vi.waitFor(() =>
expect(mutation.getCurrentResult()).toMatchObject({
status: 'success',
data: 'input',
}),
)

mutation.setOptions({
mutationKey: [...key, '2'],
Expand All @@ -131,27 +124,26 @@ describe('mutationObserver', () => {
const key = queryKey()
const mutationObserver = new MutationObserver(queryClient, {
mutationKey: [...key, '1'],
mutationFn: async (text: string) => {
await sleep(5)
return text
},
mutationFn: (text: string) => sleep(5).then(() => text),
})

const subscriptionHandler = vi.fn()

const unsubscribe = mutationObserver.subscribe(subscriptionHandler)

await mutationObserver.mutate('input')
mutationObserver.mutate('input')

expect(
queryClient.getMutationCache().find({ mutationKey: [...key, '1'] }),
).toMatchObject({
options: { mutationKey: [...key, '1'] },
state: {
status: 'success',
data: 'input',
},
})
await vi.waitFor(() =>
expect(
queryClient.getMutationCache().find({ mutationKey: [...key, '1'] }),
).toMatchObject({
options: { mutationKey: [...key, '1'] },
state: {
status: 'success',
data: 'input',
},
}),
)

mutationObserver.setOptions({
mutationKey: [...key, '2'],
Expand All @@ -173,25 +165,24 @@ describe('mutationObserver', () => {
test('changing mutation meta should not affect successful mutations', async () => {
const mutationObserver = new MutationObserver(queryClient, {
meta: { a: 1 },
mutationFn: async (text: string) => {
await sleep(5)
return text
},
mutationFn: (text: string) => sleep(5).then(() => text),
})

const subscriptionHandler = vi.fn()

const unsubscribe = mutationObserver.subscribe(subscriptionHandler)

await mutationObserver.mutate('input')
mutationObserver.mutate('input')

expect(queryClient.getMutationCache().find({})).toMatchObject({
options: { meta: { a: 1 } },
state: {
status: 'success',
data: 'input',
},
})
await vi.waitFor(() =>
expect(queryClient.getMutationCache().find({})).toMatchObject({
options: { meta: { a: 1 } },
state: {
status: 'success',
data: 'input',
},
}),
)

mutationObserver.setOptions({
meta: { a: 2 },
Expand All @@ -209,10 +200,7 @@ describe('mutationObserver', () => {
})

test('mutation cache should have different meta when updated between mutations', async () => {
const mutationFn = async (text: string) => {
await sleep(5)
return text
}
const mutationFn = (text: string) => sleep(5).then(() => text)
const mutationObserver = new MutationObserver(queryClient, {
meta: { a: 1 },
mutationFn,
Expand All @@ -222,14 +210,16 @@ describe('mutationObserver', () => {

const unsubscribe = mutationObserver.subscribe(subscriptionHandler)

await mutationObserver.mutate('input')
mutationObserver.mutate('input')
await vi.advanceTimersByTimeAsync(5)

mutationObserver.setOptions({
meta: { a: 2 },
mutationFn,
})

await mutationObserver.mutate('input')
mutationObserver.mutate('input')
await vi.advanceTimersByTimeAsync(5)

const mutations = queryClient.getMutationCache().findAll()
expect(mutations[0]).toMatchObject({
Expand All @@ -253,24 +243,23 @@ describe('mutationObserver', () => {
test('changing mutation meta should not affect rejected mutations', async () => {
const mutationObserver = new MutationObserver(queryClient, {
meta: { a: 1 },
mutationFn: async (_: string) => {
await sleep(5)
return Promise.reject(new Error('err'))
},
mutationFn: (_: string) =>
sleep(5).then(() => Promise.reject(new Error('err'))),
})

const subscriptionHandler = vi.fn()

const unsubscribe = mutationObserver.subscribe(subscriptionHandler)

await mutationObserver.mutate('input').catch(() => undefined)

expect(queryClient.getMutationCache().find({})).toMatchObject({
options: { meta: { a: 1 } },
state: {
status: 'error',
},
})
mutationObserver.mutate('input').catch(() => undefined)
await vi.waitFor(() =>
expect(queryClient.getMutationCache().find({})).toMatchObject({
options: { meta: { a: 1 } },
state: {
status: 'error',
},
}),
)

mutationObserver.setOptions({
meta: { a: 2 },
Expand All @@ -289,20 +278,15 @@ describe('mutationObserver', () => {
test('changing mutation meta should affect pending mutations', async () => {
const mutationObserver = new MutationObserver(queryClient, {
meta: { a: 1 },
mutationFn: async (text: string) => {
await sleep(20)
return text
},
mutationFn: (text: string) => sleep(20).then(() => text),
})

const subscriptionHandler = vi.fn()

const unsubscribe = mutationObserver.subscribe(subscriptionHandler)

mutationObserver.mutate('input')

await sleep(0)

await vi.advanceTimersByTimeAsync(5)
expect(queryClient.getMutationCache().find({})).toMatchObject({
options: { meta: { a: 1 } },
state: {
Expand Down
Loading