diff --git a/packages/query-devtools/src/__tests__/TanstackQueryDevtools.test.tsx b/packages/query-devtools/src/__tests__/TanstackQueryDevtools.test.tsx new file mode 100644 index 00000000000..01c8969f3ae --- /dev/null +++ b/packages/query-devtools/src/__tests__/TanstackQueryDevtools.test.tsx @@ -0,0 +1,59 @@ +import { beforeEach, describe, expect, it } from 'vitest' +import { QueryClient, onlineManager } from '@tanstack/query-core' +import { TanstackQueryDevtools } from '..' + +describe('TanstackQueryDevtools', () => { + let devtools: TanstackQueryDevtools + + beforeEach(() => { + devtools = new TanstackQueryDevtools({ + client: new QueryClient(), + queryFlavor: 'TanStack Query', + version: '5', + onlineManager, + }) + }) + + describe('mount', () => { + it('should mount devtools to the provided element', () => { + const el = document.createElement('div') + + expect(() => devtools.mount(el)).not.toThrow() + + devtools.unmount() + }) + + it('should throw if mount is called twice without unmount', () => { + const el = document.createElement('div') + devtools.mount(el) + + expect(() => devtools.mount(el)).toThrow('Devtools is already mounted') + + devtools.unmount() + }) + }) + + describe('unmount', () => { + it('should unmount devtools and allow remounting', () => { + const el = document.createElement('div') + devtools.mount(el) + + expect(() => devtools.unmount()).not.toThrow() + expect(() => devtools.mount(el)).not.toThrow() + + devtools.unmount() + }) + + it('should throw if unmount is called before mount', () => { + expect(() => devtools.unmount()).toThrow('Devtools is not mounted') + }) + + it('should throw if unmount is called twice', () => { + const el = document.createElement('div') + devtools.mount(el) + devtools.unmount() + + expect(() => devtools.unmount()).toThrow('Devtools is not mounted') + }) + }) +}) diff --git a/packages/query-devtools/src/__tests__/TanstackQueryDevtoolsPanel.test.tsx b/packages/query-devtools/src/__tests__/TanstackQueryDevtoolsPanel.test.tsx new file mode 100644 index 00000000000..1993ef67798 --- /dev/null +++ b/packages/query-devtools/src/__tests__/TanstackQueryDevtoolsPanel.test.tsx @@ -0,0 +1,59 @@ +import { beforeEach, describe, expect, it } from 'vitest' +import { QueryClient, onlineManager } from '@tanstack/query-core' +import { TanstackQueryDevtoolsPanel } from '..' + +describe('TanstackQueryDevtoolsPanel', () => { + let devtools: TanstackQueryDevtoolsPanel + + beforeEach(() => { + devtools = new TanstackQueryDevtoolsPanel({ + client: new QueryClient(), + queryFlavor: 'TanStack Query', + version: '5', + onlineManager, + }) + }) + + describe('mount', () => { + it('should mount devtools to the provided element', () => { + const el = document.createElement('div') + + expect(() => devtools.mount(el)).not.toThrow() + + devtools.unmount() + }) + + it('should throw if mount is called twice without unmount', () => { + const el = document.createElement('div') + devtools.mount(el) + + expect(() => devtools.mount(el)).toThrow('Devtools is already mounted') + + devtools.unmount() + }) + }) + + describe('unmount', () => { + it('should unmount devtools and allow remounting', () => { + const el = document.createElement('div') + devtools.mount(el) + + expect(() => devtools.unmount()).not.toThrow() + expect(() => devtools.mount(el)).not.toThrow() + + devtools.unmount() + }) + + it('should throw if unmount is called before mount', () => { + expect(() => devtools.unmount()).toThrow('Devtools is not mounted') + }) + + it('should throw if unmount is called twice', () => { + const el = document.createElement('div') + devtools.mount(el) + devtools.unmount() + + expect(() => devtools.unmount()).toThrow('Devtools is not mounted') + }) + }) +}) diff --git a/packages/query-devtools/src/__tests__/devtools.test.tsx b/packages/query-devtools/src/__tests__/devtools.test.tsx deleted file mode 100644 index 0e44d74db67..00000000000 --- a/packages/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/query-devtools/src/__tests__/utils.test.ts b/packages/query-devtools/src/__tests__/utils.test.ts index 60fbcf130ec..1c30c5e9182 100644 --- a/packages/query-devtools/src/__tests__/utils.test.ts +++ b/packages/query-devtools/src/__tests__/utils.test.ts @@ -1,5 +1,13 @@ import { describe, expect, it } from 'vitest' -import { deleteNestedDataByPath, updateNestedDataByPath } from '../utils' +import { + deleteNestedDataByPath, + displayValue, + getMutationStatusColor, + getQueryStatusColorByLabel, + getSidedProp, + updateNestedDataByPath, +} from '../utils' +import type { MutationStatus } from '@tanstack/query-core' describe('Utils tests', () => { describe('updatedNestedDataByPath', () => { @@ -729,4 +737,113 @@ describe('Utils tests', () => { }) }) }) + + describe('getMutationStatusColor', () => { + const cases: Array<{ + label: string + status: MutationStatus + isPaused: boolean + expected: string + }> = [ + { + label: 'paused', + status: 'pending', + isPaused: true, + expected: 'purple', + }, + { + label: 'paused even when status is "error"', + status: 'error', + isPaused: true, + expected: 'purple', + }, + { label: '"error"', status: 'error', isPaused: false, expected: 'red' }, + { + label: '"pending"', + status: 'pending', + isPaused: false, + expected: 'yellow', + }, + { + label: '"success"', + status: 'success', + isPaused: false, + expected: 'green', + }, + { label: '"idle"', status: 'idle', isPaused: false, expected: 'gray' }, + ] + + it.each(cases)( + 'should return "$expected" when mutation is $label', + ({ status, isPaused, expected }) => { + expect(getMutationStatusColor({ status, isPaused })).toBe(expected) + }, + ) + }) + + describe('getQueryStatusColorByLabel', () => { + it('should return "green" for "fresh"', () => { + expect(getQueryStatusColorByLabel('fresh')).toBe('green') + }) + + it('should return "yellow" for "stale"', () => { + expect(getQueryStatusColorByLabel('stale')).toBe('yellow') + }) + + it('should return "purple" for "paused"', () => { + expect(getQueryStatusColorByLabel('paused')).toBe('purple') + }) + + it('should return "gray" for "inactive"', () => { + expect(getQueryStatusColorByLabel('inactive')).toBe('gray') + }) + + it('should return "blue" for "fetching"', () => { + expect(getQueryStatusColorByLabel('fetching')).toBe('blue') + }) + }) + + describe('displayValue', () => { + it('should stringify a primitive value', () => { + expect(displayValue('hello')).toBe('"hello"') + }) + + it('should stringify a number', () => { + expect(displayValue(42)).toBe('42') + }) + + it('should serialize an object using superjson and discard meta', () => { + expect(displayValue({ a: 1, b: 'two' })).toBe('{"a":1,"b":"two"}') + }) + + it('should return "null" for "undefined" since only the json part is used', () => { + expect(displayValue(undefined)).toBe('null') + }) + + it('should return a single-line string by default', () => { + expect(displayValue({ a: 1 })).toBe('{"a":1}') + }) + + it('should return an indented multi-line string when "beautify" is true', () => { + expect(displayValue({ a: 1 }, true)).toBe('{\n "a": 1\n}') + }) + }) + + describe('getSidedProp', () => { + it('should append capitalized "top" to the prop', () => { + expect(getSidedProp('margin', 'top')).toBe('marginTop') + }) + + it('should append capitalized "bottom" to the prop', () => { + expect(getSidedProp('margin', 'bottom')).toBe('marginBottom') + }) + + it('should append capitalized "left" to the prop', () => { + expect(getSidedProp('padding', 'left')).toBe('paddingLeft') + }) + + it('should append capitalized "right" to the prop', () => { + expect(getSidedProp('padding', 'right')).toBe('paddingRight') + }) + }) })