Skip to content

Commit

Permalink
test(svelte-query): Better createMutation tests (#7773)
Browse files Browse the repository at this point in the history
  • Loading branch information
lachlancollins committed Jul 22, 2024
1 parent 0edbc49 commit ffd404f
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts">
import { QueryClient } from '@tanstack/query-core'
import { createInfiniteQuery } from '../../src/index'
import type { QueryObserverResult } from '@tanstack/query-core'
import type { Writable } from 'svelte/store'
export let states: Writable<Array<QueryObserverResult>>
const queryClient = new QueryClient()
const query = createInfiniteQuery(
{
queryKey: ['test'],
queryFn: () => Promise.resolve({ count: 1 }),
select: (data) => ({
pages: data.pages.map((x) => `count: ${x.count}`),
pageParams: data.pageParams,
}),
getNextPageParam: () => undefined,
initialPageParam: 0,
},
queryClient,
)
$: states.update((prev) => [...prev, $query])
</script>

<div>{$query.data?.pages.join(',')}</div>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, test } from 'vitest'
import { render, waitFor } from '@testing-library/svelte'
import { get, writable } from 'svelte/store'
import BaseExample from './BaseExample.svelte'
import SelectExample from './SelectExample.svelte'
import type { Writable } from 'svelte/store'
import type { QueryObserverResult } from '@tanstack/query-core'

Expand Down Expand Up @@ -93,4 +94,32 @@ describe('createInfiniteQuery', () => {
fetchStatus: 'idle',
})
})

test('Select a part of the data', async () => {
const statesStore: Writable<Array<QueryObserverResult>> = writable([])

const rendered = render(SelectExample, {
props: {
states: statesStore,
},
})

await waitFor(() => {
expect(rendered.queryByText('count: 1')).toBeInTheDocument()
})

const states = get(statesStore)

expect(states).toHaveLength(2)

expect(states[0]).toMatchObject({
data: undefined,
isSuccess: false,
})

expect(states[1]).toMatchObject({
data: { pages: ['count: 1'] },
isSuccess: true,
})
})
})
15 changes: 0 additions & 15 deletions packages/svelte-query/tests/createMutation/BaseExample.svelte

This file was deleted.

24 changes: 24 additions & 0 deletions packages/svelte-query/tests/createMutation/FailureExample.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script lang="ts">
import { writable } from 'svelte/store'
import { QueryClient } from '@tanstack/query-core'
import { setQueryClientContext } from '../../src/context'
import { createMutation } from '../../src/createMutation'
export let mutationFn: (value: {
count: number
}) => Promise<{ count: number }>
const count = writable(0)
const queryClient = new QueryClient()
setQueryClientContext(queryClient)
const mutation = createMutation({ mutationFn: mutationFn })
</script>

<button on:click={() => $mutation.mutate({ count: ++$count })}>Mutate</button>

<div>Data: {$mutation.data?.count}</div>
<div>Status: {$mutation.status}</div>
<div>Failure Count: {$mutation.failureCount}</div>
<div>Failure Reason: {$mutation.failureReason}</div>
28 changes: 28 additions & 0 deletions packages/svelte-query/tests/createMutation/OnSuccessExample.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts">
import { writable } from 'svelte/store'
import { QueryClient } from '@tanstack/query-core'
import { setQueryClientContext } from '../../src/context'
import { createMutation } from '../../src/createMutation'
export let onSuccessMock: any
export let onSettledMock: any
const count = writable(0)
const queryClient = new QueryClient()
setQueryClientContext(queryClient)
const mutation = createMutation({
mutationFn: (vars: { count: number }) => Promise.resolve(vars.count),
onSuccess: (data) => {
onSuccessMock(data)
},
onSettled: (data) => {
onSettledMock(data)
},
})
</script>

<button on:click={() => $mutation.mutate({ count: ++$count })}>Mutate</button>

<div>Count: {$count}</div>
21 changes: 21 additions & 0 deletions packages/svelte-query/tests/createMutation/ResetExample.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script lang="ts">
import { QueryClient } from '@tanstack/query-core'
import { setQueryClientContext } from '../../src/context'
import { createMutation } from '../../src/createMutation'
const queryClient = new QueryClient()
setQueryClientContext(queryClient)
const mutation = createMutation({
mutationFn: () => {
const err = new Error('Expected mock error')
err.stack = ''
return Promise.reject(err)
},
})
</script>

<button on:click={() => $mutation.reset()}>Reset</button>
<button on:click={() => $mutation.mutate()}>Mutate</button>

<div>Error: {$mutation.error?.message}</div>
103 changes: 94 additions & 9 deletions packages/svelte-query/tests/createMutation/createMutation.test.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,108 @@
import { describe, expect, test, vi } from 'vitest'
import { fireEvent, render, waitFor } from '@testing-library/svelte'
import BaseExample from './BaseExample.svelte'
import { sleep } from '../utils'
import ResetExample from './ResetExample.svelte'
import OnSuccessExample from './OnSuccessExample.svelte'
import FailureExample from './FailureExample.svelte'

describe('createMutation', () => {
test('Call mutate and check function runs', async () => {
const mutationFn = vi.fn()
test('Able to reset `error`', async () => {
const rendered = render(ResetExample)

const rendered = render(BaseExample, {
await waitFor(() => {
expect(rendered.queryByText('Error: undefined')).toBeInTheDocument()
})

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

await waitFor(() => {
expect(
rendered.queryByText('Error: Expected mock error'),
).toBeInTheDocument()
})

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

await waitFor(() => {
expect(rendered.queryByText('Error: undefined')).toBeInTheDocument()
})
})

test('Able to call `onSuccess` and `onSettled` after each successful mutate', async () => {
const onSuccessMock = vi.fn()
const onSettledMock = vi.fn()

const rendered = render(OnSuccessExample, {
props: {
options: {
mutationFn,
},
onSuccessMock,
onSettledMock,
},
})

fireEvent.click(rendered.getByRole('button'))
await waitFor(() => {
expect(rendered.queryByText('Count: 0')).toBeInTheDocument()
})

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

await waitFor(() => {
expect(rendered.queryByText('Count: 3')).toBeInTheDocument()
})

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

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

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

expect(onSettledMock).toHaveBeenCalledWith(1)
expect(onSettledMock).toHaveBeenCalledWith(2)
expect(onSettledMock).toHaveBeenCalledWith(3)
})

test('Set correct values for `failureReason` and `failureCount` on multiple mutate calls', async () => {
type Value = { count: number }

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

mutationFn.mockImplementationOnce(() => {
return Promise.reject(`Expected mock error`)
})

mutationFn.mockImplementation(async (value) => {
await sleep(5)
return Promise.resolve(value)
})

const rendered = render(FailureExample, {
props: {
mutationFn,
},
})

await waitFor(() => rendered.queryByText('Data: undefined'))

fireEvent.click(rendered.getByRole('button', { name: /Mutate/i }))
await waitFor(() => rendered.getByText('Data: undefined'))
await waitFor(() => rendered.getByText('Status: error'))
await waitFor(() => rendered.getByText('Failure Count: 1'))
await waitFor(() =>
rendered.getByText('Failure Reason: Expected mock error'),
)

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('Failure Count: 0'))
await waitFor(() => rendered.getByText('Failure Reason: null'))
})
})

0 comments on commit ffd404f

Please sign in to comment.