@tanstack/react-query-devtools 5.0.0-alpha.9 → 5.0.0-alpha.91

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 (145) hide show
  1. package/build/legacy/devtools-d8b99e07.d.ts +42 -0
  2. package/build/legacy/devtools.cjs +91 -0
  3. package/build/legacy/devtools.cjs.map +1 -0
  4. package/build/legacy/devtools.d.cts +4 -0
  5. package/build/legacy/devtools.d.ts +4 -0
  6. package/build/legacy/devtools.js +57 -0
  7. package/build/legacy/devtools.js.map +1 -0
  8. package/build/legacy/index.cjs +45 -0
  9. package/build/legacy/index.cjs.map +1 -0
  10. package/build/legacy/index.d.cts +8 -0
  11. package/build/legacy/index.d.ts +8 -0
  12. package/build/legacy/index.js +11 -0
  13. package/build/legacy/index.js.map +1 -0
  14. package/build/legacy/production.cjs +43 -0
  15. package/build/legacy/production.cjs.map +1 -0
  16. package/build/legacy/production.d.cts +8 -0
  17. package/build/legacy/production.d.ts +8 -0
  18. package/build/legacy/production.js +9 -0
  19. package/build/legacy/production.js.map +1 -0
  20. package/build/modern/devtools-d8b99e07.d.ts +42 -0
  21. package/build/modern/devtools.cjs +91 -0
  22. package/build/modern/devtools.cjs.map +1 -0
  23. package/build/modern/devtools.d.cts +4 -0
  24. package/build/modern/devtools.d.ts +4 -0
  25. package/build/modern/devtools.js +57 -0
  26. package/build/modern/devtools.js.map +1 -0
  27. package/build/modern/index.cjs +45 -0
  28. package/build/modern/index.cjs.map +1 -0
  29. package/build/modern/index.d.cts +8 -0
  30. package/build/modern/index.d.ts +8 -0
  31. package/build/modern/index.js +11 -0
  32. package/build/modern/index.js.map +1 -0
  33. package/build/modern/production.cjs +43 -0
  34. package/build/modern/production.cjs.map +1 -0
  35. package/build/modern/production.d.cts +8 -0
  36. package/build/modern/production.d.ts +8 -0
  37. package/build/modern/production.js +9 -0
  38. package/build/modern/production.js.map +1 -0
  39. package/package.json +32 -27
  40. package/src/__tests__/devtools.test.tsx +1 -1009
  41. package/src/__tests__/utils.tsx +4 -4
  42. package/src/devtools.tsx +59 -1309
  43. package/src/index.ts +0 -7
  44. package/src/production.ts +5 -0
  45. package/build/lib/Explorer.d.ts +0 -50
  46. package/build/lib/Explorer.esm.js +0 -254
  47. package/build/lib/Explorer.esm.js.map +0 -1
  48. package/build/lib/Explorer.js +0 -288
  49. package/build/lib/Explorer.js.map +0 -1
  50. package/build/lib/Explorer.mjs +0 -254
  51. package/build/lib/Explorer.mjs.map +0 -1
  52. package/build/lib/Logo.d.ts +0 -1
  53. package/build/lib/Logo.esm.js +0 -32
  54. package/build/lib/Logo.esm.js.map +0 -1
  55. package/build/lib/Logo.js +0 -55
  56. package/build/lib/Logo.js.map +0 -1
  57. package/build/lib/Logo.mjs +0 -32
  58. package/build/lib/Logo.mjs.map +0 -1
  59. package/build/lib/__tests__/Explorer.test.d.ts +0 -1
  60. package/build/lib/__tests__/devtools.test.d.ts +0 -1
  61. package/build/lib/__tests__/utils.d.ts +0 -22
  62. package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js +0 -17
  63. package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js.map +0 -1
  64. package/build/lib/_virtual/_rollupPluginBabelHelpers.js +0 -19
  65. package/build/lib/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
  66. package/build/lib/_virtual/_rollupPluginBabelHelpers.mjs +0 -17
  67. package/build/lib/_virtual/_rollupPluginBabelHelpers.mjs.map +0 -1
  68. package/build/lib/devtools.d.ts +0 -113
  69. package/build/lib/devtools.esm.js +0 -900
  70. package/build/lib/devtools.esm.js.map +0 -1
  71. package/build/lib/devtools.js +0 -921
  72. package/build/lib/devtools.js.map +0 -1
  73. package/build/lib/devtools.mjs +0 -869
  74. package/build/lib/devtools.mjs.map +0 -1
  75. package/build/lib/index.d.ts +0 -3
  76. package/build/lib/index.esm.js +0 -12
  77. package/build/lib/index.esm.js.map +0 -1
  78. package/build/lib/index.js +0 -15
  79. package/build/lib/index.js.map +0 -1
  80. package/build/lib/index.mjs +0 -12
  81. package/build/lib/index.mjs.map +0 -1
  82. package/build/lib/index.prod.d.ts +0 -3
  83. package/build/lib/index.prod.esm.js +0 -1559
  84. package/build/lib/index.prod.esm.js.map +0 -1
  85. package/build/lib/index.prod.js +0 -1580
  86. package/build/lib/index.prod.js.map +0 -1
  87. package/build/lib/index.prod.mjs +0 -1528
  88. package/build/lib/index.prod.mjs.map +0 -1
  89. package/build/lib/noop.d.ts +0 -2
  90. package/build/lib/screenreader.d.ts +0 -3
  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 -8
  98. package/build/lib/styledComponents.esm.js +0 -95
  99. package/build/lib/styledComponents.esm.js.map +0 -1
  100. package/build/lib/styledComponents.js +0 -104
  101. package/build/lib/styledComponents.js.map +0 -1
  102. package/build/lib/styledComponents.mjs +0 -95
  103. package/build/lib/styledComponents.mjs.map +0 -1
  104. package/build/lib/theme.d.ts +0 -36
  105. package/build/lib/theme.esm.js +0 -33
  106. package/build/lib/theme.esm.js.map +0 -1
  107. package/build/lib/theme.js +0 -56
  108. package/build/lib/theme.js.map +0 -1
  109. package/build/lib/theme.mjs +0 -33
  110. package/build/lib/theme.mjs.map +0 -1
  111. package/build/lib/useLocalStorage.d.ts +0 -1
  112. package/build/lib/useLocalStorage.esm.js +0 -40
  113. package/build/lib/useLocalStorage.esm.js.map +0 -1
  114. package/build/lib/useLocalStorage.js +0 -63
  115. package/build/lib/useLocalStorage.js.map +0 -1
  116. package/build/lib/useLocalStorage.mjs +0 -40
  117. package/build/lib/useLocalStorage.mjs.map +0 -1
  118. package/build/lib/useMediaQuery.d.ts +0 -1
  119. package/build/lib/useMediaQuery.esm.js +0 -36
  120. package/build/lib/useMediaQuery.esm.js.map +0 -1
  121. package/build/lib/useMediaQuery.js +0 -59
  122. package/build/lib/useMediaQuery.js.map +0 -1
  123. package/build/lib/useMediaQuery.mjs +0 -36
  124. package/build/lib/useMediaQuery.mjs.map +0 -1
  125. package/build/lib/utils.d.ts +0 -79
  126. package/build/lib/utils.esm.js +0 -184
  127. package/build/lib/utils.esm.js.map +0 -1
  128. package/build/lib/utils.js +0 -218
  129. package/build/lib/utils.js.map +0 -1
  130. package/build/lib/utils.mjs +0 -184
  131. package/build/lib/utils.mjs.map +0 -1
  132. package/build/umd/index.development.js +0 -3195
  133. package/build/umd/index.development.js.map +0 -1
  134. package/build/umd/index.production.js +0 -2
  135. package/build/umd/index.production.js.map +0 -1
  136. package/src/Explorer.tsx +0 -385
  137. package/src/Logo.tsx +0 -32
  138. package/src/__tests__/Explorer.test.tsx +0 -150
  139. package/src/noop.ts +0 -7
  140. package/src/screenreader.tsx +0 -16
  141. package/src/styledComponents.ts +0 -110
  142. package/src/theme.tsx +0 -33
  143. package/src/useLocalStorage.ts +0 -52
  144. package/src/useMediaQuery.ts +0 -34
  145. package/src/utils.ts +0 -319
@@ -1,1013 +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 } 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 sort the queries according to the sorting filter', async () => {
482
- const { queryClient, queryCache } = createQueryClient()
483
-
484
- function Page() {
485
- const query1Result = useQuery({
486
- queryKey: ['query-1'],
487
- queryFn: async () => {
488
- await sleep(20)
489
- return 'query-1-result'
490
- },
491
- })
492
-
493
- const query3Result = useQuery({
494
- queryKey: ['query-3'],
495
- queryFn: async () => {
496
- await sleep(10)
497
- return 'query-3-result'
498
- },
499
- staleTime: Infinity,
500
- enabled: typeof query1Result.data === 'string',
501
- })
502
-
503
- const query2Result = useQuery({
504
- queryKey: ['query-2'],
505
- queryFn: async () => {
506
- await sleep(10)
507
- return 'query-2-result'
508
- },
509
-
510
- enabled: typeof query3Result.data === 'string',
511
- })
512
-
513
- return (
514
- <div>
515
- <h1>
516
- {query1Result.data} {query2Result.data} {query3Result.data}
517
- </h1>
518
- </div>
519
- )
520
- }
521
-
522
- renderWithClient(queryClient, <Page />)
523
-
524
- fireEvent.click(
525
- screen.getByRole('button', { name: /open react query devtools/i }),
526
- )
527
-
528
- const query1Hash =
529
- queryCache.find({ queryKey: ['query-1'] })?.queryHash ?? 'invalid hash'
530
- const query2Hash =
531
- queryCache.find({ queryKey: ['query-2'] })?.queryHash ?? 'invalid hash'
532
- const query3Hash =
533
- queryCache.find({ queryKey: ['query-3'] })?.queryHash ?? 'invalid hash'
534
-
535
- const sortSelect = screen.getByLabelText(/sort queries/i)
536
- let queries = []
537
-
538
- // When sorted by query hash the queries get sorted according
539
- // to just the number, with the order being -> query-1, query-2, query-3
540
- fireEvent.change(sortSelect, { target: { value: 'Query Hash' } })
541
-
542
- /** To check the order of the queries we can use regex to find
543
- * all the row items in an array and then compare the items
544
- * one by one in the order we expect it
545
- * @reference https://github.com/testing-library/react-testing-library/issues/313#issuecomment-625294327
546
- */
547
- queries = await screen.findAllByText(/\["query-[1-3]"\]/)
548
- expect(queries[0]?.textContent).toEqual(query1Hash)
549
- expect(queries[1]?.textContent).toEqual(query2Hash)
550
- expect(queries[2]?.textContent).toEqual(query3Hash)
551
-
552
- // Wait for the queries to be resolved
553
- await screen.findByText(/query-1-result query-2-result query-3-result/i)
554
-
555
- // When sorted by the last updated date the queries are sorted by the time
556
- // they were updated and since the query-2 takes longest time to complete
557
- // and query-1 the shortest, so the order is -> query-2, query-3, query-1
558
- fireEvent.change(sortSelect, { target: { value: 'Last Updated' } })
559
-
560
- queries = await screen.findAllByText(/\["query-[1-3]"\]/)
561
- expect(queries[0]?.textContent).toEqual(query2Hash)
562
- expect(queries[1]?.textContent).toEqual(query3Hash)
563
- expect(queries[2]?.textContent).toEqual(query1Hash)
564
-
565
- // When sorted by the status and then last updated date the queries
566
- // query-3 takes precedence because its stale time being infinity, it
567
- // always remains fresh, the rest of the queries are sorted by their last
568
- // updated time, so the resulting order is -> query-3, query-2, query-1
569
- fireEvent.change(sortSelect, {
570
- target: { value: 'Status > Last Updated' },
571
- })
572
-
573
- queries = await screen.findAllByText(/\["query-[1-3]"\]/)
574
- expect(queries[0]?.textContent).toEqual(query3Hash)
575
- expect(queries[1]?.textContent).toEqual(query2Hash)
576
- expect(queries[2]?.textContent).toEqual(query1Hash)
577
-
578
- // Switch the order form ascending to descending and expect the
579
- // query order to be reversed from previous state
580
- fireEvent.click(screen.getByRole('button', { name: /⬆ asc/i }))
581
-
582
- queries = await screen.findAllByText(/\["query-[1-3]"\]/)
583
- expect(queries[0]?.textContent).toEqual(query1Hash)
584
- expect(queries[1]?.textContent).toEqual(query2Hash)
585
- expect(queries[2]?.textContent).toEqual(query3Hash)
586
- })
587
-
588
- it('should initialize filtering and sorting values with defaults when they are not stored in localstorage', () => {
589
- localStorage.removeItem('reactQueryDevtoolsBaseSort')
590
- localStorage.removeItem('reactQueryDevtoolsSortFn')
591
- localStorage.removeItem('reactQueryDevtoolsFilter')
592
-
593
- const { queryClient } = createQueryClient()
594
-
595
- function Page() {
596
- const { data = 'default' } = useQuery({
597
- queryKey: ['check'],
598
- queryFn: async () => {
599
- await sleep(10)
600
- return 'test'
601
- },
602
- })
603
-
604
- return (
605
- <div>
606
- <h1>{data}</h1>
607
- </div>
608
- )
609
- }
610
-
611
- renderWithClient(queryClient, <Page />, {
612
- initialIsOpen: true,
613
- })
614
-
615
- const filterInput: HTMLInputElement =
616
- screen.getByLabelText(/Filter by queryhash/i)
617
- expect(filterInput.value).toEqual('')
618
-
619
- const sortCombobox: HTMLSelectElement =
620
- screen.getByLabelText(/Sort queries/i)
621
- expect(sortCombobox.value).toEqual(Object.keys(sortFns)[0])
622
-
623
- expect(screen.getByRole('button', { name: /Asc/i })).toBeInTheDocument()
624
-
625
- const detailsPanel = screen.queryByText(/Query Details/i)
626
- expect(detailsPanel).not.toBeInTheDocument()
627
- })
628
-
629
- it('should initialize sorting values with ones stored in localstorage', async () => {
630
- localStorage.setItem('reactQueryDevtoolsBaseSort', 'true')
631
- localStorage.setItem(
632
- 'reactQueryDevtoolsSortFn',
633
- JSON.stringify(Object.keys(sortFns)[1]),
634
- )
635
-
636
- const { queryClient } = createQueryClient()
637
-
638
- function Page() {
639
- const { data = 'default' } = useQuery({
640
- queryKey: ['check'],
641
- queryFn: async () => {
642
- await sleep(10)
643
- return 'test'
644
- },
645
- })
646
-
647
- return (
648
- <div>
649
- <h1>{data}</h1>
650
- </div>
651
- )
652
- }
653
-
654
- renderWithClient(queryClient, <Page />, {
655
- initialIsOpen: true,
656
- })
657
-
658
- const sortCombobox: HTMLSelectElement =
659
- screen.getByLabelText(/Sort queries/i)
660
- expect(sortCombobox.value).toEqual(Object.keys(sortFns)[1])
661
-
662
- expect(screen.getByRole('button', { name: /Desc/i })).toBeInTheDocument()
663
- })
664
-
665
- it('should initialize filter value with one stored in localstorage', () => {
666
- localStorage.setItem('reactQueryDevtoolsFilter', JSON.stringify('posts'))
667
-
668
- const { queryClient } = createQueryClient()
669
-
670
- function Page() {
671
- const { data = 'default' } = useQuery({
672
- queryKey: ['check'],
673
- queryFn: async () => {
674
- await sleep(10)
675
- return 'test'
676
- },
677
- })
678
-
679
- return (
680
- <div>
681
- <h1>{data}</h1>
682
- </div>
683
- )
684
- }
685
-
686
- renderWithClient(queryClient, <Page />, {
687
- initialIsOpen: true,
688
- })
689
-
690
- const filterInput: HTMLInputElement =
691
- screen.getByLabelText(/Filter by queryhash/i)
692
- expect(filterInput.value).toEqual('posts')
693
- })
694
-
695
- it('style should have a nonce', async () => {
696
- const { queryClient } = createQueryClient()
697
-
698
- function Page() {
699
- return <div></div>
700
- }
701
-
702
- const { container } = renderWithClient(queryClient, <Page />, {
703
- styleNonce: 'test-nonce',
704
- initialIsOpen: false,
705
- })
706
- const styleTag = container.querySelector('style')
707
- expect(styleTag).toHaveAttribute('nonce', 'test-nonce')
708
-
709
- await screen.findByRole('button', { name: /react query devtools/i })
710
- })
711
-
712
- it('should render a menu to select panel position', async () => {
713
- const { queryClient } = createQueryClient()
714
-
715
- function Page() {
716
- const { data = 'default' } = useQuery({
717
- queryKey: ['check'],
718
- queryFn: async () => 'test',
719
- })
720
-
721
- return (
722
- <div>
723
- <h1>{data}</h1>
724
- </div>
725
- )
726
- }
727
-
728
- renderWithClient(queryClient, <Page />, {
729
- initialIsOpen: true,
730
- })
731
-
732
- const positionSelect: HTMLSelectElement = await screen.findByLabelText(
733
- 'Panel position',
734
- )
735
-
736
- expect(positionSelect.value).toBe('bottom')
737
- })
738
-
739
- it(`should render the panel to the left if panelPosition is set to 'left'`, async () => {
740
- const { queryClient } = createQueryClient()
741
-
742
- function Page() {
743
- const { data = 'default' } = useQuery({
744
- queryKey: ['check'],
745
- queryFn: async () => 'test',
746
- })
747
-
748
- return (
749
- <div>
750
- <h1>{data}</h1>
751
- </div>
752
- )
753
- }
754
-
755
- renderWithClient(queryClient, <Page />, {
756
- initialIsOpen: true,
757
- panelPosition: 'left',
758
- })
759
-
760
- const positionSelect: HTMLSelectElement = await screen.findByLabelText(
761
- 'Panel position',
762
- )
763
-
764
- expect(positionSelect.value).toBe('left')
765
-
766
- const panel = (await screen.getByLabelText(
767
- 'React Query Devtools Panel',
768
- )) as HTMLDivElement
769
-
770
- expect(panel.style.left).toBe('0px')
771
- expect(panel.style.width).toBe('500px')
772
- expect(panel.style.height).toBe('100vh')
773
- })
774
-
775
- it('should change the panel position if user select different option from the menu', async () => {
776
- const { queryClient } = createQueryClient()
777
-
778
- function Page() {
779
- const { data = 'default' } = useQuery({
780
- queryKey: ['check'],
781
- queryFn: async () => 'test',
782
- })
783
-
784
- return (
785
- <div>
786
- <h1>{data}</h1>
787
- </div>
788
- )
789
- }
790
-
791
- renderWithClient(queryClient, <Page />, {
792
- initialIsOpen: true,
793
- })
794
-
795
- const positionSelect: HTMLSelectElement = await screen.findByLabelText(
796
- 'Panel position',
797
- )
798
-
799
- expect(positionSelect.value).toBe('bottom')
800
-
801
- const panel = (await screen.getByLabelText(
802
- 'React Query Devtools Panel',
803
- )) as HTMLDivElement
804
-
805
- expect(panel.style.bottom).toBe('0px')
806
- expect(panel.style.height).toBe('500px')
807
- expect(panel.style.width).toBe('100%')
808
-
809
- await act(async () => {
810
- fireEvent.change(positionSelect, { target: { value: 'right' } })
811
- })
812
-
813
- expect(positionSelect.value).toBe('right')
814
-
815
- expect(panel.style.right).toBe('0px')
816
- expect(panel.style.width).toBe('500px')
817
- expect(panel.style.height).toBe('100vh')
818
- })
819
-
820
- it('should restore parent element padding after closing', async () => {
821
- const { queryClient } = createQueryClient()
822
-
823
- function Page() {
824
- const { data = 'default' } = useQuery({
825
- queryKey: ['check'],
826
- queryFn: async () => 'test',
827
- })
828
-
829
- return (
830
- <div>
831
- <h1>{data}</h1>
832
- </div>
833
- )
834
- }
835
-
836
- const parentElementTestid = 'parentElement'
837
- const parentPaddings = {
838
- paddingTop: '428px',
839
- paddingBottom: '39px',
840
- paddingLeft: '-373px',
841
- paddingRight: '20%',
842
- }
843
-
844
- function Parent({ children }: { children: React.ReactElement }) {
845
- return (
846
- <div data-testid={parentElementTestid} style={parentPaddings}>
847
- {children}
848
- </div>
849
- )
850
- }
851
-
852
- renderWithClient(
853
- queryClient,
854
- <Page />,
855
- {
856
- initialIsOpen: true,
857
- panelPosition: 'bottom',
858
- },
859
- { wrapper: Parent },
860
- )
861
-
862
- const parentElement = screen.getByTestId(parentElementTestid)
863
- expect(parentElement).toHaveStyle({
864
- paddingTop: '0px',
865
- paddingLeft: '0px',
866
- paddingRight: '0px',
867
- paddingBottom: defaultPanelSize,
868
- })
869
-
870
- fireEvent.click(screen.getByRole('button', { name: /^close$/i }))
871
- expect(parentElement).toHaveStyle(parentPaddings)
872
- })
873
-
874
- it('should simulate loading state', async () => {
875
- const { queryClient } = createQueryClient()
876
- let count = 0
877
- function App() {
878
- const { data, fetchStatus } = useQuery({
879
- queryKey: ['key'],
880
- queryFn: () => {
881
- count++
882
- return Promise.resolve('test')
883
- },
884
- })
885
-
886
- return (
887
- <div>
888
- <h1>
889
- {data ?? 'No data'}, {fetchStatus}
890
- </h1>
891
- </div>
892
- )
893
- }
894
-
895
- renderWithClient(queryClient, <App />, {
896
- initialIsOpen: true,
897
- })
898
-
899
- await screen.findByRole('heading', { name: /test/i })
900
-
901
- const loadingButton = await screen.findByRole('button', {
902
- name: 'Trigger loading',
903
- })
904
- fireEvent.click(loadingButton)
905
-
906
- await waitFor(() => {
907
- expect(screen.getByText('Restore loading')).toBeInTheDocument()
908
- })
909
-
910
- await waitFor(() => {
911
- expect(screen.getByText('No data, fetching')).toBeInTheDocument()
912
- })
913
-
914
- fireEvent.click(screen.getByRole('button', { name: /restore loading/i }))
915
-
916
- await waitFor(() => {
917
- expect(screen.getByText('test, idle')).toBeInTheDocument()
918
- })
919
-
920
- expect(count).toBe(2)
921
- })
922
-
923
- it('should simulate error state', async () => {
924
- const { queryClient } = createQueryClient()
925
- function App() {
926
- const { status, error } = useQuery({
927
- queryKey: ['key'],
928
- queryFn: () => {
929
- return Promise.resolve('test')
930
- },
931
- })
932
-
933
- return (
934
- <div>
935
- <h1>
936
- {!!error ? 'Some error' : 'No error'}, {status}
937
- </h1>
938
- </div>
939
- )
940
- }
941
-
942
- renderWithClient(queryClient, <App />, {
943
- initialIsOpen: true,
944
- })
945
-
946
- const errorButton = await screen.findByRole('button', {
947
- name: 'Trigger error',
948
- })
949
- fireEvent.click(errorButton)
950
-
951
- await waitFor(() => {
952
- expect(screen.getByText('Restore error')).toBeInTheDocument()
953
- })
954
-
955
- await waitFor(() => {
956
- expect(screen.getByText('Some error, error')).toBeInTheDocument()
957
- })
958
-
959
- fireEvent.click(screen.getByRole('button', { name: /Restore error/i }))
960
-
961
- await waitFor(() => {
962
- expect(screen.getByText('No error, success')).toBeInTheDocument()
963
- })
964
- })
965
-
966
- it('should can simulate a specific error', async () => {
967
- const { queryClient } = createQueryClient()
968
-
969
- function App() {
970
- const { status, error } = useQuery({
971
- queryKey: ['key'],
972
- queryFn: () => {
973
- return Promise.resolve('test')
974
- },
975
- })
976
-
977
- return (
978
- <div data-testid="test">
979
- <h1>
980
- {error instanceof CustomError
981
- ? error.message.toString()
982
- : 'No error'}
983
- , {status}
984
- </h1>
985
- </div>
986
- )
987
- }
988
-
989
- renderWithClient(queryClient, <App />, {
990
- initialIsOpen: true,
991
- errorTypes: [
992
- {
993
- name: 'error1',
994
- initializer: () => new CustomError('error1'),
995
- },
996
- ],
997
- })
998
-
999
- const errorOption = await screen.findByLabelText('Trigger error:')
1000
-
1001
- UserEvent.selectOptions(errorOption, 'error1')
1002
-
1003
- await waitFor(() => {
1004
- expect(screen.getByText('error1, error')).toBeInTheDocument()
1005
- })
1006
-
1007
- fireEvent.click(screen.getByRole('button', { name: /Restore error/i }))
1008
-
1009
- await waitFor(() => {
1010
- expect(screen.getByText('No error, success')).toBeInTheDocument()
1011
- })
3
+ expect(1).toBe(1)
1012
4
  })
1013
5
  })