diff --git a/packages/preact-query-devtools/package.json b/packages/preact-query-devtools/package.json
index cbcbe3f9493..f9a03c29dee 100644
--- a/packages/preact-query-devtools/package.json
+++ b/packages/preact-query-devtools/package.json
@@ -27,6 +27,8 @@
"test:types:ts59": "node ../../node_modules/typescript59/lib/tsc.js --build tsconfig.legacy.json",
"test:types:tscurrent": "tsc --build",
"test:types:ts60": "node ../../node_modules/typescript60/lib/tsc.js --build tsconfig.legacy.json",
+ "test:lib": "vitest",
+ "test:lib:dev": "pnpm run test:lib --watch",
"test:build": "publint --strict && attw --pack",
"build": "tsup --tsconfig tsconfig.prod.json",
"build:dev": "tsup --watch"
diff --git a/packages/preact-query-devtools/src/__tests__/PreactQueryDevtools.test.tsx b/packages/preact-query-devtools/src/__tests__/PreactQueryDevtools.test.tsx
new file mode 100644
index 00000000000..25fd5c41698
--- /dev/null
+++ b/packages/preact-query-devtools/src/__tests__/PreactQueryDevtools.test.tsx
@@ -0,0 +1,77 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { render } from '@testing-library/preact'
+import { QueryClient, QueryClientProvider } from '@tanstack/preact-query'
+import type { TanstackQueryDevtools } from '@tanstack/query-devtools'
+
+const mountMock = vi.fn()
+const unmountMock = vi.fn()
+const setClientMock = vi.fn()
+const setButtonPositionMock = vi.fn()
+const setPositionMock = vi.fn()
+const setInitialIsOpenMock = vi.fn()
+const setErrorTypesMock = vi.fn()
+const setThemeMock = vi.fn()
+
+vi.mock('@tanstack/query-devtools', () => ({
+ TanstackQueryDevtools: vi.fn(function (this: TanstackQueryDevtools) {
+ this.mount = mountMock
+ this.unmount = unmountMock
+ this.setClient = setClientMock
+ this.setButtonPosition = setButtonPositionMock
+ this.setPosition = setPositionMock
+ this.setInitialIsOpen = setInitialIsOpenMock
+ this.setErrorTypes = setErrorTypesMock
+ this.setTheme = setThemeMock
+ }),
+}))
+
+describe('PreactQueryDevtools', () => {
+ beforeEach(() => {
+ vi.clearAllMocks()
+ })
+
+ it('should throw an error if no query client has been set', async () => {
+ const { PreactQueryDevtools } = await import('../PreactQueryDevtools')
+
+ expect(() => render()).toThrow(
+ 'No QueryClient set, use QueryClientProvider to set one',
+ )
+ })
+
+ it('should not throw an error if query client is provided via context', async () => {
+ const { PreactQueryDevtools } = await import('../PreactQueryDevtools')
+ const queryClient = new QueryClient()
+
+ expect(() =>
+ render(
+
+
+ ,
+ ),
+ ).not.toThrow()
+ expect(mountMock).toHaveBeenCalled()
+ })
+
+ it('should not throw an error if query client is provided via props', async () => {
+ const { PreactQueryDevtools } = await import('../PreactQueryDevtools')
+ const queryClient = new QueryClient()
+
+ expect(() =>
+ render(),
+ ).not.toThrow()
+ expect(mountMock).toHaveBeenCalled()
+ })
+
+ it('should return null in non-development environments', async () => {
+ vi.stubEnv('NODE_ENV', 'production')
+ vi.resetModules()
+
+ try {
+ const { PreactQueryDevtools } = await import('..')
+ expect(PreactQueryDevtools({})).toBeNull()
+ } finally {
+ vi.unstubAllEnvs()
+ vi.resetModules()
+ }
+ })
+})
diff --git a/packages/preact-query-devtools/src/__tests__/PreactQueryDevtoolsPanel.test.tsx b/packages/preact-query-devtools/src/__tests__/PreactQueryDevtoolsPanel.test.tsx
new file mode 100644
index 00000000000..cc03560a367
--- /dev/null
+++ b/packages/preact-query-devtools/src/__tests__/PreactQueryDevtoolsPanel.test.tsx
@@ -0,0 +1,78 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { render } from '@testing-library/preact'
+import { QueryClient, QueryClientProvider } from '@tanstack/preact-query'
+import type { TanstackQueryDevtoolsPanel } from '@tanstack/query-devtools'
+
+const mountMock = vi.fn()
+const unmountMock = vi.fn()
+const setClientMock = vi.fn()
+const setOnCloseMock = vi.fn()
+const setErrorTypesMock = vi.fn()
+const setThemeMock = vi.fn()
+
+vi.mock('@tanstack/query-devtools', () => ({
+ TanstackQueryDevtoolsPanel: vi.fn(function (
+ this: TanstackQueryDevtoolsPanel,
+ ) {
+ this.mount = mountMock
+ this.unmount = unmountMock
+ this.setClient = setClientMock
+ this.setOnClose = setOnCloseMock
+ this.setErrorTypes = setErrorTypesMock
+ this.setTheme = setThemeMock
+ }),
+}))
+
+describe('PreactQueryDevtoolsPanel', () => {
+ beforeEach(() => {
+ vi.clearAllMocks()
+ })
+
+ it('should throw an error if no query client has been set', async () => {
+ const { PreactQueryDevtoolsPanel } =
+ await import('../PreactQueryDevtoolsPanel')
+
+ expect(() => render()).toThrow(
+ 'No QueryClient set, use QueryClientProvider to set one',
+ )
+ })
+
+ it('should not throw an error if query client is provided via context', async () => {
+ const { PreactQueryDevtoolsPanel } =
+ await import('../PreactQueryDevtoolsPanel')
+ const queryClient = new QueryClient()
+
+ expect(() =>
+ render(
+
+
+ ,
+ ),
+ ).not.toThrow()
+ expect(mountMock).toHaveBeenCalled()
+ })
+
+ it('should not throw an error if query client is provided via props', async () => {
+ const { PreactQueryDevtoolsPanel } =
+ await import('../PreactQueryDevtoolsPanel')
+ const queryClient = new QueryClient()
+
+ expect(() =>
+ render(),
+ ).not.toThrow()
+ expect(mountMock).toHaveBeenCalled()
+ })
+
+ it('should return null in non-development environments', async () => {
+ vi.stubEnv('NODE_ENV', 'production')
+ vi.resetModules()
+
+ try {
+ const { PreactQueryDevtoolsPanel } = await import('..')
+ expect(PreactQueryDevtoolsPanel({})).toBeNull()
+ } finally {
+ vi.unstubAllEnvs()
+ vi.resetModules()
+ }
+ })
+})
diff --git a/packages/react-query-devtools/src/__tests__/ReactQueryDevtools.test.tsx b/packages/react-query-devtools/src/__tests__/ReactQueryDevtools.test.tsx
new file mode 100644
index 00000000000..0d48c3d173d
--- /dev/null
+++ b/packages/react-query-devtools/src/__tests__/ReactQueryDevtools.test.tsx
@@ -0,0 +1,77 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { render } from '@testing-library/react'
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+import type { TanstackQueryDevtools } from '@tanstack/query-devtools'
+
+const mountMock = vi.fn()
+const unmountMock = vi.fn()
+const setClientMock = vi.fn()
+const setButtonPositionMock = vi.fn()
+const setPositionMock = vi.fn()
+const setInitialIsOpenMock = vi.fn()
+const setErrorTypesMock = vi.fn()
+const setThemeMock = vi.fn()
+
+vi.mock('@tanstack/query-devtools', () => ({
+ TanstackQueryDevtools: vi.fn(function (this: TanstackQueryDevtools) {
+ this.mount = mountMock
+ this.unmount = unmountMock
+ this.setClient = setClientMock
+ this.setButtonPosition = setButtonPositionMock
+ this.setPosition = setPositionMock
+ this.setInitialIsOpen = setInitialIsOpenMock
+ this.setErrorTypes = setErrorTypesMock
+ this.setTheme = setThemeMock
+ }),
+}))
+
+describe('ReactQueryDevtools', () => {
+ beforeEach(() => {
+ vi.clearAllMocks()
+ })
+
+ it('should throw an error if no query client has been set', async () => {
+ const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
+
+ expect(() => render()).toThrow(
+ 'No QueryClient set, use QueryClientProvider to set one',
+ )
+ })
+
+ it('should not throw an error if query client is provided via context', async () => {
+ const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
+ const queryClient = new QueryClient()
+
+ expect(() =>
+ render(
+
+
+ ,
+ ),
+ ).not.toThrow()
+ expect(mountMock).toHaveBeenCalled()
+ })
+
+ it('should not throw an error if query client is provided via props', async () => {
+ const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
+ const queryClient = new QueryClient()
+
+ expect(() =>
+ render(),
+ ).not.toThrow()
+ expect(mountMock).toHaveBeenCalled()
+ })
+
+ it('should return null in non-development environments', async () => {
+ vi.stubEnv('NODE_ENV', 'production')
+ vi.resetModules()
+
+ try {
+ const { ReactQueryDevtools } = await import('..')
+ expect(ReactQueryDevtools({})).toBeNull()
+ } finally {
+ vi.unstubAllEnvs()
+ vi.resetModules()
+ }
+ })
+})
diff --git a/packages/react-query-devtools/src/__tests__/ReactQueryDevtoolsPanel.test.tsx b/packages/react-query-devtools/src/__tests__/ReactQueryDevtoolsPanel.test.tsx
new file mode 100644
index 00000000000..4beb7d99c02
--- /dev/null
+++ b/packages/react-query-devtools/src/__tests__/ReactQueryDevtoolsPanel.test.tsx
@@ -0,0 +1,78 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { render } from '@testing-library/react'
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+import type { TanstackQueryDevtoolsPanel } from '@tanstack/query-devtools'
+
+const mountMock = vi.fn()
+const unmountMock = vi.fn()
+const setClientMock = vi.fn()
+const setOnCloseMock = vi.fn()
+const setErrorTypesMock = vi.fn()
+const setThemeMock = vi.fn()
+
+vi.mock('@tanstack/query-devtools', () => ({
+ TanstackQueryDevtoolsPanel: vi.fn(function (
+ this: TanstackQueryDevtoolsPanel,
+ ) {
+ this.mount = mountMock
+ this.unmount = unmountMock
+ this.setClient = setClientMock
+ this.setOnClose = setOnCloseMock
+ this.setErrorTypes = setErrorTypesMock
+ this.setTheme = setThemeMock
+ }),
+}))
+
+describe('ReactQueryDevtoolsPanel', () => {
+ beforeEach(() => {
+ vi.clearAllMocks()
+ })
+
+ it('should throw an error if no query client has been set', async () => {
+ const { ReactQueryDevtoolsPanel } =
+ await import('../ReactQueryDevtoolsPanel')
+
+ expect(() => render()).toThrow(
+ 'No QueryClient set, use QueryClientProvider to set one',
+ )
+ })
+
+ it('should not throw an error if query client is provided via context', async () => {
+ const { ReactQueryDevtoolsPanel } =
+ await import('../ReactQueryDevtoolsPanel')
+ const queryClient = new QueryClient()
+
+ expect(() =>
+ render(
+
+
+ ,
+ ),
+ ).not.toThrow()
+ expect(mountMock).toHaveBeenCalled()
+ })
+
+ it('should not throw an error if query client is provided via props', async () => {
+ const { ReactQueryDevtoolsPanel } =
+ await import('../ReactQueryDevtoolsPanel')
+ const queryClient = new QueryClient()
+
+ expect(() =>
+ render(),
+ ).not.toThrow()
+ expect(mountMock).toHaveBeenCalled()
+ })
+
+ it('should return null in non-development environments', async () => {
+ vi.stubEnv('NODE_ENV', 'production')
+ vi.resetModules()
+
+ try {
+ const { ReactQueryDevtoolsPanel } = await import('..')
+ expect(ReactQueryDevtoolsPanel({})).toBeNull()
+ } finally {
+ vi.unstubAllEnvs()
+ vi.resetModules()
+ }
+ })
+})
diff --git a/packages/react-query-devtools/src/__tests__/devtools.test.tsx b/packages/react-query-devtools/src/__tests__/devtools.test.tsx
deleted file mode 100644
index 0e44d74db67..00000000000
--- a/packages/react-query-devtools/src/__tests__/devtools.test.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import { describe, expect, it } from 'vitest'
-
-describe('ReactQueryDevtools', () => {
- it('should be able to open and close devtools', () => {
- expect(1).toBe(1)
- })
-})
diff --git a/packages/react-query-devtools/src/__tests__/not-development.test.tsx b/packages/react-query-devtools/src/__tests__/not-development.test.tsx
deleted file mode 100644
index 6353147ed4d..00000000000
--- a/packages/react-query-devtools/src/__tests__/not-development.test.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { describe, expect, it } from 'vitest'
-import { ReactQueryDevtools } from '..'
-
-describe('ReactQueryDevtools not in process.env.NODE_ENV=development', () => {
- it('should return null', () => {
- expect(process.env.NODE_ENV).not.toBe('development')
- expect(ReactQueryDevtools({})).toBeNull()
- })
-})
diff --git a/packages/svelte-query-devtools/package.json b/packages/svelte-query-devtools/package.json
index 79cca89edbe..c6b58ea9a25 100644
--- a/packages/svelte-query-devtools/package.json
+++ b/packages/svelte-query-devtools/package.json
@@ -24,6 +24,8 @@
"compile": "tsc --build",
"test:types": "svelte-check --tsconfig ./tsconfig.json",
"test:eslint": "eslint --concurrency=auto ./src",
+ "test:lib": "vitest",
+ "test:lib:dev": "pnpm run test:lib --watch",
"test:build": "publint --strict && attw --pack",
"build": "svelte-package --input ./src --output ./dist"
},
@@ -53,6 +55,7 @@
"@sveltejs/package": "^2.4.0",
"@sveltejs/vite-plugin-svelte": "^5.1.1",
"@tanstack/svelte-query": "workspace:*",
+ "@testing-library/svelte": "^5.2.8",
"@typescript-eslint/parser": "^8.48.0",
"eslint-plugin-svelte": "^3.11.0",
"svelte": "^5.39.3",
diff --git a/packages/svelte-query-devtools/tests/Devtools.svelte.test.ts b/packages/svelte-query-devtools/tests/Devtools.svelte.test.ts
new file mode 100644
index 00000000000..dc773f54309
--- /dev/null
+++ b/packages/svelte-query-devtools/tests/Devtools.svelte.test.ts
@@ -0,0 +1,39 @@
+import { describe, expect, it } from 'vitest'
+import { render } from '@testing-library/svelte'
+import { QueryClient } from '@tanstack/svelte-query'
+import SvelteQueryDevtools from '../src/Devtools.svelte'
+import Wrapper from './Wrapper.svelte'
+
+describe('SvelteQueryDevtools', () => {
+ it('should render the parent container without throwing in non-development environments', () => {
+ const queryClient = new QueryClient()
+
+ const { container } = render(SvelteQueryDevtools, {
+ props: { client: queryClient },
+ })
+
+ expect(
+ container.querySelector('.tsqd-parent-container'),
+ ).toBeInTheDocument()
+ })
+
+ it('should throw an error if no query client has been set', () => {
+ expect(() => render(SvelteQueryDevtools)).toThrow(
+ 'No QueryClient was found in Svelte context. Did you forget to wrap your component with QueryClientProvider?',
+ )
+ })
+
+ it('should not throw an error if query client is provided via context', () => {
+ const queryClient = new QueryClient()
+
+ expect(() => render(Wrapper, { props: { queryClient } })).not.toThrow()
+ })
+
+ it('should not throw an error if query client is provided via props', () => {
+ const queryClient = new QueryClient()
+
+ expect(() =>
+ render(SvelteQueryDevtools, { props: { client: queryClient } }),
+ ).not.toThrow()
+ })
+})
diff --git a/packages/svelte-query-devtools/tests/Wrapper.svelte b/packages/svelte-query-devtools/tests/Wrapper.svelte
new file mode 100644
index 00000000000..35c5cf15176
--- /dev/null
+++ b/packages/svelte-query-devtools/tests/Wrapper.svelte
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/packages/svelte-query-devtools/tests/test-setup.ts b/packages/svelte-query-devtools/tests/test-setup.ts
new file mode 100644
index 00000000000..a9d0dd31aa6
--- /dev/null
+++ b/packages/svelte-query-devtools/tests/test-setup.ts
@@ -0,0 +1 @@
+import '@testing-library/jest-dom/vitest'
diff --git a/packages/svelte-query-devtools/tsconfig.json b/packages/svelte-query-devtools/tsconfig.json
index 773fd3d525d..cce7cfa8c38 100644
--- a/packages/svelte-query-devtools/tsconfig.json
+++ b/packages/svelte-query-devtools/tsconfig.json
@@ -4,6 +4,6 @@
"outDir": "./dist-ts",
"rootDir": "."
},
- "include": ["src", "*.config.*", "package.json"],
+ "include": ["src", "tests", "*.config.*", "package.json"],
"references": [{ "path": "../query-devtools" }, { "path": "../svelte-query" }]
}
diff --git a/packages/svelte-query-devtools/vite.config.ts b/packages/svelte-query-devtools/vite.config.ts
index 01ebc554bd3..5b2d97f30f2 100644
--- a/packages/svelte-query-devtools/vite.config.ts
+++ b/packages/svelte-query-devtools/vite.config.ts
@@ -1,8 +1,11 @@
import { svelte } from '@sveltejs/vite-plugin-svelte'
-import { defineConfig } from 'vite'
+import { defineConfig } from 'vitest/config'
+import { svelteTesting } from '@testing-library/svelte/vite'
+
+import packageJson from './package.json'
export default defineConfig({
- plugins: [svelte()],
+ plugins: [svelte(), svelteTesting()],
// fix from https://github.com/vitest-dev/vitest/issues/6992#issuecomment-2509408660
resolve: {
conditions: ['@tanstack/custom-condition'],
@@ -14,4 +17,17 @@ export default defineConfig({
},
},
},
+ test: {
+ name: packageJson.name,
+ dir: './tests',
+ watch: false,
+ environment: 'jsdom',
+ setupFiles: ['./tests/test-setup.ts'],
+ coverage: {
+ enabled: true,
+ provider: 'istanbul',
+ include: ['src/**/*'],
+ },
+ typecheck: { enabled: true },
+ },
})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 258ab23246e..82cb34c9228 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -2936,6 +2936,9 @@ importers:
'@tanstack/svelte-query':
specifier: workspace:*
version: link:../svelte-query
+ '@testing-library/svelte':
+ specifier: ^5.2.8
+ version: 5.3.1(svelte@5.55.1)(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.90.0)(terser@5.46.1)(yaml@2.8.3))(vitest@4.1.2(@types/node@22.19.15)(jsdom@27.4.0)(msw@2.12.14(@types/node@22.19.15)(typescript@5.9.3))(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.90.0)(terser@5.46.1)(yaml@2.8.3)))
'@typescript-eslint/parser':
specifier: 8.58.1
version: 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)