import { beforeEach, describe, expect, it, vi } from 'vitest'
import { render } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { 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 forward "buttonPosition" to the devtools instance', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
render(
,
)
expect(setButtonPositionMock).toHaveBeenCalledWith('top-left')
})
it('should forward "position" to the devtools instance', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
render()
expect(setPositionMock).toHaveBeenCalledWith('left')
})
it('should forward "initialIsOpen" to the devtools instance', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
render()
expect(setInitialIsOpenMock).toHaveBeenCalledWith(true)
})
it('should default "initialIsOpen" to "false" when the prop is omitted', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
render()
expect(setInitialIsOpenMock).toHaveBeenCalledWith(false)
})
it('should forward "errorTypes" to the devtools instance', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
const errorTypes = [
{ name: 'Network', initializer: () => new Error('Network') },
]
render()
expect(setErrorTypesMock).toHaveBeenCalledWith(errorTypes)
})
it('should default "errorTypes" to an empty array when the prop is omitted', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
render()
expect(setErrorTypesMock).toHaveBeenCalledWith([])
})
it('should forward "theme" to the devtools instance', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
render()
expect(setThemeMock).toHaveBeenCalledWith('dark')
})
it('should forward the resolved "QueryClient" via "setClient"', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
render()
expect(setClientMock).toHaveBeenCalledWith(queryClient)
})
it('should forward "styleNonce" to the devtools constructor', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
render()
expect(TanstackQueryDevtools).toHaveBeenCalledWith(
expect.objectContaining({ styleNonce: 'abc' }),
)
})
it('should forward "shadowDOMTarget" to the devtools constructor', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
const shadowDOMTarget = document
.createElement('div')
.attachShadow({ mode: 'open' })
render(
,
)
expect(TanstackQueryDevtools).toHaveBeenCalledWith(
expect.objectContaining({ shadowDOMTarget }),
)
})
it('should forward "hideDisabledQueries" to the devtools constructor', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
render(
,
)
expect(TanstackQueryDevtools).toHaveBeenCalledWith(
expect.objectContaining({ hideDisabledQueries: true }),
)
})
it('should call "unmount" on the devtools instance when the component unmounts', async () => {
const { ReactQueryDevtools } = await import('../ReactQueryDevtools')
const queryClient = new QueryClient()
const { unmount } = render()
unmount()
expect(unmountMock).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()
}
})
})