Skip to content

Commit ffd404f

Browse files
test(svelte-query): Better createMutation tests (#7773)
1 parent 0edbc49 commit ffd404f

File tree

7 files changed

+224
-24
lines changed

7 files changed

+224
-24
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script lang="ts">
2+
import { QueryClient } from '@tanstack/query-core'
3+
import { createInfiniteQuery } from '../../src/index'
4+
import type { QueryObserverResult } from '@tanstack/query-core'
5+
import type { Writable } from 'svelte/store'
6+
7+
export let states: Writable<Array<QueryObserverResult>>
8+
9+
const queryClient = new QueryClient()
10+
11+
const query = createInfiniteQuery(
12+
{
13+
queryKey: ['test'],
14+
queryFn: () => Promise.resolve({ count: 1 }),
15+
select: (data) => ({
16+
pages: data.pages.map((x) => `count: ${x.count}`),
17+
pageParams: data.pageParams,
18+
}),
19+
getNextPageParam: () => undefined,
20+
initialPageParam: 0,
21+
},
22+
queryClient,
23+
)
24+
25+
$: states.update((prev) => [...prev, $query])
26+
</script>
27+
28+
<div>{$query.data?.pages.join(',')}</div>

packages/svelte-query/tests/createInfiniteQuery/createInfiniteQuery.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { describe, expect, test } from 'vitest'
22
import { render, waitFor } from '@testing-library/svelte'
33
import { get, writable } from 'svelte/store'
44
import BaseExample from './BaseExample.svelte'
5+
import SelectExample from './SelectExample.svelte'
56
import type { Writable } from 'svelte/store'
67
import type { QueryObserverResult } from '@tanstack/query-core'
78

@@ -93,4 +94,32 @@ describe('createInfiniteQuery', () => {
9394
fetchStatus: 'idle',
9495
})
9596
})
97+
98+
test('Select a part of the data', async () => {
99+
const statesStore: Writable<Array<QueryObserverResult>> = writable([])
100+
101+
const rendered = render(SelectExample, {
102+
props: {
103+
states: statesStore,
104+
},
105+
})
106+
107+
await waitFor(() => {
108+
expect(rendered.queryByText('count: 1')).toBeInTheDocument()
109+
})
110+
111+
const states = get(statesStore)
112+
113+
expect(states).toHaveLength(2)
114+
115+
expect(states[0]).toMatchObject({
116+
data: undefined,
117+
isSuccess: false,
118+
})
119+
120+
expect(states[1]).toMatchObject({
121+
data: { pages: ['count: 1'] },
122+
isSuccess: true,
123+
})
124+
})
96125
})

packages/svelte-query/tests/createMutation/BaseExample.svelte

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script lang="ts">
2+
import { writable } from 'svelte/store'
3+
import { QueryClient } from '@tanstack/query-core'
4+
import { setQueryClientContext } from '../../src/context'
5+
import { createMutation } from '../../src/createMutation'
6+
7+
export let mutationFn: (value: {
8+
count: number
9+
}) => Promise<{ count: number }>
10+
11+
const count = writable(0)
12+
13+
const queryClient = new QueryClient()
14+
setQueryClientContext(queryClient)
15+
16+
const mutation = createMutation({ mutationFn: mutationFn })
17+
</script>
18+
19+
<button on:click={() => $mutation.mutate({ count: ++$count })}>Mutate</button>
20+
21+
<div>Data: {$mutation.data?.count}</div>
22+
<div>Status: {$mutation.status}</div>
23+
<div>Failure Count: {$mutation.failureCount}</div>
24+
<div>Failure Reason: {$mutation.failureReason}</div>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script lang="ts">
2+
import { writable } from 'svelte/store'
3+
import { QueryClient } from '@tanstack/query-core'
4+
import { setQueryClientContext } from '../../src/context'
5+
import { createMutation } from '../../src/createMutation'
6+
7+
export let onSuccessMock: any
8+
export let onSettledMock: any
9+
10+
const count = writable(0)
11+
12+
const queryClient = new QueryClient()
13+
setQueryClientContext(queryClient)
14+
15+
const mutation = createMutation({
16+
mutationFn: (vars: { count: number }) => Promise.resolve(vars.count),
17+
onSuccess: (data) => {
18+
onSuccessMock(data)
19+
},
20+
onSettled: (data) => {
21+
onSettledMock(data)
22+
},
23+
})
24+
</script>
25+
26+
<button on:click={() => $mutation.mutate({ count: ++$count })}>Mutate</button>
27+
28+
<div>Count: {$count}</div>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<script lang="ts">
2+
import { QueryClient } from '@tanstack/query-core'
3+
import { setQueryClientContext } from '../../src/context'
4+
import { createMutation } from '../../src/createMutation'
5+
6+
const queryClient = new QueryClient()
7+
setQueryClientContext(queryClient)
8+
9+
const mutation = createMutation({
10+
mutationFn: () => {
11+
const err = new Error('Expected mock error')
12+
err.stack = ''
13+
return Promise.reject(err)
14+
},
15+
})
16+
</script>
17+
18+
<button on:click={() => $mutation.reset()}>Reset</button>
19+
<button on:click={() => $mutation.mutate()}>Mutate</button>
20+
21+
<div>Error: {$mutation.error?.message}</div>
Lines changed: 94 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,108 @@
11
import { describe, expect, test, vi } from 'vitest'
22
import { fireEvent, render, waitFor } from '@testing-library/svelte'
3-
import BaseExample from './BaseExample.svelte'
3+
import { sleep } from '../utils'
4+
import ResetExample from './ResetExample.svelte'
5+
import OnSuccessExample from './OnSuccessExample.svelte'
6+
import FailureExample from './FailureExample.svelte'
47

58
describe('createMutation', () => {
6-
test('Call mutate and check function runs', async () => {
7-
const mutationFn = vi.fn()
9+
test('Able to reset `error`', async () => {
10+
const rendered = render(ResetExample)
811

9-
const rendered = render(BaseExample, {
12+
await waitFor(() => {
13+
expect(rendered.queryByText('Error: undefined')).toBeInTheDocument()
14+
})
15+
16+
fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
17+
18+
await waitFor(() => {
19+
expect(
20+
rendered.queryByText('Error: Expected mock error'),
21+
).toBeInTheDocument()
22+
})
23+
24+
fireEvent.click(rendered.getByRole('button', { name: /Reset/i }))
25+
26+
await waitFor(() => {
27+
expect(rendered.queryByText('Error: undefined')).toBeInTheDocument()
28+
})
29+
})
30+
31+
test('Able to call `onSuccess` and `onSettled` after each successful mutate', async () => {
32+
const onSuccessMock = vi.fn()
33+
const onSettledMock = vi.fn()
34+
35+
const rendered = render(OnSuccessExample, {
1036
props: {
11-
options: {
12-
mutationFn,
13-
},
37+
onSuccessMock,
38+
onSettledMock,
1439
},
1540
})
1641

17-
fireEvent.click(rendered.getByRole('button'))
42+
await waitFor(() => {
43+
expect(rendered.queryByText('Count: 0')).toBeInTheDocument()
44+
})
45+
46+
fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
47+
fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
48+
fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
49+
50+
await waitFor(() => {
51+
expect(rendered.queryByText('Count: 3')).toBeInTheDocument()
52+
})
53+
54+
await waitFor(() => {
55+
expect(onSuccessMock).toHaveBeenCalledTimes(3)
56+
})
57+
58+
expect(onSuccessMock).toHaveBeenCalledWith(1)
59+
expect(onSuccessMock).toHaveBeenCalledWith(2)
60+
expect(onSuccessMock).toHaveBeenCalledWith(3)
1861

1962
await waitFor(() => {
20-
expect(mutationFn).toHaveBeenCalledTimes(1)
63+
expect(onSettledMock).toHaveBeenCalledTimes(3)
64+
})
65+
66+
expect(onSettledMock).toHaveBeenCalledWith(1)
67+
expect(onSettledMock).toHaveBeenCalledWith(2)
68+
expect(onSettledMock).toHaveBeenCalledWith(3)
69+
})
70+
71+
test('Set correct values for `failureReason` and `failureCount` on multiple mutate calls', async () => {
72+
type Value = { count: number }
73+
74+
const mutationFn = vi.fn<(value: Value) => Promise<Value>>()
75+
76+
mutationFn.mockImplementationOnce(() => {
77+
return Promise.reject(`Expected mock error`)
2178
})
79+
80+
mutationFn.mockImplementation(async (value) => {
81+
await sleep(5)
82+
return Promise.resolve(value)
83+
})
84+
85+
const rendered = render(FailureExample, {
86+
props: {
87+
mutationFn,
88+
},
89+
})
90+
91+
await waitFor(() => rendered.queryByText('Data: undefined'))
92+
93+
fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
94+
await waitFor(() => rendered.getByText('Data: undefined'))
95+
await waitFor(() => rendered.getByText('Status: error'))
96+
await waitFor(() => rendered.getByText('Failure Count: 1'))
97+
await waitFor(() =>
98+
rendered.getByText('Failure Reason: Expected mock error'),
99+
)
100+
101+
fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
102+
await waitFor(() => rendered.getByText('Status: pending'))
103+
await waitFor(() => rendered.getByText('Status: success'))
104+
await waitFor(() => rendered.getByText('Data: 2'))
105+
await waitFor(() => rendered.getByText('Failure Count: 0'))
106+
await waitFor(() => rendered.getByText('Failure Reason: null'))
22107
})
23108
})

0 commit comments

Comments
 (0)