Skip to content

feat!: necessary api changes for React 19 compatibility #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 38 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ddf9df9
add `renderWithoutAct` helper
phryneas Nov 26, 2024
e8616b3
painful progress
phryneas Nov 26, 2024
5ff5420
make render async to wait for first render
phryneas Nov 27, 2024
c124751
all tests passing
phryneas Nov 27, 2024
20ef3eb
more tweaking
phryneas Nov 27, 2024
b086f98
fix type
phryneas Nov 27, 2024
6fb6fb1
also wrap asyncWrapper
phryneas Nov 27, 2024
8474b54
export `RenderWithoutActAsync` type
phryneas Nov 27, 2024
d926b40
build legacy root in React 16/17
phryneas Nov 28, 2024
1ad050f
disable act with confidence
phryneas Nov 28, 2024
9ef55bb
don't auto-disable act, throw error instead
phryneas Nov 29, 2024
2c5b29e
adjust imports
phryneas Nov 29, 2024
69a4c4b
wait a bunch longer so react doesn't batch
phryneas Nov 29, 2024
c064440
add comment
phryneas Nov 29, 2024
932f938
guard in tests against accidental `IS_REACT_ACT_ENVIRONMENT`
phryneas Nov 29, 2024
451d67a
drain the microtask queue before returning from `peekRender`
phryneas Nov 29, 2024
53d9f45
directly import from `@testing-library/dom` where possible
phryneas Nov 29, 2024
32daf10
move `useWithoutAct` into `disableActEnvironment`, reduce api size
phryneas Dec 2, 2024
084b691
keep `writable` at cleanup
phryneas Dec 2, 2024
563b934
early bailout in `cleanup`
phryneas Dec 2, 2024
0e9d9d7
keep `renderWithoutAct` private
phryneas Dec 2, 2024
94f35e5
`renderToRenderStream` also should be async
phryneas Dec 2, 2024
262ceba
make `rerender` wait for the render and return `Promise<void>`
phryneas Dec 2, 2024
c09b997
update README
phryneas Dec 2, 2024
200d9d2
remove unused type
phryneas Dec 2, 2024
0cf8f41
undo `renderToRenderStream` changes
phryneas Dec 2, 2024
20601bc
add type export back
phryneas Dec 2, 2024
e1cb39d
update type
phryneas Dec 2, 2024
fab8705
guard against sync rerenders
phryneas Dec 2, 2024
04c222d
remove `renderToRenderStream`
phryneas Dec 3, 2024
324ae88
add lint pr job
phryneas Dec 3, 2024
e1eae04
avoid uncaught promise rejection in test
phryneas Dec 3, 2024
7e9ac02
Merge branch 'main' into pr/noActRender
phryneas Dec 3, 2024
7ea9591
run tests with React 19 RC1
phryneas Dec 3, 2024
7ede425
use `use` over the shim when available
phryneas Dec 3, 2024
f3fb67d
Apply suggestions from code review
phryneas Dec 4, 2024
b0d022f
adjust import
phryneas Dec 4, 2024
4d2345b
review suggestions
phryneas Dec 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
painful progress
  • Loading branch information
phryneas committed Nov 26, 2024
commit e8616b307e4afb3f71c5f0ec54747796520f6c7a
11 changes: 7 additions & 4 deletions src/__tests__/renderHookToSnapshotStream.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import {renderHookToSnapshotStream} from '@testing-library/react-render-stream'
import * as React from 'react'
import {withDisabledActWarnings} from '../__testHelpers__/withDisabledActWarnings.js'

// @ts-expect-error this is not defined anywhere
globalThis.IS_REACT_ACT_ENVIRONMENT = false

const testEvents = new EventEmitter<{
rerenderWithValue: [unknown]
}>()
Expand Down Expand Up @@ -33,13 +36,13 @@ test('basic functionality', async () => {
const {takeSnapshot} = renderHookToSnapshotStream(useRerenderEvents, {
initialProps: 'initial',
})
testEvents.emit('rerenderWithValue', 'value')
await Promise.resolve()
testEvents.emit('rerenderWithValue', 'value2')
{
const snapshot = await takeSnapshot()
expect(snapshot).toBe('initial')
}
testEvents.emit('rerenderWithValue', 'value')
await Promise.resolve()
testEvents.emit('rerenderWithValue', 'value2')
{
const snapshot = await takeSnapshot()
expect(snapshot).toBe('value')
Expand All @@ -62,12 +65,12 @@ test.each<[type: string, initialValue: unknown, ...nextValues: unknown[]]>([
const {takeSnapshot} = renderHookToSnapshotStream(useRerenderEvents, {
initialProps: initialValue,
})
expect(await takeSnapshot()).toBe(initialValue)
for (const nextValue of nextValues) {
testEvents.emit('rerenderWithValue', nextValue)
// allow for a render to happen
await Promise.resolve()
}
expect(await takeSnapshot()).toBe(initialValue)
for (const nextValue of nextValues) {
expect(await takeSnapshot()).toBe(nextValue)
}
Expand Down
10 changes: 7 additions & 3 deletions src/__tests__/renderToRenderStream.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import {describe, test, expect} from '@jest/globals'
import {renderToRenderStream} from '@testing-library/react-render-stream'
import {userEvent} from '@testing-library/user-event'
import * as React from 'react'

// @ts-expect-error this is not defined anywhere
globalThis.IS_REACT_ACT_ENVIRONMENT = false

function CounterForm({
value,
onIncrement,
Expand Down Expand Up @@ -39,14 +43,14 @@ describe('snapshotDOM', () => {
},
)
const utils = await renderResultPromise
const incrementButton = utils.getByText('Increment')
await userEvent.click(incrementButton)
await userEvent.click(incrementButton)
{
const {withinDOM} = await takeRender()
const input = withinDOM().getByLabelText<HTMLInputElement>('Value')
expect(input.value).toBe('0')
}
const incrementButton = utils.getByText('Increment')
await userEvent.click(incrementButton)
await userEvent.click(incrementButton)
{
const {withinDOM} = await takeRender()
const input = withinDOM().getByLabelText<HTMLInputElement>('Value')
Expand Down
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
import '@testing-library/react-render-stream/expect'
import {cleanup} from '@testing-library/react-render-stream/pure'
export * from '@testing-library/react-render-stream/pure'

const global = globalThis as {afterEach?: (fn: () => void) => void}
if (global.afterEach) {
global.afterEach(cleanup)
}
2 changes: 1 addition & 1 deletion src/pure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ export type {SnapshotStream} from './renderHookToSnapshotStream.js'

export type {Assertable} from './assertable.js'

export {renderWithoutAct} from './renderStream/renderWithoutAct.js'
export {renderWithoutAct, cleanup} from './renderStream/renderWithoutAct.js'
49 changes: 32 additions & 17 deletions src/renderStream/__tests__/createRenderStream.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
import {jest, describe, test, expect} from '@jest/globals'
import {createRenderStream} from '@testing-library/react-render-stream'
import {userEvent} from '@testing-library/user-event'
//import {userEvent} from '@testing-library/user-event'
import * as React from 'react'
import {ErrorBoundary} from 'react-error-boundary'
import {getExpectErrorMessage} from '../../__testHelpers__/getCleanedErrorMessage.js'

// @ts-expect-error this is not defined anywhere
globalThis.IS_REACT_ACT_ENVIRONMENT = false

async function click(element: HTMLElement) {
const opts = {bubbles: true, cancelable: true, buttons: 1}
element.dispatchEvent(new Event('mousedown', opts))
await new Promise(r => setTimeout(r, 50))
element.dispatchEvent(new Event('mouseup', opts))
element.dispatchEvent(new Event('click', opts))
}

function CounterForm({
value,
onIncrement,
Expand Down Expand Up @@ -39,14 +50,14 @@ describe('snapshotDOM', () => {
snapshotDOM: true,
})
const utils = render(<Counter />)
const incrementButton = utils.getByText('Increment')
await userEvent.click(incrementButton)
await userEvent.click(incrementButton)
{
const {withinDOM} = await takeRender()
const input = withinDOM().getByLabelText<HTMLInputElement>('Value')
expect(input.value).toBe('0')
}
const incrementButton = utils.getByText('Increment') as HTMLElement // TODO
await click(incrementButton)
await click(incrementButton)
{
const {withinDOM} = await takeRender()
// a one-off to test that `queryBy` works and accepts a type argument
Expand Down Expand Up @@ -76,7 +87,7 @@ describe('snapshotDOM', () => {
const {withinDOM} = await takeRender()
const snapshotIncrementButton = withinDOM().getByText('Increment')
try {
await userEvent.click(snapshotIncrementButton)
await click(snapshotIncrementButton)
} catch (error) {
expect(error).toMatchInlineSnapshot(`
[Error: Uncaught [Error:
Expand Down Expand Up @@ -130,13 +141,13 @@ describe('replaceSnapshot', () => {
value: number
}>()
const utils = render(<Counter />)
const incrementButton = utils.getByText('Increment')
await userEvent.click(incrementButton)
await userEvent.click(incrementButton)
{
const {snapshot} = await takeRender()
expect(snapshot).toEqual({value: 0})
}
const incrementButton = utils.getByText('Increment') as HTMLElement // TODO
await click(incrementButton)
await click(incrementButton)
{
const {snapshot} = await takeRender()
expect(snapshot).toEqual({value: 1})
Expand All @@ -160,13 +171,14 @@ describe('replaceSnapshot', () => {
initialSnapshot: {unrelatedValue: 'unrelated', value: -1},
})
const utils = render(<Counter />)
const incrementButton = utils.getByText('Increment')
await userEvent.click(incrementButton)
await userEvent.click(incrementButton)
{
const {snapshot} = await takeRender()
expect(snapshot).toEqual({unrelatedValue: 'unrelated', value: 0})
}

const incrementButton = utils.getByText('Increment') as HTMLElement // TODO
await click(incrementButton)
await click(incrementButton)
{
const {snapshot} = await takeRender()
expect(snapshot).toEqual({unrelatedValue: 'unrelated', value: 1})
Expand Down Expand Up @@ -203,6 +215,8 @@ describe('replaceSnapshot', () => {
<Counter />
</ErrorBoundary>,
)
await new Promise(r => setTimeout(r, 10))

spy.mockRestore()

expect(caughtError!).toMatchInlineSnapshot(
Expand Down Expand Up @@ -231,10 +245,11 @@ describe('onRender', () => {
},
})
const utils = render(<Counter />)
const incrementButton = utils.getByText('Increment')
await userEvent.click(incrementButton)
await userEvent.click(incrementButton)
await takeRender()

const incrementButton = utils.getByText('Increment') as HTMLElement // TODO
await click(incrementButton)
await click(incrementButton)
await takeRender()
await takeRender()
})
Expand All @@ -254,10 +269,10 @@ describe('onRender', () => {
})

const utils = render(<Counter />)
const incrementButton = utils.getByText('Increment')
await userEvent.click(incrementButton)
await userEvent.click(incrementButton)
await takeRender()
const incrementButton = utils.getByText('Increment') as HTMLElement // TODO
await click(incrementButton)
await click(incrementButton)
const error = await getExpectErrorMessage(takeRender())

expect(error).toMatchInlineSnapshot(`
Expand Down
14 changes: 14 additions & 0 deletions src/renderStream/renderWithoutAct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ function renderRoot(
root: ReturnType<typeof createConcurrentRoot>
},
): RenderResult<Queries, any, any> {
// @ts-expect-error this is not defined anywhere
globalThis.IS_REACT_ACT_ENVIRONMENT = false
root.render(
WrapperComponent ? React.createElement(WrapperComponent, null, ui) : ui,
)
Expand Down Expand Up @@ -150,3 +152,15 @@ function createConcurrentRoot(container: ReactDOMClient.Container) {
},
}
}

export function cleanup() {
mountedRootEntries.forEach(({root, container}) => {
root.unmount()

if (container.parentNode === document.body) {
document.body.removeChild(container)
}
})
mountedRootEntries.length = 0
mountedContainers.clear()
}
Loading