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()
- })
-})