Skip to content

Commit

Permalink
test: refactor concurrent rendering tests (#1457)
Browse files Browse the repository at this point in the history
* test: refactor concurrent rendering tests

* test: use wrapper option that testing-library provides instead of wrapping manually
  • Loading branch information
koba04 committed Sep 13, 2021
1 parent 8fff15b commit df16c89
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 35 deletions.
60 changes: 32 additions & 28 deletions test/use-swr-concurrent-rendering.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
// Only eventual consistency is guaranteed.

import { screen, fireEvent } from '@testing-library/react'
import { createResponse, sleep } from './utils'
import { createKey, createResponse, sleep } from './utils'

describe('useSWR - concurrent rendering', () => {
let React, ReactDOM, act, useSWR
let React, ReactDOM, act, useSWR, reactRoot, renderWithConfig

beforeAll(() => {
jest.resetModules()
Expand All @@ -21,38 +21,44 @@ describe('useSWR - concurrent rendering', () => {
ReactDOM = require('react-dom')
act = require('react-dom/test-utils').act
useSWR = require('swr').default
})
const SWRConfig = require('swr').SWRConfig

it('should fetch data in concurrent rendering', async () => {
const root = document.createElement('div')
document.body.appendChild(root)
const reactRoot = ReactDOM.createRoot(root)
reactRoot = ReactDOM.createRoot(root)

renderWithConfig = (element, config) =>
act(() =>
reactRoot.render(
<SWRConfig value={{ provider: () => new Map(), ...config }}>
{element}
</SWRConfig>
)
)
})
afterEach(() => {
act(() => reactRoot.unmount())
})

it('should fetch data in concurrent rendering', async () => {
const key = createKey()
function Page() {
const { data } = useSWR(
'concurrent-1',
() => createResponse('0', { delay: 50 }),
{
dedupingInterval: 0
}
)
const { data } = useSWR(key, () => createResponse('0', { delay: 50 }), {
dedupingInterval: 0
})
return <div>data:{data}</div>
}

act(() => reactRoot.render(<Page />))
renderWithConfig(<Page />)

screen.getByText('data:')
await act(() => sleep(100))
screen.getByText('data:0')

act(() => reactRoot.unmount())
})

it('should pause when changing the key inside a transition', async () => {
const root = document.createElement('div')
document.body.appendChild(root)
const reactRoot = ReactDOM.createRoot(root)

const initialKey = createKey()
const newKey = createKey()
const fetcher = (k: string) => createResponse(k, { delay: 100 })
// eslint-disable-next-line react/prop-types
function Component({ swrKey }) {
Expand All @@ -65,10 +71,10 @@ describe('useSWR - concurrent rendering', () => {
}
function Page() {
const [isPending, startTransition] = React.useTransition()
const [key, setKey] = React.useState('concurrent-2')
const [key, setKey] = React.useState(initialKey)

return (
<div onClick={() => startTransition(() => setKey('new-key'))}>
<div onClick={() => startTransition(() => setKey(newKey))}>
isPending:{isPending ? 1 : 0},
<React.Suspense fallback="loading">
<Component swrKey={key} />
Expand All @@ -77,21 +83,19 @@ describe('useSWR - concurrent rendering', () => {
)
}

act(() => reactRoot.render(<Page />))
renderWithConfig(<Page />)

screen.getByText('isPending:0,loading')
await act(() => sleep(120))
screen.getByText('isPending:0,data:concurrent-2')
fireEvent.click(screen.getByText('isPending:0,data:concurrent-2'))
screen.getByText(`isPending:0,data:${initialKey}`)
fireEvent.click(screen.getByText(`isPending:0,data:${initialKey}`))
await act(() => sleep(10))

// Pending state
screen.getByText('isPending:1,data:concurrent-2')
screen.getByText(`isPending:1,data:${initialKey}`)

// Transition end
await act(() => sleep(120))
screen.getByText('isPending:0,data:new-key')

act(() => reactRoot.unmount())
screen.getByText(`isPending:0,data:${newKey}`)
})
})
11 changes: 4 additions & 7 deletions test/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,10 @@ const _renderWithConfig = (
element: React.ReactElement,
config: Parameters<typeof SWRConfig>[0]['value']
): ReturnType<typeof render> => {
const result = render(<SWRConfig value={config}>{element}</SWRConfig>)
return {
...result,
// override the rerender method to wrap the element with SWRConfig again
rerender: (rerenderElement: React.ReactElement) =>
result.rerender(<SWRConfig value={config}>{rerenderElement}</SWRConfig>)
}
const TestSWRConfig = ({ children }: { children: React.ReactNode }) => (
<SWRConfig value={config}>{children}</SWRConfig>
)
return render(element, { wrapper: TestSWRConfig })
}

export const renderWithConfig = (
Expand Down

0 comments on commit df16c89

Please sign in to comment.