Skip to content

Commit

Permalink
feat(react-query-devtools): enable setting loading/error via devtools (
Browse files Browse the repository at this point in the history
…#4352)

* feat(devtools): enable setting loading/error via devtools

* Some cleanup

* refactor: use flex-gap to align buttons

* refactor: fix linter and dropdown reset

* refactor: operate directly on activeQuery

* Change buttons to toggle states

* Sneak some queryState into meta

* Added test for error and loading

* Fix lint

* Fix prettier formatting

* chore: releases should run on alpha/beta as well

* chore: extract package validation to an extra script (#5039)

* chore: extract package validation to an extra script

and run it during CI

* chore: add missing `build:types` script to solid-query

* docs: update link for v2 docs (#5044)

* docs: update link for v2 docs

* Update README.md

---------

Co-authored-by: Dominik Dorfmeister <[email protected]>

* release: v4.24.12

* fix(react-query-devtools): do not stretch query status label (#5063)

Do not stretch query status label (fresh, fetching, paused, stale, inactive) shown on Query Details view.

* release: v4.24.13

* fix(react-query-devtools): add 'use client' directive to disable SSR (#5041)

Co-authored-by: Dominik Dorfmeister <[email protected]>

* release: v4.24.14

* feat(core): re-export matchQuery from utils (#5070)

Co-authored-by: Dominik Dorfmeister <[email protected]>

* release: v4.25.0

* feat(query-core): Add global onSettled callbacks for QueryCache and MutationCache (#5075)

* feat(query-core): Add global onSettled callbacks for QueryCache and MutationCache

* test: tests for query onSettled callback

* test: tests for mutation onSettled callback

* docs: onSettled callbacks

* release: v4.26.0

* fix(core): make sure mutations get updated options (#5085)

this fixes an issue around stale closures where callbacks are not updated, thus are called with wrong values in the closure

* release: v4.26.1

* fix(eslint-plugin): improve object property checks (#5079)

* fix(eslint-plugin): improve object property checks

* prettier

* release: v4.26.2

* docs: add adapter dropdown to issue template (#5108)

* docs(queries): rename `success` (#5110)

* chore: `test:lib` task-caching w/ Nx (#5116)

* adding quick caching test

* reverting workflow change

* updating pr yml to test nx speed

* fixing yml on property

* fixing yml on property

* fixing target name

* upping to running4 in parallel

* upping to running 5 in parallel

* upping to running 6 in parallel

* upping to running 7 in parallel

* upping to running 8 in parallel

* upping to running 9 in parallel

* upping to running 10 in parallel

* opting for --parallel=5

* cleaning up nx.json

* revert touching of ci.yml file

* reverting on property of pr.yml file

* updating root pacakge.json test:lib command

* fixing frozen lockfile error in ci

---------

Co-authored-by: Dominik Dorfmeister <[email protected]>

* chore: fix missing dependencies (#5127)

* chore: include scripts directory in linting

and fix issues

* chore: add missing dependencies chalk and semver

* chore: turning off Nx daemon in CI (#5128)

* chore: downgrade chalk to v4 because v5 is ESM only (#5130)

see: https://stackoverflow.com/questions/70309135/chalk-error-err-require-esm-require-of-es-module

* fix(eslint-plugin): ignore internal properties (#5119)

* chore: resolve merge conflicts

---------

Co-authored-by: Dominik Dorfmeister <[email protected]>
Co-authored-by: Abhijeet Singh <[email protected]>
Co-authored-by: Tanner Linsley <[email protected]>
Co-authored-by: janinegygax <[email protected]>
Co-authored-by: Youssouf Oumar <[email protected]>
Co-authored-by: remolueoend <[email protected]>
Co-authored-by: Eliya Cohen <[email protected]>
Co-authored-by: Damian Osipiuk <[email protected]>
Co-authored-by: Leon Fong <[email protected]>
Co-authored-by: Zachary DeRose <[email protected]>
Co-authored-by: Zachary DeRose <[email protected]>
  • Loading branch information
12 people authored Mar 15, 2023
1 parent 33338ad commit b7089d1
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 5 deletions.
2 changes: 2 additions & 0 deletions docs/react/devtools.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ function App() {
- The position of the React Query devtools panel
- `context?: React.Context<QueryClient | undefined>`
- Use this to use a custom React Query context. Otherwise, `defaultContext` will be used.
- `errorTypes?: { name: string; initializer: (query: Query) => { toString(): string }}`
- Use this to predefine some errors that can be triggered on your queries. Initializer will be called (with the specific query) when that error is toggled on from the UI. It must return an item that can be stringified so we can check for it's presence on any given query.

## Embedded Mode

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@testing-library/react": "^13.0.0",
"@testing-library/react-17": "npm:@testing-library/[email protected]",
"@testing-library/react-hooks": "^7.0.2",
"@testing-library/user-event": "14.4.3",
"@types/jest": "^26.0.4",
"@types/luxon": "^2.3.1",
"@types/node": "^17.0.25",
Expand Down
4 changes: 2 additions & 2 deletions packages/query-core/src/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ interface ContinueAction {

interface SetStateAction<TData, TError> {
type: 'setState'
state: QueryState<TData, TError>
state: Partial<QueryState<TData, TError>>
setStateOptions?: SetStateOptions
}

Expand Down Expand Up @@ -212,7 +212,7 @@ export class Query<
}

setState(
state: QueryState<TData, TError>,
state: Partial<QueryState<TData, TError>>,
setStateOptions?: SetStateOptions,
): void {
this.dispatch({ type: 'setState', state, setStateOptions })
Expand Down
139 changes: 139 additions & 0 deletions packages/react-query-devtools/src/__tests__/devtools.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
sleep,
createQueryClient,
} from './utils'
import UserEvent from '@testing-library/user-event'

// TODO: This should be removed with the types for react-error-boundary get updated.
declare module 'react-error-boundary' {
Expand All @@ -19,6 +20,13 @@ declare module 'react-error-boundary' {
}
}

class CustomError extends Error {
constructor(message: string) {
super(message)
this.name = 'CustomError'
}
}

Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query: string) => ({
Expand Down Expand Up @@ -915,4 +923,135 @@ describe('ReactQueryDevtools', () => {
fireEvent.click(screen.getByRole('button', { name: /^close$/i }))
expect(parentElement).toHaveStyle(parentPaddings)
})

it('should simulate loading state', async () => {
const { queryClient } = createQueryClient()
let count = 0
function App() {
const { data, fetchStatus } = useQuery(['key'], () => {
count++
return Promise.resolve('test')
})

return (
<div>
<h1>
{data ?? 'No data'}, {fetchStatus}
</h1>
</div>
)
}

renderWithClient(queryClient, <App />, {
initialIsOpen: true,
})

await screen.findByRole('heading', { name: /test/i })

const loadingButton = await screen.findByRole('button', {
name: 'Trigger loading',
})
fireEvent.click(loadingButton)

await waitFor(() => {
expect(screen.getByText('Restore loading')).toBeInTheDocument()
})

await waitFor(() => {
expect(screen.getByText('No data, fetching')).toBeInTheDocument()
})

fireEvent.click(screen.getByRole('button', { name: /restore loading/i }))

await waitFor(() => {
expect(screen.getByText('test, idle')).toBeInTheDocument()
})

expect(count).toBe(2)
})

it('should simulate error state', async () => {
const { queryClient } = createQueryClient()
function App() {
const { status, error } = useQuery(['key'], () => {
return Promise.resolve('test')
})

return (
<div>
<h1>
{!!error ? 'Some error' : 'No error'}, {status}
</h1>
</div>
)
}

renderWithClient(queryClient, <App />, {
initialIsOpen: true,
})

const errorButton = await screen.findByRole('button', {
name: 'Trigger error',
})
fireEvent.click(errorButton)

await waitFor(() => {
expect(screen.getByText('Restore error')).toBeInTheDocument()
})

await waitFor(() => {
expect(screen.getByText('Some error, error')).toBeInTheDocument()
})

fireEvent.click(screen.getByRole('button', { name: /Restore error/i }))

await waitFor(() => {
expect(screen.getByText('No error, success')).toBeInTheDocument()
})
})

it('should can simulate a specific error', async () => {
const { queryClient } = createQueryClient()

function App() {
const { status, error } = useQuery(['key'], () => {
return Promise.resolve('test')
})

return (
<div data-testid="test">
<h1>
{error instanceof CustomError
? error.message.toString()
: 'No error'}
, {status}
</h1>
</div>
)
}

renderWithClient(queryClient, <App />, {
initialIsOpen: true,
errorTypes: [
{
name: 'error1',
initializer: () => new CustomError('error1'),
},
],
})

const errorOption = await screen.findByLabelText('Trigger error:')

UserEvent.selectOptions(errorOption, 'error1')

await waitFor(() => {
expect(screen.getByText('error1, error')).toBeInTheDocument()
})

fireEvent.click(screen.getByRole('button', { name: /Restore error/i }))

await waitFor(() => {
expect(screen.getByText('No error, success')).toBeInTheDocument()
})
})
})
Loading

0 comments on commit b7089d1

Please sign in to comment.