@tanstack/react-query-devtools 5.0.0-alpha.26 → 5.0.0-alpha.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/build/lib/__tests__/devtools.test.d.ts +0 -1
  2. package/build/lib/__tests__/devtools.test.d.ts.map +1 -1
  3. package/build/lib/devtools.d.ts +8 -30
  4. package/build/lib/devtools.d.ts.map +1 -1
  5. package/build/lib/devtools.esm.js +47 -226
  6. package/build/lib/devtools.esm.js.map +1 -1
  7. package/build/lib/devtools.js +45 -244
  8. package/build/lib/devtools.js.map +1 -1
  9. package/build/lib/devtools.mjs +47 -225
  10. package/build/lib/devtools.mjs.map +1 -1
  11. package/build/lib/index.d.ts +0 -1
  12. package/build/lib/index.d.ts.map +1 -1
  13. package/build/lib/index.esm.js +8 -5
  14. package/build/lib/index.esm.js.map +1 -1
  15. package/build/lib/index.js +7 -5
  16. package/build/lib/index.js.map +1 -1
  17. package/build/lib/index.mjs +8 -5
  18. package/build/lib/index.mjs.map +1 -1
  19. package/build/lib/index.prod.d.ts +0 -1
  20. package/build/lib/index.prod.esm.js +7901 -1501
  21. package/build/lib/index.prod.esm.js.map +1 -1
  22. package/build/lib/index.prod.js +7909 -1528
  23. package/build/lib/index.prod.js.map +1 -1
  24. package/build/lib/index.prod.mjs +7922 -1489
  25. package/build/lib/index.prod.mjs.map +1 -1
  26. package/build/umd/index.development.js +7146 -2375
  27. package/build/umd/index.development.js.map +1 -1
  28. package/build/umd/index.production.js +1 -1
  29. package/build/umd/index.production.js.map +1 -1
  30. package/package.json +2 -3
  31. package/src/__tests__/devtools.test.tsx +1 -1135
  32. package/src/devtools.tsx +52 -306
  33. package/src/index.ts +6 -6
  34. package/build/lib/CachePanel/ActiveQuery.d.ts +0 -19
  35. package/build/lib/CachePanel/ActiveQuery.d.ts.map +0 -1
  36. package/build/lib/CachePanel/ActiveQuery.esm.js +0 -277
  37. package/build/lib/CachePanel/ActiveQuery.esm.js.map +0 -1
  38. package/build/lib/CachePanel/ActiveQuery.js +0 -281
  39. package/build/lib/CachePanel/ActiveQuery.js.map +0 -1
  40. package/build/lib/CachePanel/ActiveQuery.mjs +0 -261
  41. package/build/lib/CachePanel/ActiveQuery.mjs.map +0 -1
  42. package/build/lib/CachePanel/CachePanel.d.ts +0 -58
  43. package/build/lib/CachePanel/CachePanel.d.ts.map +0 -1
  44. package/build/lib/CachePanel/CachePanel.esm.js +0 -310
  45. package/build/lib/CachePanel/CachePanel.esm.js.map +0 -1
  46. package/build/lib/CachePanel/CachePanel.js +0 -315
  47. package/build/lib/CachePanel/CachePanel.js.map +0 -1
  48. package/build/lib/CachePanel/CachePanel.mjs +0 -310
  49. package/build/lib/CachePanel/CachePanel.mjs.map +0 -1
  50. package/build/lib/CachePanel/Header/QueryStatusCount.d.ts +0 -8
  51. package/build/lib/CachePanel/Header/QueryStatusCount.d.ts.map +0 -1
  52. package/build/lib/CachePanel/Header/QueryStatusCount.esm.js +0 -49
  53. package/build/lib/CachePanel/Header/QueryStatusCount.esm.js.map +0 -1
  54. package/build/lib/CachePanel/Header/QueryStatusCount.js +0 -53
  55. package/build/lib/CachePanel/Header/QueryStatusCount.js.map +0 -1
  56. package/build/lib/CachePanel/Header/QueryStatusCount.mjs +0 -49
  57. package/build/lib/CachePanel/Header/QueryStatusCount.mjs.map +0 -1
  58. package/build/lib/CachePanel/QueryRow.d.ts +0 -14
  59. package/build/lib/CachePanel/QueryRow.d.ts.map +0 -1
  60. package/build/lib/CachePanel/QueryRow.esm.js +0 -98
  61. package/build/lib/CachePanel/QueryRow.esm.js.map +0 -1
  62. package/build/lib/CachePanel/QueryRow.js +0 -102
  63. package/build/lib/CachePanel/QueryRow.js.map +0 -1
  64. package/build/lib/CachePanel/QueryRow.mjs +0 -82
  65. package/build/lib/CachePanel/QueryRow.mjs.map +0 -1
  66. package/build/lib/Explorer.d.ts +0 -51
  67. package/build/lib/Explorer.d.ts.map +0 -1
  68. package/build/lib/Explorer.esm.js +0 -254
  69. package/build/lib/Explorer.esm.js.map +0 -1
  70. package/build/lib/Explorer.js +0 -288
  71. package/build/lib/Explorer.js.map +0 -1
  72. package/build/lib/Explorer.mjs +0 -254
  73. package/build/lib/Explorer.mjs.map +0 -1
  74. package/build/lib/Logo.d.ts +0 -2
  75. package/build/lib/Logo.esm.js +0 -32
  76. package/build/lib/Logo.esm.js.map +0 -1
  77. package/build/lib/Logo.js +0 -55
  78. package/build/lib/Logo.js.map +0 -1
  79. package/build/lib/Logo.mjs +0 -32
  80. package/build/lib/Logo.mjs.map +0 -1
  81. package/build/lib/__tests__/Explorer.test.d.ts +0 -2
  82. package/build/lib/__tests__/Explorer.test.d.ts.map +0 -1
  83. package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js +0 -17
  84. package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js.map +0 -1
  85. package/build/lib/_virtual/_rollupPluginBabelHelpers.js +0 -19
  86. package/build/lib/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
  87. package/build/lib/_virtual/_rollupPluginBabelHelpers.mjs +0 -17
  88. package/build/lib/_virtual/_rollupPluginBabelHelpers.mjs.map +0 -1
  89. package/build/lib/noop.d.ts +0 -3
  90. package/build/lib/screenreader.d.ts +0 -4
  91. package/build/lib/screenreader.esm.js +0 -17
  92. package/build/lib/screenreader.esm.js.map +0 -1
  93. package/build/lib/screenreader.js +0 -40
  94. package/build/lib/screenreader.js.map +0 -1
  95. package/build/lib/screenreader.mjs +0 -17
  96. package/build/lib/screenreader.mjs.map +0 -1
  97. package/build/lib/styledComponents.d.ts +0 -9
  98. package/build/lib/styledComponents.d.ts.map +0 -1
  99. package/build/lib/styledComponents.esm.js +0 -103
  100. package/build/lib/styledComponents.esm.js.map +0 -1
  101. package/build/lib/styledComponents.js +0 -112
  102. package/build/lib/styledComponents.js.map +0 -1
  103. package/build/lib/styledComponents.mjs +0 -103
  104. package/build/lib/styledComponents.mjs.map +0 -1
  105. package/build/lib/theme.d.ts +0 -37
  106. package/build/lib/theme.esm.js +0 -33
  107. package/build/lib/theme.esm.js.map +0 -1
  108. package/build/lib/theme.js +0 -56
  109. package/build/lib/theme.js.map +0 -1
  110. package/build/lib/theme.mjs +0 -33
  111. package/build/lib/theme.mjs.map +0 -1
  112. package/build/lib/types.d.ts +0 -12
  113. package/build/lib/types.d.ts.map +0 -1
  114. package/build/lib/useLocalStorage.d.ts +0 -2
  115. package/build/lib/useLocalStorage.esm.js +0 -40
  116. package/build/lib/useLocalStorage.esm.js.map +0 -1
  117. package/build/lib/useLocalStorage.js +0 -63
  118. package/build/lib/useLocalStorage.js.map +0 -1
  119. package/build/lib/useLocalStorage.mjs +0 -40
  120. package/build/lib/useLocalStorage.mjs.map +0 -1
  121. package/build/lib/useMediaQuery.d.ts +0 -2
  122. package/build/lib/useMediaQuery.esm.js +0 -36
  123. package/build/lib/useMediaQuery.esm.js.map +0 -1
  124. package/build/lib/useMediaQuery.js +0 -59
  125. package/build/lib/useMediaQuery.js.map +0 -1
  126. package/build/lib/useMediaQuery.mjs +0 -36
  127. package/build/lib/useMediaQuery.mjs.map +0 -1
  128. package/build/lib/useSubscribeToQueryCache.d.ts +0 -4
  129. package/build/lib/useSubscribeToQueryCache.d.ts.map +0 -1
  130. package/build/lib/useSubscribeToQueryCache.esm.js +0 -15
  131. package/build/lib/useSubscribeToQueryCache.esm.js.map +0 -1
  132. package/build/lib/useSubscribeToQueryCache.js +0 -19
  133. package/build/lib/useSubscribeToQueryCache.js.map +0 -1
  134. package/build/lib/useSubscribeToQueryCache.mjs +0 -15
  135. package/build/lib/useSubscribeToQueryCache.mjs.map +0 -1
  136. package/build/lib/utils.d.ts +0 -80
  137. package/build/lib/utils.d.ts.map +0 -1
  138. package/build/lib/utils.esm.js +0 -184
  139. package/build/lib/utils.esm.js.map +0 -1
  140. package/build/lib/utils.js +0 -218
  141. package/build/lib/utils.js.map +0 -1
  142. package/build/lib/utils.mjs +0 -184
  143. package/build/lib/utils.mjs.map +0 -1
  144. package/src/CachePanel/ActiveQuery.tsx +0 -388
  145. package/src/CachePanel/CachePanel.tsx +0 -439
  146. package/src/CachePanel/Header/QueryStatusCount.tsx +0 -93
  147. package/src/CachePanel/QueryRow.tsx +0 -125
  148. package/src/Explorer.tsx +0 -385
  149. package/src/Logo.tsx +0 -32
  150. package/src/__tests__/Explorer.test.tsx +0 -150
  151. package/src/noop.ts +0 -7
  152. package/src/screenreader.tsx +0 -16
  153. package/src/styledComponents.ts +0 -126
  154. package/src/theme.tsx +0 -33
  155. package/src/types.ts +0 -12
  156. package/src/useLocalStorage.ts +0 -52
  157. package/src/useMediaQuery.ts +0 -34
  158. package/src/useSubscribeToQueryCache.ts +0 -26
  159. package/src/utils.ts +0 -319
@@ -1,1139 +1,5 @@
1
- import * as React from 'react'
2
- import { fireEvent, screen, waitFor, act } from '@testing-library/react'
3
- import '@testing-library/jest-dom'
4
- import { useQuery, onlineManager } from '@tanstack/react-query'
5
- import { defaultPanelSize, sortFns } from '../utils'
6
- import {
7
- getByTextContent,
8
- renderWithClient,
9
- sleep,
10
- createQueryClient,
11
- } from './utils'
12
- import { vi } from 'vitest'
13
- import UserEvent from '@testing-library/user-event'
14
-
15
- class CustomError extends Error {
16
- constructor(message: string) {
17
- super(message)
18
- this.name = 'CustomError'
19
- }
20
- }
21
-
22
- Object.defineProperty(window, 'matchMedia', {
23
- writable: true,
24
- value: vi.fn().mockImplementation((query: string) => ({
25
- matches: false,
26
- media: query,
27
- onchange: null,
28
- addListener: vi.fn(), // deprecated
29
- removeListener: vi.fn(), // deprecated
30
- addEventListener: vi.fn(),
31
- removeEventListener: vi.fn(),
32
- dispatchEvent: vi.fn(),
33
- })),
34
- })
35
-
36
1
  describe('ReactQueryDevtools', () => {
37
- beforeEach(() => {
38
- localStorage.removeItem('reactQueryDevtoolsOpen')
39
- localStorage.removeItem('reactQueryDevtoolsPanelPosition')
40
- })
41
2
  it('should be able to open and close devtools', async () => {
42
- const { queryClient } = createQueryClient()
43
- const onCloseClick = vi.fn()
44
- const onToggleClick = vi.fn()
45
-
46
- function Page() {
47
- const { data = 'default' } = useQuery({
48
- queryKey: ['check'],
49
- queryFn: async () => {
50
- await sleep(10)
51
- return 'test'
52
- },
53
- })
54
-
55
- return (
56
- <div>
57
- <h1>{data}</h1>
58
- </div>
59
- )
60
- }
61
-
62
- renderWithClient(queryClient, <Page />, {
63
- initialIsOpen: false,
64
- closeButtonProps: { onClick: onCloseClick },
65
- toggleButtonProps: { onClick: onToggleClick },
66
- })
67
-
68
- const verifyDevtoolsIsOpen = () => {
69
- expect(
70
- screen.queryByRole('generic', { name: /react query devtools panel/i }),
71
- ).not.toBeNull()
72
- expect(
73
- screen.queryByRole('button', { name: /open react query devtools/i }),
74
- ).toBeNull()
75
- }
76
- const verifyDevtoolsIsClosed = () => {
77
- expect(
78
- screen.queryByRole('generic', { name: /react query devtools panel/i }),
79
- ).toBeNull()
80
- expect(
81
- screen.queryByRole('button', { name: /open react query devtools/i }),
82
- ).not.toBeNull()
83
- }
84
-
85
- const waitForDevtoolsToOpen = () =>
86
- screen.findByRole('button', { name: /close react query devtools/i })
87
- const waitForDevtoolsToClose = () =>
88
- screen.findByRole('button', { name: /open react query devtools/i })
89
-
90
- const getOpenLogoButton = () =>
91
- screen.getByRole('button', { name: /open react query devtools/i })
92
- const getCloseLogoButton = () =>
93
- screen.getByRole('button', { name: /close react query devtools/i })
94
- const getCloseButton = () =>
95
- screen.getByRole('button', { name: /^close$/i })
96
-
97
- verifyDevtoolsIsClosed()
98
-
99
- fireEvent.click(getOpenLogoButton())
100
- await waitForDevtoolsToOpen()
101
-
102
- verifyDevtoolsIsOpen()
103
-
104
- fireEvent.click(getCloseLogoButton())
105
- await waitForDevtoolsToClose()
106
-
107
- verifyDevtoolsIsClosed()
108
-
109
- fireEvent.click(getOpenLogoButton())
110
- await waitForDevtoolsToOpen()
111
-
112
- verifyDevtoolsIsOpen()
113
-
114
- fireEvent.click(getCloseButton())
115
- await waitForDevtoolsToClose()
116
-
117
- verifyDevtoolsIsClosed()
118
- })
119
-
120
- it('should be able to drag devtools without error', async () => {
121
- const { queryClient } = createQueryClient()
122
-
123
- function Page() {
124
- const { data = 'default' } = useQuery({
125
- queryKey: ['check'],
126
- queryFn: async () => {
127
- await sleep(10)
128
- return 'test'
129
- },
130
- })
131
-
132
- return (
133
- <div>
134
- <h1>{data}</h1>
135
- </div>
136
- )
137
- }
138
-
139
- const result = renderWithClient(queryClient, <Page />, {
140
- initialIsOpen: false,
141
- })
142
-
143
- const draggableElement = result.container
144
- .querySelector('#ReactQueryDevtoolsPanel')
145
- ?.querySelector('div')
146
-
147
- if (!draggableElement) {
148
- throw new Error('Could not find the draggable element')
149
- }
150
-
151
- await act(async () => {
152
- fireEvent.mouseDown(draggableElement)
153
- })
154
- })
155
-
156
- it('should display the correct query states', async () => {
157
- const { queryClient, queryCache } = createQueryClient()
158
-
159
- function Page() {
160
- const { data = 'default' } = useQuery({
161
- queryKey: ['check'],
162
- queryFn: async () => {
163
- await sleep(100)
164
- return 'test'
165
- },
166
- staleTime: 300,
167
- })
168
-
169
- return (
170
- <div>
171
- <h1>{data}</h1>
172
- </div>
173
- )
174
- }
175
-
176
- function PageParent() {
177
- const [isPageVisible, togglePageVisible] = React.useReducer(
178
- (visible) => !visible,
179
- true,
180
- )
181
-
182
- return (
183
- <div>
184
- <button
185
- type="button"
186
- aria-label="Toggle page visibility"
187
- onClick={togglePageVisible}
188
- >
189
- Toggle Page
190
- </button>
191
- {isPageVisible && <Page />}
192
- </div>
193
- )
194
- }
195
-
196
- renderWithClient(queryClient, <PageParent />)
197
-
198
- fireEvent.click(
199
- screen.getByRole('button', { name: /open react query devtools/i }),
200
- )
201
-
202
- const currentQuery = queryCache.find({ queryKey: ['check'] })
203
-
204
- // When the query is fetching then expect number of
205
- // fetching queries to be 1
206
- expect(currentQuery?.state.fetchStatus).toEqual('fetching')
207
- await screen.findByText(
208
- getByTextContent(
209
- 'fresh (0) fetching (1) paused (0) stale (0) inactive (0)',
210
- ),
211
- )
212
-
213
- // When we are done fetching the query doesn't go stale
214
- // until 300ms after, so expect the number of fresh
215
- // queries to be 1
216
- await waitFor(() => {
217
- expect(currentQuery?.state.fetchStatus).toEqual('idle')
218
- })
219
- await screen.findByText(
220
- getByTextContent(
221
- 'fresh (1) fetching (0) paused (0) stale (0) inactive (0)',
222
- ),
223
- )
224
-
225
- // Then wait for the query to go stale and then
226
- // expect the number of stale queries to be 1
227
- await waitFor(() => {
228
- expect(currentQuery?.isStale()).toEqual(false)
229
- })
230
- await screen.findByText(
231
- getByTextContent(
232
- 'fresh (0) fetching (0) paused (0) stale (1) inactive (0)',
233
- ),
234
- )
235
-
236
- // Unmount the page component thus making the query inactive
237
- // and expect number of inactive queries to be 1
238
- fireEvent.click(
239
- screen.getByRole('button', { name: /toggle page visibility/i }),
240
- )
241
- await screen.findByText(
242
- getByTextContent(
243
- 'fresh (0) fetching (0) paused (0) stale (0) inactive (1)',
244
- ),
245
- )
246
- })
247
-
248
- it('should display the query hash and open the query details', async () => {
249
- const { queryClient, queryCache } = createQueryClient()
250
-
251
- function Page() {
252
- const { data = 'default' } = useQuery({
253
- queryKey: ['check'],
254
- queryFn: async () => {
255
- await sleep(10)
256
- return 'test'
257
- },
258
- })
259
-
260
- return (
261
- <div>
262
- <h1>{data}</h1>
263
- </div>
264
- )
265
- }
266
-
267
- renderWithClient(queryClient, <Page />)
268
-
269
- fireEvent.click(
270
- screen.getByRole('button', { name: /open react query devtools/i }),
271
- )
272
-
273
- const currentQuery = queryCache.find({ queryKey: ['check'] })
274
-
275
- await screen.findByText(getByTextContent(`1${currentQuery?.queryHash}`))
276
-
277
- const queryButton = await screen.findByRole('button', {
278
- name: `Open query details for ${currentQuery?.queryHash}`,
279
- })
280
-
281
- fireEvent.click(queryButton)
282
-
283
- await screen.findByText(/query details/i)
284
- })
285
-
286
- it('should filter the queries via the query hash', async () => {
287
- const { queryClient, queryCache } = createQueryClient()
288
-
289
- function Page() {
290
- const fooResult = useQuery({
291
- queryKey: ['foo'],
292
- queryFn: async () => {
293
- await sleep(10)
294
- return 'foo-result'
295
- },
296
- })
297
-
298
- const barResult = useQuery({
299
- queryKey: ['bar'],
300
- queryFn: async () => {
301
- await sleep(10)
302
- return 'bar-result'
303
- },
304
- })
305
-
306
- const bazResult = useQuery({
307
- queryKey: ['baz'],
308
- queryFn: async () => {
309
- await sleep(10)
310
- return 'baz-result'
311
- },
312
- })
313
-
314
- return (
315
- <div>
316
- <h1>
317
- {barResult.data} {fooResult.data} {bazResult.data}
318
- </h1>
319
- </div>
320
- )
321
- }
322
-
323
- renderWithClient(queryClient, <Page />)
324
-
325
- fireEvent.click(
326
- screen.getByRole('button', { name: /open react query devtools/i }),
327
- )
328
-
329
- const fooQueryHash =
330
- queryCache.find({ queryKey: ['foo'] })?.queryHash ?? 'invalid hash'
331
- const barQueryHash =
332
- queryCache.find({ queryKey: ['bar'] })?.queryHash ?? 'invalid hash'
333
- const bazQueryHash =
334
- queryCache.find({ queryKey: ['baz'] })?.queryHash ?? 'invalid hash'
335
-
336
- await screen.findByText(fooQueryHash)
337
- screen.getByText(barQueryHash)
338
- screen.getByText(bazQueryHash)
339
-
340
- const filterInput = screen.getByLabelText(/filter by queryhash/i)
341
- fireEvent.change(filterInput, { target: { value: 'fo' } })
342
-
343
- await screen.findByText(fooQueryHash)
344
- const barItem = screen.queryByText(barQueryHash)
345
- const bazItem = screen.queryByText(bazQueryHash)
346
- expect(barItem).toBeNull()
347
- expect(bazItem).toBeNull()
348
-
349
- fireEvent.change(filterInput, { target: { value: '' } })
350
- })
351
-
352
- it('should show a disabled label if all observers are disabled', async () => {
353
- const { queryClient } = createQueryClient()
354
-
355
- function Page() {
356
- const [enabled, setEnabled] = React.useState(false)
357
- const { data } = useQuery({
358
- queryKey: ['key'],
359
- queryFn: async () => {
360
- await sleep(10)
361
- return 'test'
362
- },
363
- enabled,
364
- })
365
-
366
- return (
367
- <div>
368
- <h1>{data}</h1>
369
- <button onClick={() => setEnabled(true)}>Enable Query</button>
370
- </div>
371
- )
372
- }
373
-
374
- renderWithClient(queryClient, <Page />, { initialIsOpen: true })
375
-
376
- await screen.findByText(/disabled/i)
377
-
378
- fireEvent.click(screen.getByRole('button', { name: /enable query/i }))
379
-
380
- await waitFor(() => {
381
- expect(screen.queryByText(/disabled/i)).not.toBeInTheDocument()
382
- })
383
- })
384
-
385
- it('should not show a disabled label for inactive queries', async () => {
386
- const { queryClient } = createQueryClient()
387
-
388
- function Page() {
389
- const { data } = useQuery({
390
- queryKey: ['key'],
391
- queryFn: () => Promise.resolve('test'),
392
- enabled: false,
393
- })
394
-
395
- return (
396
- <div>
397
- <h1>{data}</h1>
398
- </div>
399
- )
400
- }
401
-
402
- function App() {
403
- const [visible, setVisible] = React.useState(true)
404
-
405
- return (
406
- <div>
407
- {visible ? <Page /> : null}
408
- <button onClick={() => setVisible(false)}>Hide Query</button>
409
- </div>
410
- )
411
- }
412
-
413
- renderWithClient(queryClient, <App />, { initialIsOpen: true })
414
-
415
- await screen.findByText(/disabled/i)
416
-
417
- fireEvent.click(screen.getByRole('button', { name: /hide query/i }))
418
-
419
- await waitFor(() => {
420
- expect(screen.queryByText(/disabled/i)).not.toBeInTheDocument()
421
- })
422
- })
423
-
424
- it('should simulate offline mode', async () => {
425
- const { queryClient } = createQueryClient()
426
- let count = 0
427
-
428
- function App() {
429
- const { data, fetchStatus } = useQuery({
430
- queryKey: ['key'],
431
- queryFn: () => {
432
- count++
433
- return Promise.resolve('test')
434
- },
435
- })
436
-
437
- return (
438
- <div>
439
- <h1>
440
- {data}, {fetchStatus}
441
- </h1>
442
- </div>
443
- )
444
- }
445
-
446
- renderWithClient(queryClient, <App />, {
447
- initialIsOpen: true,
448
- })
449
-
450
- await screen.findByRole('heading', { name: /test/i })
451
-
452
- fireEvent.click(
453
- screen.getByRole('button', { name: /mock offline behavior/i }),
454
- )
455
-
456
- const queryButton = await screen.findByRole('button', {
457
- name: 'Open query details for ["key"]',
458
- })
459
- fireEvent.click(queryButton)
460
-
461
- const refetchButton = await screen.findByRole('button', {
462
- name: /refetch/i,
463
- })
464
- fireEvent.click(refetchButton)
465
-
466
- await waitFor(() => {
467
- expect(screen.getByText('test, paused')).toBeInTheDocument()
468
- })
469
-
470
- fireEvent.click(
471
- screen.getByRole('button', { name: /restore offline mock/i }),
472
- )
473
-
474
- await waitFor(() => {
475
- expect(screen.getByText('test, idle')).toBeInTheDocument()
476
- })
477
-
478
- expect(count).toBe(2)
479
- })
480
-
481
- it('should inform onlineManager when offline mode is simulated', () => {
482
- const { queryClient } = createQueryClient()
483
- const online: Array<boolean> = []
484
-
485
- const unsubscribe = onlineManager.subscribe(() => {
486
- online.push(onlineManager.isOnline())
487
- })
488
-
489
- renderWithClient(queryClient, <div />, {
490
- initialIsOpen: true,
491
- })
492
-
493
- fireEvent.click(
494
- screen.getByRole('button', { name: /mock offline behavior/i }),
495
- )
496
-
497
- fireEvent.click(
498
- screen.getByRole('button', { name: /restore offline mock/i }),
499
- )
500
-
501
- expect(online).toStrictEqual([false, true])
502
-
503
- unsubscribe()
504
- })
505
-
506
- it('should sort the queries according to the sorting filter', async () => {
507
- const { queryClient, queryCache } = createQueryClient()
508
-
509
- function Page() {
510
- const query1Result = useQuery({
511
- queryKey: ['query-1'],
512
- queryFn: async () => {
513
- await sleep(20)
514
- return 'query-1-result'
515
- },
516
- })
517
-
518
- const query3Result = useQuery({
519
- queryKey: ['query-3'],
520
- queryFn: async () => {
521
- await sleep(10)
522
- return 'query-3-result'
523
- },
524
- staleTime: Infinity,
525
- enabled: typeof query1Result.data === 'string',
526
- })
527
-
528
- const query2Result = useQuery({
529
- queryKey: ['query-2'],
530
- queryFn: async () => {
531
- await sleep(10)
532
- return 'query-2-result'
533
- },
534
-
535
- enabled: typeof query3Result.data === 'string',
536
- })
537
-
538
- return (
539
- <div>
540
- <h1>
541
- {query1Result.data} {query2Result.data} {query3Result.data}
542
- </h1>
543
- </div>
544
- )
545
- }
546
-
547
- renderWithClient(queryClient, <Page />)
548
-
549
- fireEvent.click(
550
- screen.getByRole('button', { name: /open react query devtools/i }),
551
- )
552
-
553
- const query1Hash =
554
- queryCache.find({ queryKey: ['query-1'] })?.queryHash ?? 'invalid hash'
555
- const query2Hash =
556
- queryCache.find({ queryKey: ['query-2'] })?.queryHash ?? 'invalid hash'
557
- const query3Hash =
558
- queryCache.find({ queryKey: ['query-3'] })?.queryHash ?? 'invalid hash'
559
-
560
- const sortSelect = screen.getByLabelText(/sort queries/i)
561
- let queries = []
562
-
563
- // When sorted by query hash the queries get sorted according
564
- // to just the number, with the order being -> query-1, query-2, query-3
565
- fireEvent.change(sortSelect, { target: { value: 'Query Hash' } })
566
-
567
- /** To check the order of the queries we can use regex to find
568
- * all the row items in an array and then compare the items
569
- * one by one in the order we expect it
570
- * @reference https://github.com/testing-library/react-testing-library/issues/313#issuecomment-625294327
571
- */
572
- queries = await screen.findAllByText(/\["query-[1-3]"\]/)
573
- expect(queries[0]?.textContent).toEqual(query1Hash)
574
- expect(queries[1]?.textContent).toEqual(query2Hash)
575
- expect(queries[2]?.textContent).toEqual(query3Hash)
576
-
577
- // Wait for the queries to be resolved
578
- await screen.findByText(/query-1-result query-2-result query-3-result/i)
579
-
580
- // When sorted by the last updated date the queries are sorted by the time
581
- // they were updated and since the query-2 takes longest time to complete
582
- // and query-1 the shortest, so the order is -> query-2, query-3, query-1
583
- fireEvent.change(sortSelect, { target: { value: 'Last Updated' } })
584
-
585
- queries = await screen.findAllByText(/\["query-[1-3]"\]/)
586
- expect(queries[0]?.textContent).toEqual(query2Hash)
587
- expect(queries[1]?.textContent).toEqual(query3Hash)
588
- expect(queries[2]?.textContent).toEqual(query1Hash)
589
-
590
- // When sorted by the status and then last updated date the queries
591
- // query-3 takes precedence because its stale time being infinity, it
592
- // always remains fresh, the rest of the queries are sorted by their last
593
- // updated time, so the resulting order is -> query-3, query-2, query-1
594
- fireEvent.change(sortSelect, {
595
- target: { value: 'Status > Last Updated' },
596
- })
597
-
598
- queries = await screen.findAllByText(/\["query-[1-3]"\]/)
599
- expect(queries[0]?.textContent).toEqual(query3Hash)
600
- expect(queries[1]?.textContent).toEqual(query2Hash)
601
- expect(queries[2]?.textContent).toEqual(query1Hash)
602
-
603
- // Switch the order form ascending to descending and expect the
604
- // query order to be reversed from previous state
605
- fireEvent.click(screen.getByRole('button', { name: /⬆ asc/i }))
606
-
607
- queries = await screen.findAllByText(/\["query-[1-3]"\]/)
608
- expect(queries[0]?.textContent).toEqual(query1Hash)
609
- expect(queries[1]?.textContent).toEqual(query2Hash)
610
- expect(queries[2]?.textContent).toEqual(query3Hash)
611
- })
612
-
613
- it('should initialize filtering and sorting values with defaults when they are not stored in localstorage', () => {
614
- localStorage.removeItem('reactQueryDevtoolsBaseSort')
615
- localStorage.removeItem('reactQueryDevtoolsSortFn')
616
- localStorage.removeItem('reactQueryDevtoolsFilter')
617
-
618
- const { queryClient } = createQueryClient()
619
-
620
- function Page() {
621
- const { data = 'default' } = useQuery({
622
- queryKey: ['check'],
623
- queryFn: async () => {
624
- await sleep(10)
625
- return 'test'
626
- },
627
- })
628
-
629
- return (
630
- <div>
631
- <h1>{data}</h1>
632
- </div>
633
- )
634
- }
635
-
636
- renderWithClient(queryClient, <Page />, {
637
- initialIsOpen: true,
638
- })
639
-
640
- const filterInput: HTMLInputElement =
641
- screen.getByLabelText(/Filter by queryhash/i)
642
- expect(filterInput.value).toEqual('')
643
-
644
- const sortCombobox: HTMLSelectElement =
645
- screen.getByLabelText(/Sort queries/i)
646
- expect(sortCombobox.value).toEqual(Object.keys(sortFns)[0])
647
-
648
- expect(screen.getByRole('button', { name: /Asc/i })).toBeInTheDocument()
649
-
650
- const detailsPanel = screen.queryByText(/Query Details/i)
651
- expect(detailsPanel).not.toBeInTheDocument()
652
- })
653
-
654
- it('should initialize sorting values with ones stored in localstorage', async () => {
655
- localStorage.setItem('reactQueryDevtoolsBaseSort', 'true')
656
- localStorage.setItem(
657
- 'reactQueryDevtoolsSortFn',
658
- JSON.stringify(Object.keys(sortFns)[1]),
659
- )
660
-
661
- const { queryClient } = createQueryClient()
662
-
663
- function Page() {
664
- const { data = 'default' } = useQuery({
665
- queryKey: ['check'],
666
- queryFn: async () => {
667
- await sleep(10)
668
- return 'test'
669
- },
670
- })
671
-
672
- return (
673
- <div>
674
- <h1>{data}</h1>
675
- </div>
676
- )
677
- }
678
-
679
- renderWithClient(queryClient, <Page />, {
680
- initialIsOpen: true,
681
- })
682
-
683
- const sortCombobox: HTMLSelectElement =
684
- screen.getByLabelText(/Sort queries/i)
685
- expect(sortCombobox.value).toEqual(Object.keys(sortFns)[1])
686
-
687
- expect(screen.getByRole('button', { name: /Desc/i })).toBeInTheDocument()
688
- })
689
-
690
- it('should initialize filter value with one stored in localstorage', () => {
691
- localStorage.setItem('reactQueryDevtoolsFilter', JSON.stringify('posts'))
692
-
693
- const { queryClient } = createQueryClient()
694
-
695
- function Page() {
696
- const { data = 'default' } = useQuery({
697
- queryKey: ['check'],
698
- queryFn: async () => {
699
- await sleep(10)
700
- return 'test'
701
- },
702
- })
703
-
704
- return (
705
- <div>
706
- <h1>{data}</h1>
707
- </div>
708
- )
709
- }
710
-
711
- renderWithClient(queryClient, <Page />, {
712
- initialIsOpen: true,
713
- })
714
-
715
- const filterInput: HTMLInputElement =
716
- screen.getByLabelText(/Filter by queryhash/i)
717
- expect(filterInput.value).toEqual('posts')
718
- })
719
-
720
- it('should not show queries after clear', async () => {
721
- const { queryClient, queryCache } = createQueryClient()
722
-
723
- function Page() {
724
- const query1Result = useQuery({
725
- queryKey: ['query-1'],
726
- queryFn: async () => {
727
- return 'query-1-result'
728
- },
729
- })
730
- const query2Result = useQuery({
731
- queryKey: ['query-2'],
732
- queryFn: async () => {
733
- return 'query-2-result'
734
- },
735
- })
736
- const query3Result = useQuery({
737
- queryKey: ['query-3'],
738
- queryFn: async () => {
739
- return 'query-3-result'
740
- },
741
- })
742
-
743
- return (
744
- <div>
745
- <h1>
746
- {query1Result.data} {query2Result.data} {query3Result.data}{' '}
747
- </h1>
748
- </div>
749
- )
750
- }
751
-
752
- renderWithClient(queryClient, <Page />)
753
-
754
- fireEvent.click(
755
- screen.getByRole('button', { name: /open react query devtools/i }),
756
- )
757
-
758
- expect(queryCache.getAll()).toHaveLength(3)
759
-
760
- const clearButton = screen.getByLabelText(/clear/i)
761
- fireEvent.click(clearButton)
762
-
763
- expect(queryCache.getAll()).toHaveLength(0)
764
- })
765
-
766
- it('style should have a nonce', async () => {
767
- const { queryClient } = createQueryClient()
768
-
769
- function Page() {
770
- return <div></div>
771
- }
772
-
773
- const { container } = renderWithClient(queryClient, <Page />, {
774
- styleNonce: 'test-nonce',
775
- initialIsOpen: false,
776
- })
777
- const styleTag = container.querySelector('style')
778
- expect(styleTag).toHaveAttribute('nonce', 'test-nonce')
779
-
780
- await screen.findByRole('button', { name: /react query devtools/i })
781
- })
782
-
783
- it('should render a menu to select panel position', async () => {
784
- const { queryClient } = createQueryClient()
785
-
786
- function Page() {
787
- const { data = 'default' } = useQuery({
788
- queryKey: ['check'],
789
- queryFn: async () => 'test',
790
- })
791
-
792
- return (
793
- <div>
794
- <h1>{data}</h1>
795
- </div>
796
- )
797
- }
798
-
799
- renderWithClient(queryClient, <Page />, {
800
- initialIsOpen: true,
801
- })
802
-
803
- const positionSelect: HTMLSelectElement = await screen.findByLabelText(
804
- 'Panel position',
805
- )
806
-
807
- expect(positionSelect.value).toBe('bottom')
808
- })
809
-
810
- it(`should render the panel to the left if panelPosition is set to 'left'`, async () => {
811
- const { queryClient } = createQueryClient()
812
-
813
- function Page() {
814
- const { data = 'default' } = useQuery({
815
- queryKey: ['check'],
816
- queryFn: async () => 'test',
817
- })
818
-
819
- return (
820
- <div>
821
- <h1>{data}</h1>
822
- </div>
823
- )
824
- }
825
-
826
- renderWithClient(queryClient, <Page />, {
827
- initialIsOpen: true,
828
- panelPosition: 'left',
829
- })
830
-
831
- const positionSelect: HTMLSelectElement = await screen.findByLabelText(
832
- 'Panel position',
833
- )
834
-
835
- expect(positionSelect.value).toBe('left')
836
-
837
- const panel = (await screen.getByLabelText(
838
- 'React Query Devtools Panel',
839
- )) as HTMLDivElement
840
-
841
- expect(panel.style.left).toBe('0px')
842
- expect(panel.style.width).toBe('500px')
843
- expect(panel.style.height).toBe('100vh')
844
- })
845
-
846
- it('should change the panel position if user select different option from the menu', async () => {
847
- const { queryClient } = createQueryClient()
848
-
849
- function Page() {
850
- const { data = 'default' } = useQuery({
851
- queryKey: ['check'],
852
- queryFn: async () => 'test',
853
- })
854
-
855
- return (
856
- <div>
857
- <h1>{data}</h1>
858
- </div>
859
- )
860
- }
861
-
862
- renderWithClient(queryClient, <Page />, {
863
- initialIsOpen: true,
864
- })
865
-
866
- const positionSelect: HTMLSelectElement = await screen.findByLabelText(
867
- 'Panel position',
868
- )
869
-
870
- expect(positionSelect.value).toBe('bottom')
871
-
872
- const panel = (await screen.getByLabelText(
873
- 'React Query Devtools Panel',
874
- )) as HTMLDivElement
875
-
876
- expect(panel.style.bottom).toBe('0px')
877
- expect(panel.style.height).toBe('500px')
878
- expect(panel.style.width).toBe('100%')
879
-
880
- await act(async () => {
881
- fireEvent.change(positionSelect, { target: { value: 'right' } })
882
- })
883
-
884
- expect(positionSelect.value).toBe('right')
885
-
886
- expect(panel.style.right).toBe('0px')
887
- expect(panel.style.width).toBe('500px')
888
- expect(panel.style.height).toBe('100vh')
889
- })
890
-
891
- it('should restore parent element padding after closing', async () => {
892
- const { queryClient } = createQueryClient()
893
-
894
- function Page() {
895
- const { data = 'default' } = useQuery({
896
- queryKey: ['check'],
897
- queryFn: async () => 'test',
898
- })
899
-
900
- return (
901
- <div>
902
- <h1>{data}</h1>
903
- </div>
904
- )
905
- }
906
-
907
- const parentElementTestid = 'parentElement'
908
- const parentPaddings = {
909
- paddingTop: '428px',
910
- paddingBottom: '39px',
911
- paddingLeft: '-373px',
912
- paddingRight: '20%',
913
- }
914
-
915
- function Parent({ children }: { children: React.ReactElement }) {
916
- return (
917
- <div data-testid={parentElementTestid} style={parentPaddings}>
918
- {children}
919
- </div>
920
- )
921
- }
922
-
923
- renderWithClient(
924
- queryClient,
925
- <Page />,
926
- {
927
- initialIsOpen: true,
928
- panelPosition: 'bottom',
929
- },
930
- { wrapper: Parent },
931
- )
932
-
933
- const parentElement = screen.getByTestId(parentElementTestid)
934
- expect(parentElement).toHaveStyle({
935
- paddingTop: '0px',
936
- paddingLeft: '0px',
937
- paddingRight: '0px',
938
- paddingBottom: defaultPanelSize,
939
- })
940
-
941
- fireEvent.click(screen.getByRole('button', { name: /^close$/i }))
942
- expect(parentElement).toHaveStyle(parentPaddings)
943
- })
944
-
945
- it('should simulate loading state', async () => {
946
- const { queryClient } = createQueryClient()
947
- let count = 0
948
- function App() {
949
- const { data, fetchStatus } = useQuery({
950
- queryKey: ['key'],
951
- queryFn: () => {
952
- count++
953
- return Promise.resolve('test')
954
- },
955
- })
956
-
957
- return (
958
- <div>
959
- <h1>
960
- {data ?? 'No data'}, {fetchStatus}
961
- </h1>
962
- </div>
963
- )
964
- }
965
-
966
- renderWithClient(queryClient, <App />, {
967
- initialIsOpen: true,
968
- })
969
-
970
- await screen.findByRole('heading', { name: /test/i })
971
-
972
- const loadingButton = await screen.findByRole('button', {
973
- name: 'Trigger loading',
974
- })
975
- fireEvent.click(loadingButton)
976
-
977
- await waitFor(() => {
978
- expect(screen.getByText('Restore loading')).toBeInTheDocument()
979
- })
980
-
981
- await waitFor(() => {
982
- expect(screen.getByText('No data, fetching')).toBeInTheDocument()
983
- })
984
-
985
- fireEvent.click(screen.getByRole('button', { name: /restore loading/i }))
986
-
987
- await waitFor(() => {
988
- expect(screen.getByText('test, idle')).toBeInTheDocument()
989
- })
990
-
991
- expect(count).toBe(2)
992
- })
993
-
994
- it('should simulate error state', async () => {
995
- const { queryClient } = createQueryClient()
996
- function App() {
997
- const { status, error } = useQuery({
998
- queryKey: ['key'],
999
- queryFn: () => {
1000
- return Promise.resolve('test')
1001
- },
1002
- })
1003
-
1004
- return (
1005
- <div>
1006
- <h1>
1007
- {!!error ? 'Some error' : 'No error'}, {status}
1008
- </h1>
1009
- </div>
1010
- )
1011
- }
1012
-
1013
- renderWithClient(queryClient, <App />, {
1014
- initialIsOpen: true,
1015
- })
1016
-
1017
- const errorButton = await screen.findByRole('button', {
1018
- name: 'Trigger error',
1019
- })
1020
- fireEvent.click(errorButton)
1021
-
1022
- await waitFor(() => {
1023
- expect(screen.getByText('Restore error')).toBeInTheDocument()
1024
- })
1025
-
1026
- await waitFor(() => {
1027
- expect(screen.getByText('Some error, error')).toBeInTheDocument()
1028
- })
1029
-
1030
- fireEvent.click(screen.getByRole('button', { name: /Restore error/i }))
1031
-
1032
- await waitFor(() => {
1033
- expect(screen.getByText('No error, success')).toBeInTheDocument()
1034
- })
1035
- })
1036
-
1037
- it('should can simulate a specific error', async () => {
1038
- const { queryClient } = createQueryClient()
1039
-
1040
- function App() {
1041
- const { status, error } = useQuery({
1042
- queryKey: ['key'],
1043
- queryFn: () => {
1044
- return Promise.resolve('test')
1045
- },
1046
- })
1047
-
1048
- return (
1049
- <div data-testid="test">
1050
- <h1>
1051
- {error instanceof CustomError
1052
- ? error.message.toString()
1053
- : 'No error'}
1054
- , {status}
1055
- </h1>
1056
- </div>
1057
- )
1058
- }
1059
-
1060
- renderWithClient(queryClient, <App />, {
1061
- initialIsOpen: true,
1062
- errorTypes: [
1063
- {
1064
- name: 'error1',
1065
- initializer: () => new CustomError('error1'),
1066
- },
1067
- ],
1068
- })
1069
-
1070
- const errorOption = await screen.findByLabelText('Trigger error:')
1071
-
1072
- UserEvent.selectOptions(errorOption, 'error1')
1073
-
1074
- await waitFor(() => {
1075
- expect(screen.getByText('error1, error')).toBeInTheDocument()
1076
- })
1077
-
1078
- fireEvent.click(screen.getByRole('button', { name: /Restore error/i }))
1079
-
1080
- await waitFor(() => {
1081
- expect(screen.getByText('No error, success')).toBeInTheDocument()
1082
- })
1083
- })
1084
-
1085
- it('should not refetch when already restoring a query', async () => {
1086
- const { queryClient } = createQueryClient()
1087
-
1088
- let count = 0
1089
- let resolvePromise: (value: unknown) => void = () => undefined
1090
-
1091
- function App() {
1092
- const { data } = useQuery({
1093
- queryKey: ['key'],
1094
- queryFn: () => {
1095
- count++
1096
-
1097
- // Resolve the promise immediately when
1098
- // the query is fetched for the first time
1099
- if (count === 1) {
1100
- return Promise.resolve('test')
1101
- }
1102
-
1103
- return new Promise((resolve) => {
1104
- // Do not resolve immediately and store the
1105
- // resolve function to resolve the promise later
1106
- resolvePromise = resolve
1107
- })
1108
- },
1109
- })
1110
-
1111
- return (
1112
- <div>
1113
- <h1>{typeof data === 'string' ? data : 'No data'}</h1>
1114
- </div>
1115
- )
1116
- }
1117
-
1118
- renderWithClient(queryClient, <App />, {
1119
- initialIsOpen: true,
1120
- })
1121
-
1122
- const loadingButton = await screen.findByRole('button', {
1123
- name: 'Trigger loading',
1124
- })
1125
- fireEvent.click(loadingButton)
1126
-
1127
- await waitFor(() => {
1128
- expect(screen.getByText('Restore loading')).toBeInTheDocument()
1129
- })
1130
-
1131
- // Click the restore loading button twice and only resolve query promise
1132
- // after the second click.
1133
- fireEvent.click(screen.getByRole('button', { name: /restore loading/i }))
1134
- fireEvent.click(screen.getByRole('button', { name: /restore loading/i }))
1135
- resolvePromise('test')
1136
-
1137
- expect(count).toBe(2)
3
+ expect(1).toBe(1)
1138
4
  })
1139
5
  })