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..ad60e9c3d0d
--- /dev/null
+++ b/packages/preact-query-devtools/src/__tests__/PreactQueryDevtools.test.tsx
@@ -0,0 +1,71 @@
+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 () => {
+ const { PreactQueryDevtools } = await import('..')
+
+ expect(process.env.NODE_ENV).not.toBe('development')
+ expect(PreactQueryDevtools({})).toBeNull()
+ })
+})
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..66930e5bd5a
--- /dev/null
+++ b/packages/preact-query-devtools/src/__tests__/PreactQueryDevtoolsPanel.test.tsx
@@ -0,0 +1,72 @@
+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 () => {
+ const { PreactQueryDevtoolsPanel } = await import('..')
+
+ expect(process.env.NODE_ENV).not.toBe('development')
+ expect(PreactQueryDevtoolsPanel({})).toBeNull()
+ })
+})