From 5eb3058c55d543ef0ddc75a7a4668dfc28e45640 Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Wed, 7 May 2025 03:05:38 +0900 Subject: [PATCH 1/2] ci(*): update vitest/expect-expect rule as error --- .../solid-query-devtools/eslint.config.js | 12 +- .../eslint.config.js | 12 +- packages/solid-query/eslint.config.js | 12 +- .../src/__tests__/queryOptions.test-d.tsx | 16 +- .../src/__tests__/suspense.test.tsx | 146 +++++++--- .../src/__tests__/transition.test.tsx | 10 +- .../src/__tests__/useIsFetching.test.tsx | 26 +- .../src/__tests__/useIsMutating.test.tsx | 5 +- .../src/__tests__/useMutation.test.tsx | 61 ++++- .../src/__tests__/useQueries.test.tsx | 1 + .../src/__tests__/useQuery.test.tsx | 255 +++++++++++++----- .../svelte-query-devtools/eslint.config.js | 8 - .../eslint.config.js | 8 - packages/svelte-query/eslint.config.js | 8 - packages/vue-query-devtools/eslint.config.js | 13 +- packages/vue-query/eslint.config.js | 13 +- .../__tests__/infiniteQueryOptions.test-d.ts | 20 +- .../src/__tests__/queryClient.test-d.ts | 40 +-- .../src/__tests__/queryOptions.test-d.ts | 16 +- 19 files changed, 424 insertions(+), 258 deletions(-) diff --git a/packages/solid-query-devtools/eslint.config.js b/packages/solid-query-devtools/eslint.config.js index 7ccaf501775..df75435c7e1 100644 --- a/packages/solid-query-devtools/eslint.config.js +++ b/packages/solid-query-devtools/eslint.config.js @@ -1,15 +1,5 @@ // @ts-check -import vitest from '@vitest/eslint-plugin' import rootConfig from './root.eslint.config.js' -export default [ - ...rootConfig, - { - plugins: { vitest }, - rules: { - ...vitest.configs.recommended.rules, - 'vitest/expect-expect': 'warn', - }, - }, -] +export default [...rootConfig] diff --git a/packages/solid-query-persist-client/eslint.config.js b/packages/solid-query-persist-client/eslint.config.js index 7ccaf501775..df75435c7e1 100644 --- a/packages/solid-query-persist-client/eslint.config.js +++ b/packages/solid-query-persist-client/eslint.config.js @@ -1,15 +1,5 @@ // @ts-check -import vitest from '@vitest/eslint-plugin' import rootConfig from './root.eslint.config.js' -export default [ - ...rootConfig, - { - plugins: { vitest }, - rules: { - ...vitest.configs.recommended.rules, - 'vitest/expect-expect': 'warn', - }, - }, -] +export default [...rootConfig] diff --git a/packages/solid-query/eslint.config.js b/packages/solid-query/eslint.config.js index 7ccaf501775..df75435c7e1 100644 --- a/packages/solid-query/eslint.config.js +++ b/packages/solid-query/eslint.config.js @@ -1,15 +1,5 @@ // @ts-check -import vitest from '@vitest/eslint-plugin' import rootConfig from './root.eslint.config.js' -export default [ - ...rootConfig, - { - plugins: { vitest }, - rules: { - ...vitest.configs.recommended.rules, - 'vitest/expect-expect': 'warn', - }, - }, -] +export default [...rootConfig] diff --git a/packages/solid-query/src/__tests__/queryOptions.test-d.tsx b/packages/solid-query/src/__tests__/queryOptions.test-d.tsx index 68cfecf7afc..6fb6a7c5f2f 100644 --- a/packages/solid-query/src/__tests__/queryOptions.test-d.tsx +++ b/packages/solid-query/src/__tests__/queryOptions.test-d.tsx @@ -1,16 +1,18 @@ -import { describe, expectTypeOf, it } from 'vitest' +import { assertType, describe, expectTypeOf, it } from 'vitest' import { QueryClient, dataTagSymbol, skipToken } from '@tanstack/query-core' import { useQuery } from '../useQuery' import { queryOptions } from '../queryOptions' describe('queryOptions', () => { it('should not allow excess properties', () => { - queryOptions({ - queryKey: ['key'], - queryFn: () => Promise.resolve(5), - // @ts-expect-error this is a good error, because stallTime does not exist! - stallTime: 1000, - }) + assertType( + queryOptions({ + queryKey: ['key'], + queryFn: () => Promise.resolve(5), + // @ts-expect-error this is a good error, because stallTime does not exist! + stallTime: 1000, + }), + ) }) it('should infer types for callbacks', () => { queryOptions({ diff --git a/packages/solid-query/src/__tests__/suspense.test.tsx b/packages/solid-query/src/__tests__/suspense.test.tsx index 5a56e072279..8a35844618c 100644 --- a/packages/solid-query/src/__tests__/suspense.test.tsx +++ b/packages/solid-query/src/__tests__/suspense.test.tsx @@ -263,15 +263,21 @@ describe("useQuery's in Suspense mode", () => { )) - await waitFor(() => rendered.getByText('Loading...')) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) - await waitFor(() => rendered.getByText('error boundary')) + await waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) - await waitFor(() => rendered.getByText('retry')) + await waitFor(() => expect(rendered.getByText('retry')).toBeInTheDocument()) fireEvent.click(rendered.getByText('retry')) - await waitFor(() => rendered.getByText('rendered')) + await waitFor(() => + expect(rendered.getByText('rendered')).toBeInTheDocument(), + ) }) it('should retry fetch if the reset error boundary has been reset', async () => { @@ -325,15 +331,23 @@ describe("useQuery's in Suspense mode", () => { )) - await waitFor(() => rendered.getByText('Loading...')) - await waitFor(() => rendered.getByText('error boundary')) - await waitFor(() => rendered.getByText('retry')) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) + await waitFor(() => expect(rendered.getByText('retry')).toBeInTheDocument()) fireEvent.click(rendered.getByText('retry')) - await waitFor(() => rendered.getByText('error boundary')) - await waitFor(() => rendered.getByText('retry')) + await waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) + await waitFor(() => expect(rendered.getByText('retry')).toBeInTheDocument()) succeed = true fireEvent.click(rendered.getByText('retry')) - await waitFor(() => rendered.getByText('rendered')) + await waitFor(() => + expect(rendered.getByText('rendered')).toBeInTheDocument(), + ) }) it('should refetch when re-mounting', async () => { @@ -383,16 +397,28 @@ describe("useQuery's in Suspense mode", () => { )) - await waitFor(() => rendered.getByText('Loading...')) - await waitFor(() => rendered.getByText('data: 1')) - await waitFor(() => rendered.getByText('fetching: false')) - await waitFor(() => rendered.getByText('hide')) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('data: 1')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('fetching: false')).toBeInTheDocument(), + ) + await waitFor(() => expect(rendered.getByText('hide')).toBeInTheDocument()) fireEvent.click(rendered.getByText('hide')) - await waitFor(() => rendered.getByText('show')) + await waitFor(() => expect(rendered.getByText('show')).toBeInTheDocument()) fireEvent.click(rendered.getByText('show')) - await waitFor(() => rendered.getByText('fetching: true')) - await waitFor(() => rendered.getByText('data: 2')) - await waitFor(() => rendered.getByText('fetching: false')) + await waitFor(() => + expect(rendered.getByText('fetching: true')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('data: 2')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('fetching: false')).toBeInTheDocument(), + ) }) it('should suspend when switching to a new query', async () => { @@ -436,11 +462,19 @@ describe("useQuery's in Suspense mode", () => { )) - await waitFor(() => rendered.getByText('Loading...')) - await waitFor(() => rendered.getByText(`data: ${key1}`)) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText(`data: ${key1}`)).toBeInTheDocument(), + ) fireEvent.click(rendered.getByText('switch')) - await waitFor(() => rendered.getByText('Loading...')) - await waitFor(() => rendered.getByText(`data: ${key2}`)) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText(`data: ${key2}`)).toBeInTheDocument(), + ) }) it('should throw errors to the error boundary by default', async () => { @@ -491,8 +525,12 @@ describe("useQuery's in Suspense mode", () => { )) - await waitFor(() => rendered.getByText('Loading...')) - await waitFor(() => rendered.getByText('error boundary')) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) consoleMock.mockRestore() }) @@ -541,8 +579,12 @@ describe("useQuery's in Suspense mode", () => { )) - await waitFor(() => rendered.getByText('Loading...')) - await waitFor(() => rendered.getByText('rendered')) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('rendered')).toBeInTheDocument(), + ) }) it('should throw errors to the error boundary when a throwOnError function returns true', async () => { @@ -593,8 +635,12 @@ describe("useQuery's in Suspense mode", () => { )) - await waitFor(() => rendered.getByText('Loading...')) - await waitFor(() => rendered.getByText('error boundary')) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) consoleMock.mockRestore() }) @@ -645,8 +691,12 @@ describe("useQuery's in Suspense mode", () => { )) - await waitFor(() => rendered.getByText('Loading...')) - await waitFor(() => rendered.getByText('rendered')) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('rendered')).toBeInTheDocument(), + ) }) it('should not call the queryFn when not enabled', async () => { @@ -751,16 +801,22 @@ describe("useQuery's in Suspense mode", () => { )) // render suspense fallback (Loading...) - await waitFor(() => rendered.getByText('Loading...')) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) // resolve promise -> render Page (rendered) - await waitFor(() => rendered.getByText('rendered')) + await waitFor(() => + expect(rendered.getByText('rendered')).toBeInTheDocument(), + ) // change query key succeed = false // reset query -> and throw error fireEvent.click(rendered.getByLabelText('fail')) // render error boundary fallback (error boundary) - await waitFor(() => rendered.getByText('error boundary')) + await waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) consoleMock.mockRestore() }) @@ -815,16 +871,22 @@ describe("useQuery's in Suspense mode", () => { )) // render suspense fallback (Loading...) - await waitFor(() => rendered.getByText('Loading...')) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) // resolve promise -> render Page (rendered) - await waitFor(() => rendered.getByText('rendered')) + await waitFor(() => + expect(rendered.getByText('rendered')).toBeInTheDocument(), + ) // change promise result to error succeed = false // change query key fireEvent.click(rendered.getByLabelText('fail')) // render error boundary fallback (error boundary) - await waitFor(() => rendered.getByText('error boundary')) + await waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) consoleMock.mockRestore() }) @@ -881,16 +943,22 @@ describe("useQuery's in Suspense mode", () => { )) // render empty data with 'rendered' when enabled is false - await waitFor(() => rendered.getByText('rendered')) + await waitFor(() => + expect(rendered.getByText('rendered')).toBeInTheDocument(), + ) // change enabled to true fireEvent.click(rendered.getByLabelText('fail')) // render pending fallback - await waitFor(() => rendered.getByText('Loading...')) + await waitFor(() => + expect(rendered.getByText('Loading...')).toBeInTheDocument(), + ) // render error boundary fallback (error boundary) - await waitFor(() => rendered.getByText('error boundary')) + await waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) consoleMock.mockRestore() }) diff --git a/packages/solid-query/src/__tests__/transition.test.tsx b/packages/solid-query/src/__tests__/transition.test.tsx index 3a272435af8..72f1491d2a3 100644 --- a/packages/solid-query/src/__tests__/transition.test.tsx +++ b/packages/solid-query/src/__tests__/transition.test.tsx @@ -1,4 +1,4 @@ -import { describe, it } from 'vitest' +import { describe, expect, it } from 'vitest' import { fireEvent, render, waitFor } from '@solidjs/testing-library' import { Show, Suspense, createSignal, startTransition } from 'solid-js' import { QueryCache, QueryClientProvider, useQuery } from '..' @@ -50,11 +50,13 @@ describe("useQuery's in Suspense mode with transitions", () => { )) - await waitFor(() => rendered.getByText('Show')) + await waitFor(() => expect(rendered.getByText('Show')).toBeInTheDocument()) fireEvent.click(rendered.getByLabelText('toggle')) - await waitFor(() => rendered.getByText('Message')) + await waitFor(() => + expect(rendered.getByText('Message')).toBeInTheDocument(), + ) // verify that the button also updated. See https://github.com/solidjs/solid/issues/1249 - await waitFor(() => rendered.getByText('Hide')) + await waitFor(() => expect(rendered.getByText('Hide')).toBeInTheDocument()) }) }) diff --git a/packages/solid-query/src/__tests__/useIsFetching.test.tsx b/packages/solid-query/src/__tests__/useIsFetching.test.tsx index 02fab631414..0d585974fcd 100644 --- a/packages/solid-query/src/__tests__/useIsFetching.test.tsx +++ b/packages/solid-query/src/__tests__/useIsFetching.test.tsx @@ -1,4 +1,4 @@ -import { describe, expect, it } from 'vitest' +import { describe, expect, it, vi } from 'vitest' import { fireEvent, render, waitFor } from '@solidjs/testing-library' import { Show, createEffect, createRenderEffect, createSignal } from 'solid-js' import { QueryCache, QueryClientProvider, useIsFetching, useQuery } from '..' @@ -46,10 +46,16 @@ describe('useIsFetching', () => { )) - await rendered.findByText('isFetching: 0') + await waitFor(() => + expect(rendered.getByText('isFetching: 0')).toBeInTheDocument(), + ) fireEvent.click(rendered.getByRole('button', { name: /setReady/i })) - await rendered.findByText('isFetching: 1') - await rendered.findByText('isFetching: 0') + await waitFor(() => + expect(rendered.getByText('isFetching: 1')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('isFetching: 0')).toBeInTheDocument(), + ) }) it('should not update state while rendering', async () => { @@ -215,8 +221,12 @@ describe('useIsFetching', () => { )) - await rendered.findByText('isFetching: 1') - await rendered.findByText('isFetching: 0') + await vi.waitFor(() => + expect(rendered.getByText('isFetching: 1')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('isFetching: 0')).toBeInTheDocument(), + ) }) it('should use provided custom queryClient', async () => { @@ -246,6 +256,8 @@ describe('useIsFetching', () => { const rendered = render(() => ) - await rendered.findByText('isFetching: 1') + await vi.waitFor(() => + expect(rendered.getByText('isFetching: 1')).toBeInTheDocument(), + ) }) }) diff --git a/packages/solid-query/src/__tests__/useIsMutating.test.tsx b/packages/solid-query/src/__tests__/useIsMutating.test.tsx index efd6eaf83a6..860fd32467c 100644 --- a/packages/solid-query/src/__tests__/useIsMutating.test.tsx +++ b/packages/solid-query/src/__tests__/useIsMutating.test.tsx @@ -182,9 +182,12 @@ describe('useIsMutating', () => { const rendered = render(() => ) - await waitFor(() => rendered.findByText('mutating: 1')) + await vi.waitFor(() => + expect(rendered.getByText('mutating: 1')).toBeInTheDocument(), + ) }) + // eslint-disable-next-line vitest/expect-expect it('should not change state if unmounted', async () => { // We have to mock the MutationCache to not unsubscribe // the listener when the component is unmounted diff --git a/packages/solid-query/src/__tests__/useMutation.test.tsx b/packages/solid-query/src/__tests__/useMutation.test.tsx index d1d4a8a579b..3d0894b0047 100644 --- a/packages/solid-query/src/__tests__/useMutation.test.tsx +++ b/packages/solid-query/src/__tests__/useMutation.test.tsx @@ -217,22 +217,38 @@ describe('useMutation', () => { )) - rendered.getByText('Data') + expect(rendered.getByText('Data')).toBeInTheDocument() fireEvent.click(rendered.getByRole('button', { name: /mutate/i })) - rendered.getByText('Data') - await vi.waitFor(() => rendered.getByText('Status error')) - await vi.waitFor(() => rendered.getByText('Failed 1 times')) + expect(rendered.getByText('Data')).toBeInTheDocument() await vi.waitFor(() => - rendered.getByText('Failed because Error test Jonas'), + expect(rendered.getByText('Status error')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('Failed 1 times')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect( + rendered.getByText('Failed because Error test Jonas'), + ).toBeInTheDocument(), ) fireEvent.click(rendered.getByRole('button', { name: /mutate/i })) - 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')) + await vi.waitFor(() => + expect(rendered.getByText('Status pending')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('Status success')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('Data 2')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('Failed 0 times')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('Failed because null')).toBeInTheDocument(), + ) }) it('should be able to call `onError` and `onSettled` after each failed mutate', async () => { @@ -752,6 +768,7 @@ describe('useMutation', () => { }) }) + // eslint-disable-next-line vitest/expect-expect it('should not change state if unmounted', () => { function Mutates() { const mutation = useMutation(() => ({ mutationFn: () => sleep(10) })) @@ -1148,12 +1165,20 @@ describe('useMutation', () => { )) - await rendered.findByText('error: null, status: idle') + await vi.waitFor(() => + expect( + rendered.getByText('error: null, status: idle'), + ).toBeInTheDocument(), + ) rendered.getByRole('button', { name: /mutate/i }).click() await vi.advanceTimersByTimeAsync(10) - await rendered.findByText('error: mutateFnError, status: error') + await vi.waitFor(() => + expect( + rendered.getByText('error: mutateFnError, status: error'), + ).toBeInTheDocument(), + ) }) it('should go to error state if onSettled callback errors', async () => { @@ -1224,10 +1249,18 @@ describe('useMutation', () => { const rendered = render(() => ) - await rendered.findByText('data: null, status: idle') + await vi.waitFor(() => + expect( + rendered.getByText('data: null, status: idle'), + ).toBeInTheDocument(), + ) fireEvent.click(rendered.getByRole('button', { name: /mutate/i })) - await rendered.findByText('data: custom client, status: success') + await vi.waitFor(() => + expect( + rendered.getByText('data: custom client, status: success'), + ).toBeInTheDocument(), + ) }) }) diff --git a/packages/solid-query/src/__tests__/useQueries.test.tsx b/packages/solid-query/src/__tests__/useQueries.test.tsx index fcdae15d842..6dca9bac2f3 100644 --- a/packages/solid-query/src/__tests__/useQueries.test.tsx +++ b/packages/solid-query/src/__tests__/useQueries.test.tsx @@ -648,6 +648,7 @@ describe('useQueries', () => { } }) + // eslint-disable-next-line vitest/expect-expect it('should not change state if unmounted', async () => { const key1 = queryKey() diff --git a/packages/solid-query/src/__tests__/useQuery.test.tsx b/packages/solid-query/src/__tests__/useQuery.test.tsx index 7a1547bf458..0701d4ec8fc 100644 --- a/packages/solid-query/src/__tests__/useQuery.test.tsx +++ b/packages/solid-query/src/__tests__/useQuery.test.tsx @@ -219,9 +219,11 @@ describe('useQuery', () => { )) - rendered.getByText('default') + expect(rendered.getByText('default')).toBeInTheDocument() - await waitFor(() => rendered.getByText('test')) + await vi.waitFor(() => + expect(rendered.getByText('test')).toBeInTheDocument(), + ) }) it('should return the correct states for a successful query', async () => { @@ -1889,10 +1891,10 @@ describe('useQuery', () => { )) - rendered.getByText('First Data: init') - rendered.getByText('Second Data: init') - rendered.getByText('First Status: success') - rendered.getByText('Second Status: success') + expect(rendered.getByText('First Data: init')).toBeInTheDocument() + expect(rendered.getByText('Second Data: init')).toBeInTheDocument() + expect(rendered.getByText('First Status: success')).toBeInTheDocument() + expect(rendered.getByText('Second Status: success')).toBeInTheDocument() }) it('should update query options', () => { @@ -1973,7 +1975,9 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('new')) + await vi.waitFor(() => + expect(rendered.getByText('new')).toBeInTheDocument(), + ) }) // See https://github.com/tannerlinsley/react-query/issues/170 @@ -2012,9 +2016,19 @@ describe('useQuery', () => { // use "act" to wait for state update and prevent console warning - rendered.getByText('First Status: pending, idle') - await waitFor(() => rendered.getByText('Second Status: pending, fetching')) - await waitFor(() => rendered.getByText('Second Status: success, idle')) + expect( + rendered.getByText('First Status: pending, idle'), + ).toBeInTheDocument() + await vi.waitFor(() => + expect( + rendered.getByText('Second Status: pending, fetching'), + ).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect( + rendered.getByText('Second Status: success, idle'), + ).toBeInTheDocument(), + ) }) // See https://github.com/tannerlinsley/react-query/issues/144 @@ -2039,7 +2053,7 @@ describe('useQuery', () => { )) - rendered.getByText('status: pending') + expect(rendered.getByText('status: pending')).toBeInTheDocument() }) it('should not refetch query on focus when `enabled` is set to `false`', async () => { @@ -2388,8 +2402,12 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('error')) - await waitFor(() => rendered.getByText('Error test')) + await vi.waitFor(() => + expect(rendered.getByText('error')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('Error test')).toBeInTheDocument(), + ) consoleMock.mockRestore() }) @@ -2426,7 +2444,9 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('error boundary')) + await vi.waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) consoleMock.mockRestore() }) @@ -2463,7 +2483,9 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('error boundary')) + await vi.waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) consoleMock.mockRestore() }) @@ -2502,7 +2524,11 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('Fallback error: Error test')) + await vi.waitFor(() => + expect( + rendered.getByText('Fallback error: Error test'), + ).toBeInTheDocument(), + ) consoleMock.mockRestore() }) @@ -2541,10 +2567,16 @@ describe('useQuery', () => { )) - await waitFor(() => - rendered.getByText('Outside error boundary: Error test'), + await vi.waitFor(() => + expect( + rendered.getByText('Outside error boundary: Error test'), + ).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect( + rendered.getByText('Fallback error: Error test'), + ).toBeInTheDocument(), ) - await waitFor(() => rendered.getByText('Fallback error: Error test')) consoleMock.mockRestore() }) @@ -2606,8 +2638,12 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('error')) - await waitFor(() => rendered.getByText('Local Error')) + await vi.waitFor(() => + expect(rendered.getByText('error')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('Local Error')).toBeInTheDocument(), + ) }) it('should throw error instead of setting status when error should be thrown', async () => { @@ -2645,8 +2681,12 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('error boundary')) - await waitFor(() => rendered.getByText('Remote Error')) + await vi.waitFor(() => + expect(rendered.getByText('error boundary')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('Remote Error')).toBeInTheDocument(), + ) }) it('should continue retries when observers unmount and remount while waiting for a retry (#3031)', async () => { @@ -3186,29 +3226,61 @@ describe('useQuery', () => { )) // The query should display the first error result - await waitFor(() => rendered.getByText('failureCount 1')) - await waitFor(() => rendered.getByText('failureReason fetching error 1')) - await waitFor(() => rendered.getByText('status pending')) - await waitFor(() => rendered.getByText('error null')) + await vi.waitFor(() => + expect(rendered.getByText('failureCount 1')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect( + rendered.getByText('failureReason fetching error 1'), + ).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('status pending')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('error null')).toBeInTheDocument(), + ) // Check if the query really paused await sleep(10) - await waitFor(() => rendered.getByText('failureCount 1')) - await waitFor(() => rendered.getByText('failureReason fetching error 1')) + await vi.waitFor(() => + expect(rendered.getByText('failureCount 1')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect( + rendered.getByText('failureReason fetching error 1'), + ).toBeInTheDocument(), + ) visibilityMock.mockRestore() window.dispatchEvent(new Event('visibilitychange')) // Wait for the final result - await waitFor(() => rendered.getByText('failureCount 4')) - await waitFor(() => rendered.getByText('failureReason fetching error 4')) - await waitFor(() => rendered.getByText('status error')) - await waitFor(() => rendered.getByText('error fetching error 4')) + await vi.waitFor(() => + expect(rendered.getByText('failureCount 4')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect( + rendered.getByText('failureReason fetching error 4'), + ).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('status error')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('error fetching error 4')).toBeInTheDocument(), + ) // Check if the query really stopped await sleep(10) - await waitFor(() => rendered.getByText('failureCount 4')) - await waitFor(() => rendered.getByText('failureReason fetching error 4')) + await vi.waitFor(() => + expect(rendered.getByText('failureCount 4')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect( + rendered.getByText('failureReason fetching error 4'), + ).toBeInTheDocument(), + ) }) it('should fetch on mount when a query was already created with setQueryData', async () => { @@ -3428,10 +3500,18 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('failureCount 2')) - await waitFor(() => rendered.getByText('failureReason error')) - await waitFor(() => rendered.getByText('failureCount 0')) - await waitFor(() => rendered.getByText('failureReason null')) + await waitFor(() => + expect(rendered.getByText('failureCount 2')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('failureReason error')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('failureCount 0')).toBeInTheDocument(), + ) + await waitFor(() => + expect(rendered.getByText('failureReason null')).toBeInTheDocument(), + ) }) // See https://github.com/tannerlinsley/react-query/issues/199 @@ -3515,16 +3595,17 @@ describe('useQuery', () => { )) - rendered.getByText('FetchStatus: idle') - rendered.getByText('Data: no data') + expect(rendered.getByText('FetchStatus: idle')).toBeInTheDocument() + expect(rendered.getByText('Data: no data')).toBeInTheDocument() fireEvent.click(rendered.getByText('fetch')) - await waitFor(() => rendered.getByText('FetchStatus: fetching')) - await waitFor(() => [ - rendered.getByText('FetchStatus: idle'), - rendered.getByText('Data: data'), - ]) + await vi.waitFor(() => + expect(rendered.getByText('FetchStatus: fetching')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('Data: data')).toBeInTheDocument(), + ) }) // See https://github.com/TanStack/query/issues/7711 @@ -3805,7 +3886,9 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('status: pending, idle')) + await vi.waitFor(() => + expect(rendered.getByText('status: pending, idle')).toBeInTheDocument(), + ) }) it('should not schedule garbage collection, if gcTimeout is set to `Infinity`', async () => { @@ -3942,9 +4025,15 @@ describe('useQuery', () => { )) // mount - await waitFor(() => rendered.getByText('count: 0')) - await waitFor(() => rendered.getByText('count: 1')) - await waitFor(() => rendered.getByText('count: 2')) + await vi.waitFor(() => + expect(rendered.getByText('count: 0')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('count: 1')).toBeInTheDocument(), + ) + await vi.waitFor(() => + expect(rendered.getByText('count: 2')).toBeInTheDocument(), + ) }) it('should refetch in an interval depending on function result', async () => { @@ -4079,7 +4168,7 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('')) + await vi.waitFor(() => expect(rendered.getByText('')).toBeInTheDocument()) }) it('should accept an object as query key', async () => { @@ -4097,7 +4186,9 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('[{"a":"a"}]')) + await vi.waitFor(() => + expect(rendered.getByText('[{"a":"a"}]')).toBeInTheDocument(), + ) }) it('should refetch if any query instance becomes enabled', async () => { @@ -4391,19 +4482,27 @@ describe('useQuery', () => { )) - await waitFor(() => rendered.getByText('Data: selected 101')) // 99 + 2 + await vi.waitFor(() => + expect(rendered.getByText('Data: selected 101')).toBeInTheDocument(), + ) // 99 + 2 - await waitFor(() => rendered.getByText('Data: selected 2')) // 0 + 2 + await vi.waitFor(() => + expect(rendered.getByText('Data: selected 2')).toBeInTheDocument(), + ) // 0 + 2 fireEvent.click(rendered.getByRole('button', { name: /inc/i })) - await waitFor(() => rendered.getByText('Data: selected 3')) // 0 + 3 + await vi.waitFor(() => + expect(rendered.getByText('Data: selected 3')).toBeInTheDocument(), + ) // 0 + 3 fireEvent.click(rendered.getByRole('button', { name: /forceUpdate/i })) - await waitFor(() => rendered.getByText('forceValue: 2')) + await vi.waitFor(() => rendered.getByText('forceValue: 2')) // data should still be 3 after an independent re-render - await waitFor(() => rendered.getByText('Data: selected 3')) + await vi.waitFor(() => + expect(rendered.getByText('Data: selected 3')).toBeInTheDocument(), + ) }) it('select should structurally share data', async () => { @@ -4970,18 +5069,20 @@ describe('useQuery', () => { )) // initial state check - rendered.getByText('status: pending') + expect(rendered.getByText('status: pending')).toBeInTheDocument() // render error state component - await waitFor(() => rendered.getByText('error')) + await waitFor(() => expect(rendered.getByText('error')).toBeInTheDocument()) // change to unmount query fireEvent.click(rendered.getByLabelText('change')) - await waitFor(() => rendered.getByText('rendered')) + await waitFor(() => + expect(rendered.getByText('rendered')).toBeInTheDocument(), + ) // change to mount new query fireEvent.click(rendered.getByLabelText('change')) - await waitFor(() => rendered.getByText('error')) + await waitFor(() => expect(rendered.getByText('error')).toBeInTheDocument()) }) it('should refetch when query key changed when switching between erroneous queries', async () => { @@ -5030,20 +5131,24 @@ describe('useQuery', () => { )) // initial state check - rendered.getByText('status: fetching') + expect(rendered.getByText('status: fetching')).toBeInTheDocument() // render error state component - await waitFor(() => rendered.getByText('error')) + await waitFor(() => expect(rendered.getByText('error')).toBeInTheDocument()) // change to mount second query fireEvent.click(rendered.getByLabelText('change')) - await waitFor(() => rendered.getByText('status: fetching')) - await waitFor(() => rendered.getByText('error')) + await waitFor(() => + expect(rendered.getByText('status: fetching')).toBeInTheDocument(), + ) + await waitFor(() => expect(rendered.getByText('error')).toBeInTheDocument()) // change to mount first query again fireEvent.click(rendered.getByLabelText('change')) - await waitFor(() => rendered.getByText('status: fetching')) - await waitFor(() => rendered.getByText('error')) + await waitFor(() => + expect(rendered.getByText('status: fetching')).toBeInTheDocument(), + ) + await waitFor(() => expect(rendered.getByText('error')).toBeInTheDocument()) }) it('should have no error in pending state when refetching after error occurred', async () => { @@ -6016,11 +6121,17 @@ describe('useQuery', () => { )) const fetchBtn = rendered.getByRole('button', { name: 'refetch' }) - await waitFor(() => rendered.getByText('data: 1')) + await waitFor(() => + expect(rendered.getByText('data: 1')).toBeInTheDocument(), + ) fireEvent.click(fetchBtn) - await waitFor(() => rendered.getByText('data: 2')) + await waitFor(() => + expect(rendered.getByText('data: 2')).toBeInTheDocument(), + ) fireEvent.click(fetchBtn) - await waitFor(() => rendered.getByText('data: 3')) + await waitFor(() => + expect(rendered.getByText('data: 3')).toBeInTheDocument(), + ) }) it('should use provided custom queryClient', async () => { @@ -6043,6 +6154,8 @@ describe('useQuery', () => { const rendered = render(() => ) - await waitFor(() => rendered.getByText('Status: custom client')) + await waitFor(() => + expect(rendered.getByText('Status: custom client')).toBeInTheDocument(), + ) }) }) diff --git a/packages/svelte-query-devtools/eslint.config.js b/packages/svelte-query-devtools/eslint.config.js index b40d00982ab..f31c5e878b4 100644 --- a/packages/svelte-query-devtools/eslint.config.js +++ b/packages/svelte-query-devtools/eslint.config.js @@ -1,6 +1,5 @@ // @ts-check -import vitest from '@vitest/eslint-plugin' import pluginSvelte from 'eslint-plugin-svelte' import rootConfig from './root.eslint.config.js' @@ -14,11 +13,4 @@ export default [ 'svelte/valid-compile': 'off', }, }, - { - plugins: { vitest }, - rules: { - ...vitest.configs.recommended.rules, - 'vitest/expect-expect': 'warn', - }, - }, ] diff --git a/packages/svelte-query-persist-client/eslint.config.js b/packages/svelte-query-persist-client/eslint.config.js index b40d00982ab..f31c5e878b4 100644 --- a/packages/svelte-query-persist-client/eslint.config.js +++ b/packages/svelte-query-persist-client/eslint.config.js @@ -1,6 +1,5 @@ // @ts-check -import vitest from '@vitest/eslint-plugin' import pluginSvelte from 'eslint-plugin-svelte' import rootConfig from './root.eslint.config.js' @@ -14,11 +13,4 @@ export default [ 'svelte/valid-compile': 'off', }, }, - { - plugins: { vitest }, - rules: { - ...vitest.configs.recommended.rules, - 'vitest/expect-expect': 'warn', - }, - }, ] diff --git a/packages/svelte-query/eslint.config.js b/packages/svelte-query/eslint.config.js index b40d00982ab..f31c5e878b4 100644 --- a/packages/svelte-query/eslint.config.js +++ b/packages/svelte-query/eslint.config.js @@ -1,6 +1,5 @@ // @ts-check -import vitest from '@vitest/eslint-plugin' import pluginSvelte from 'eslint-plugin-svelte' import rootConfig from './root.eslint.config.js' @@ -14,11 +13,4 @@ export default [ 'svelte/valid-compile': 'off', }, }, - { - plugins: { vitest }, - rules: { - ...vitest.configs.recommended.rules, - 'vitest/expect-expect': 'warn', - }, - }, ] diff --git a/packages/vue-query-devtools/eslint.config.js b/packages/vue-query-devtools/eslint.config.js index 0810a2d674c..6cd1d47ba72 100644 --- a/packages/vue-query-devtools/eslint.config.js +++ b/packages/vue-query-devtools/eslint.config.js @@ -1,18 +1,7 @@ // @ts-check -import vitest from '@vitest/eslint-plugin' // @ts-expect-error import pluginVue from 'eslint-plugin-vue' import rootConfig from './root.eslint.config.js' -export default [ - ...rootConfig, - ...pluginVue.configs['flat/base'], - { - plugins: { vitest }, - rules: { - ...vitest.configs.recommended.rules, - 'vitest/expect-expect': 'warn', - }, - }, -] +export default [...rootConfig, ...pluginVue.configs['flat/base']] diff --git a/packages/vue-query/eslint.config.js b/packages/vue-query/eslint.config.js index 0810a2d674c..6cd1d47ba72 100644 --- a/packages/vue-query/eslint.config.js +++ b/packages/vue-query/eslint.config.js @@ -1,18 +1,7 @@ // @ts-check -import vitest from '@vitest/eslint-plugin' // @ts-expect-error import pluginVue from 'eslint-plugin-vue' import rootConfig from './root.eslint.config.js' -export default [ - ...rootConfig, - ...pluginVue.configs['flat/base'], - { - plugins: { vitest }, - rules: { - ...vitest.configs.recommended.rules, - 'vitest/expect-expect': 'warn', - }, - }, -] +export default [...rootConfig, ...pluginVue.configs['flat/base']] diff --git a/packages/vue-query/src/__tests__/infiniteQueryOptions.test-d.ts b/packages/vue-query/src/__tests__/infiniteQueryOptions.test-d.ts index b0cb2545931..6413126ffd7 100644 --- a/packages/vue-query/src/__tests__/infiniteQueryOptions.test-d.ts +++ b/packages/vue-query/src/__tests__/infiniteQueryOptions.test-d.ts @@ -1,4 +1,4 @@ -import { describe, expectTypeOf, it } from 'vitest' +import { assertType, describe, expectTypeOf, it } from 'vitest' import { QueryClient, dataTagSymbol } from '@tanstack/query-core' import { reactive } from 'vue-demi' import { infiniteQueryOptions } from '../infiniteQueryOptions' @@ -7,14 +7,16 @@ import type { InfiniteData } from '@tanstack/query-core' describe('infiniteQueryOptions', () => { it('should not allow excess properties', () => { - infiniteQueryOptions({ - queryKey: ['key'], - queryFn: () => Promise.resolve('data'), - getNextPageParam: () => 1, - initialPageParam: 1, - // @ts-expect-error this is a good error, because stallTime does not exist! - stallTime: 1000, - }) + assertType( + infiniteQueryOptions({ + queryKey: ['key'], + queryFn: () => Promise.resolve('data'), + getNextPageParam: () => 1, + initialPageParam: 1, + // @ts-expect-error this is a good error, because stallTime does not exist! + stallTime: 1000, + }), + ) }) it('should infer types for callbacks', () => { infiniteQueryOptions({ diff --git a/packages/vue-query/src/__tests__/queryClient.test-d.ts b/packages/vue-query/src/__tests__/queryClient.test-d.ts index ae50680d342..ed4855a1347 100644 --- a/packages/vue-query/src/__tests__/queryClient.test-d.ts +++ b/packages/vue-query/src/__tests__/queryClient.test-d.ts @@ -1,4 +1,4 @@ -import { describe, expectTypeOf, it } from 'vitest' +import { assertType, describe, expectTypeOf, it } from 'vitest' import { QueryClient } from '../queryClient' import type { DataTag, InfiniteData } from '@tanstack/query-core' @@ -28,10 +28,10 @@ describe('getQueryData', () => { }) it('should only allow Arrays to be passed', () => { - const queryKey = 'key' - const queryClient = new QueryClient() - // @ts-expect-error TS2345: Argument of type 'string' is not assignable to parameter of type 'QueryKey' - return queryClient.getQueryData(queryKey) + assertType>([ + // @ts-expect-error TS2345: Argument of type 'string' is not assignable to parameter of type 'QueryKey' + { queryKey: 'key' }, + ]) }) }) @@ -125,21 +125,25 @@ describe('fetchInfiniteQuery', () => { }) it('should not allow passing getNextPageParam without pages', () => { - new QueryClient().fetchInfiniteQuery({ - queryKey: ['key'], - queryFn: () => Promise.resolve('string'), - initialPageParam: 1, - getNextPageParam: () => 1, - }) + assertType>([ + { + queryKey: ['key'], + queryFn: () => Promise.resolve('string'), + initialPageParam: 1, + getNextPageParam: () => 1, + }, + ]) }) it('should not allow passing pages without getNextPageParam', () => { - // @ts-expect-error Property 'getNextPageParam' is missing - new QueryClient().fetchInfiniteQuery({ - queryKey: ['key'], - queryFn: () => Promise.resolve('string'), - initialPageParam: 1, - pages: 5, - }) + assertType>([ + // @ts-expect-error Property 'getNextPageParam' is missing + { + queryKey: ['key'], + queryFn: () => Promise.resolve('string'), + initialPageParam: 1, + pages: 5, + }, + ]) }) }) diff --git a/packages/vue-query/src/__tests__/queryOptions.test-d.ts b/packages/vue-query/src/__tests__/queryOptions.test-d.ts index c40d606e862..65d49d945ff 100644 --- a/packages/vue-query/src/__tests__/queryOptions.test-d.ts +++ b/packages/vue-query/src/__tests__/queryOptions.test-d.ts @@ -1,4 +1,4 @@ -import { describe, expectTypeOf, it } from 'vitest' +import { assertType, describe, expectTypeOf, it } from 'vitest' import { reactive, ref } from 'vue-demi' import { dataTagSymbol } from '@tanstack/query-core' import { QueryClient } from '../queryClient' @@ -7,12 +7,14 @@ import { useQuery } from '../useQuery' describe('queryOptions', () => { it('should not allow excess properties', () => { - queryOptions({ - queryKey: ['key'], - queryFn: () => Promise.resolve(5), - // @ts-expect-error this is a good error, because stallTime does not exist! - stallTime: 1000, - }) + assertType( + queryOptions({ + queryKey: ['key'], + queryFn: () => Promise.resolve(5), + // @ts-expect-error this is a good error, because stallTime does not exist! + stallTime: 1000, + }), + ) }) it('should infer types for callbacks', () => { queryOptions({ From a626282d3af58ffb0806e7c1ee6a96b3e216729c Mon Sep 17 00:00:00 2001 From: Jonghyeon Ko Date: Wed, 7 May 2025 03:15:07 +0900 Subject: [PATCH 2/2] test: replace vi.waitFor with waitFor in useIsFetching and useIsMutating tests --- packages/solid-query/src/__tests__/useIsFetching.test.tsx | 8 ++++---- packages/solid-query/src/__tests__/useIsMutating.test.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/solid-query/src/__tests__/useIsFetching.test.tsx b/packages/solid-query/src/__tests__/useIsFetching.test.tsx index 0d585974fcd..c72a07784bd 100644 --- a/packages/solid-query/src/__tests__/useIsFetching.test.tsx +++ b/packages/solid-query/src/__tests__/useIsFetching.test.tsx @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest' +import { describe, expect, it } from 'vitest' import { fireEvent, render, waitFor } from '@solidjs/testing-library' import { Show, createEffect, createRenderEffect, createSignal } from 'solid-js' import { QueryCache, QueryClientProvider, useIsFetching, useQuery } from '..' @@ -221,10 +221,10 @@ describe('useIsFetching', () => { )) - await vi.waitFor(() => + await waitFor(() => expect(rendered.getByText('isFetching: 1')).toBeInTheDocument(), ) - await vi.waitFor(() => + await waitFor(() => expect(rendered.getByText('isFetching: 0')).toBeInTheDocument(), ) }) @@ -256,7 +256,7 @@ describe('useIsFetching', () => { const rendered = render(() => ) - await vi.waitFor(() => + await waitFor(() => expect(rendered.getByText('isFetching: 1')).toBeInTheDocument(), ) }) diff --git a/packages/solid-query/src/__tests__/useIsMutating.test.tsx b/packages/solid-query/src/__tests__/useIsMutating.test.tsx index 860fd32467c..81c29ef5915 100644 --- a/packages/solid-query/src/__tests__/useIsMutating.test.tsx +++ b/packages/solid-query/src/__tests__/useIsMutating.test.tsx @@ -182,7 +182,7 @@ describe('useIsMutating', () => { const rendered = render(() => ) - await vi.waitFor(() => + await waitFor(() => expect(rendered.getByText('mutating: 1')).toBeInTheDocument(), ) })