diff --git a/packages/query-devtools/src/__tests__/TanstackQueryDevtools.test.tsx b/packages/query-devtools/src/__tests__/TanstackQueryDevtools.test.tsx index 01c8969f3a..cef4475d83 100644 --- a/packages/query-devtools/src/__tests__/TanstackQueryDevtools.test.tsx +++ b/packages/query-devtools/src/__tests__/TanstackQueryDevtools.test.tsx @@ -56,4 +56,61 @@ describe('TanstackQueryDevtools', () => { expect(() => devtools.unmount()).toThrow('Devtools is not mounted') }) }) + + describe('setters', () => { + describe('before mount', () => { + it('should not throw when "setButtonPosition" is called', () => { + expect(() => devtools.setButtonPosition('top-left')).not.toThrow() + }) + + it('should not throw when "setPosition" is called', () => { + expect(() => devtools.setPosition('left')).not.toThrow() + }) + + it('should not throw when "setInitialIsOpen" is called', () => { + expect(() => devtools.setInitialIsOpen(true)).not.toThrow() + }) + + it('should not throw when "setErrorTypes" is called', () => { + expect(() => + devtools.setErrorTypes([ + { name: 'NetworkError', initializer: () => new Error('Network') }, + ]), + ).not.toThrow() + }) + + it('should not throw when "setClient" is called', () => { + expect(() => devtools.setClient(new QueryClient())).not.toThrow() + }) + + it('should not throw when "setTheme" is called', () => { + expect(() => devtools.setTheme('dark')).not.toThrow() + expect(() => devtools.setTheme('light')).not.toThrow() + expect(() => devtools.setTheme('system')).not.toThrow() + expect(() => devtools.setTheme(undefined)).not.toThrow() + }) + }) + + describe('after mount', () => { + it('should not throw when setters are called on a mounted instance', () => { + const el = document.createElement('div') + devtools.mount(el) + + try { + expect(() => devtools.setButtonPosition('top-left')).not.toThrow() + expect(() => devtools.setPosition('left')).not.toThrow() + expect(() => devtools.setInitialIsOpen(true)).not.toThrow() + expect(() => + devtools.setErrorTypes([ + { name: 'NetworkError', initializer: () => new Error('Network') }, + ]), + ).not.toThrow() + expect(() => devtools.setClient(new QueryClient())).not.toThrow() + expect(() => devtools.setTheme('dark')).not.toThrow() + } finally { + devtools.unmount() + } + }) + }) + }) }) diff --git a/packages/query-devtools/src/__tests__/TanstackQueryDevtoolsPanel.test.tsx b/packages/query-devtools/src/__tests__/TanstackQueryDevtoolsPanel.test.tsx index 1993ef6779..f7407ad5ff 100644 --- a/packages/query-devtools/src/__tests__/TanstackQueryDevtoolsPanel.test.tsx +++ b/packages/query-devtools/src/__tests__/TanstackQueryDevtoolsPanel.test.tsx @@ -56,4 +56,66 @@ describe('TanstackQueryDevtoolsPanel', () => { expect(() => devtools.unmount()).toThrow('Devtools is not mounted') }) }) + + describe('setters', () => { + describe('before mount', () => { + it('should not throw when "setButtonPosition" is called', () => { + expect(() => devtools.setButtonPosition('top-left')).not.toThrow() + }) + + it('should not throw when "setPosition" is called', () => { + expect(() => devtools.setPosition('left')).not.toThrow() + }) + + it('should not throw when "setInitialIsOpen" is called', () => { + expect(() => devtools.setInitialIsOpen(true)).not.toThrow() + }) + + it('should not throw when "setErrorTypes" is called', () => { + expect(() => + devtools.setErrorTypes([ + { name: 'NetworkError', initializer: () => new Error('Network') }, + ]), + ).not.toThrow() + }) + + it('should not throw when "setClient" is called', () => { + expect(() => devtools.setClient(new QueryClient())).not.toThrow() + }) + + it('should not throw when "setOnClose" is called', () => { + expect(() => devtools.setOnClose(() => {})).not.toThrow() + }) + + it('should not throw when "setTheme" is called', () => { + expect(() => devtools.setTheme('dark')).not.toThrow() + expect(() => devtools.setTheme('light')).not.toThrow() + expect(() => devtools.setTheme('system')).not.toThrow() + expect(() => devtools.setTheme(undefined)).not.toThrow() + }) + }) + + describe('after mount', () => { + it('should not throw when setters are called on a mounted instance', () => { + const el = document.createElement('div') + devtools.mount(el) + + try { + expect(() => devtools.setButtonPosition('top-left')).not.toThrow() + expect(() => devtools.setPosition('left')).not.toThrow() + expect(() => devtools.setInitialIsOpen(true)).not.toThrow() + expect(() => + devtools.setErrorTypes([ + { name: 'NetworkError', initializer: () => new Error('Network') }, + ]), + ).not.toThrow() + expect(() => devtools.setClient(new QueryClient())).not.toThrow() + expect(() => devtools.setOnClose(() => {})).not.toThrow() + expect(() => devtools.setTheme('dark')).not.toThrow() + } finally { + devtools.unmount() + } + }) + }) + }) }) diff --git a/packages/query-devtools/src/__tests__/utils.test.ts b/packages/query-devtools/src/__tests__/utils.test.ts index 0c1fb6ec50..07dff9ece4 100644 --- a/packages/query-devtools/src/__tests__/utils.test.ts +++ b/packages/query-devtools/src/__tests__/utils.test.ts @@ -539,6 +539,38 @@ describe('Utils tests', () => { `) }) + describe('array nested path', () => { + it('should delete nested data inside an array correctly', () => { + const oldData = [ + { id: 1, title: 'first' }, + { id: 2, title: 'second' }, + ] + + const newData = deleteNestedDataByPath(oldData, ['1', 'title']) + + expect(newData).not.toBe(oldData) + expect(newData).toMatchInlineSnapshot(` + [ + { + "id": 1, + "title": "first", + }, + { + "id": 2, + }, + ] + `) + }) + }) + + describe('primitive', () => { + it('should return primitive data as-is when it is not an Object/Array/Map/Set', () => { + expect(deleteNestedDataByPath(42, ['x'])).toBe(42) + expect(deleteNestedDataByPath('hello', ['x'])).toBe('hello') + expect(deleteNestedDataByPath(null, ['x'])).toBe(null) + }) + }) + describe('nested data', () => { it('should delete nested items correctly', () => { /* eslint-disable cspell/spellchecker */ @@ -1114,6 +1146,37 @@ describe('Utils tests', () => { } }) + it('should place a stale query after a fresh one when both are idle and have observers', () => { + const staleObserver = new QueryObserver(queryClient, { + queryKey: ['stale'], + staleTime: 0, + }) + const staleUnsubscribe = staleObserver.subscribe(() => {}) + const stale = queryClient.getQueryCache().find({ queryKey: ['stale'] })! + stale.setState({ + ...stale.state, + fetchStatus: 'idle', + data: 'data', + dataUpdatedAt: 200, + }) + + const fresh = buildQuery(['fresh'], { + fetchStatus: 'idle', + data: 'fresh-data', + dataUpdatedAt: 100, + }) + const freshUnsubscribe = addObserver(fresh) + + try { + expect(stale.isStale()).toBe(true) + expect(statusSort(fresh, stale)).toBe(-1) + expect(statusSort(stale, fresh)).toBe(1) + } finally { + staleUnsubscribe() + freshUnsubscribe() + } + }) + it('should fall back to "last updated" sort within the same status rank', () => { const older = buildQuery(['older'], { dataUpdatedAt: 100 }) const newer = buildQuery(['newer'], { dataUpdatedAt: 200 })