Skip to content

Commit 551d54f

Browse files
committed
add functions based on renderAsync
1 parent c4b152e commit 551d54f

File tree

5 files changed

+1252
-1287
lines changed

5 files changed

+1252
-1287
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
],
6666
"dependencies": {
6767
"@testing-library/dom": "^10.4.0",
68-
"@testing-library/react": "^16.0.1",
68+
"@testing-library/react": "https://pkg.csb.dev/testing-library/react-testing-library/commit/571fbc81/@testing-library/react/_pkg.tgz",
6969
"jsdom": "^25.0.1",
7070
"rehackt": "^0.1.0"
7171
},

src/renderHookToSnapshotStream.tsx

+52-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import {RenderHookOptions} from '@testing-library/react'
1+
import {Queries, RenderHookOptions} from '@testing-library/react'
22
import React from 'rehackt'
3-
import {createRenderStream} from './renderStream/createRenderStream.js'
3+
import {
4+
createRenderStream,
5+
RenderStream,
6+
} from './renderStream/createRenderStream.js'
47
import {type NextRenderOptions} from './renderStream/createRenderStream.js'
58
import {Render} from './renderStream/Render.js'
69
import {Assertable, assertableSymbol, markAssertable} from './assertable.js'
10+
import {SyncQueries} from './renderStream/syncQueries.js'
711

812
export interface SnapshotStream<Snapshot, Props> extends Assertable {
913
/**
@@ -49,7 +53,11 @@ export function renderHookToSnapshotStream<ReturnValue, Props>(
4953
renderCallback: (props: Props) => ReturnValue,
5054
{initialProps, ...renderOptions}: RenderHookOptions<Props> = {},
5155
): SnapshotStream<ReturnValue, Props> {
52-
const {render, ...stream} = createRenderStream<{value: ReturnValue}, never>()
56+
const {
57+
render,
58+
renderAsync: _,
59+
...stream
60+
} = createRenderStream<{value: ReturnValue}, never>()
5361

5462
const HookComponent: React.FC<{arg: Props}> = props => {
5563
stream.replaceSnapshot({value: renderCallback(props.arg)})
@@ -65,6 +73,47 @@ export function renderHookToSnapshotStream<ReturnValue, Props>(
6573
return baseRerender(<HookComponent arg={rerenderCallbackProps} />)
6674
}
6775

76+
return {
77+
...renderStreamToSnapshotStream(stream),
78+
rerender,
79+
unmount,
80+
}
81+
}
82+
83+
export async function renderHookToAsyncSnapshotStream<ReturnValue, Props>(
84+
renderCallback: (props: Props) => ReturnValue,
85+
{initialProps, ...renderOptions}: RenderHookOptions<Props> = {},
86+
): Promise<SnapshotStream<ReturnValue, Props>> {
87+
const {
88+
renderAsync,
89+
render: _,
90+
...stream
91+
} = createRenderStream<{value: ReturnValue}, never>()
92+
93+
const HookComponent: React.FC<{arg: Props}> = props => {
94+
stream.replaceSnapshot({value: renderCallback(props.arg)})
95+
return null
96+
}
97+
98+
const {rerender: baseRerender, unmount} = await renderAsync(
99+
<HookComponent arg={initialProps!} />,
100+
renderOptions,
101+
)
102+
103+
function rerender(rerenderCallbackProps: Props) {
104+
return baseRerender(<HookComponent arg={rerenderCallbackProps} />)
105+
}
106+
107+
return {
108+
...renderStreamToSnapshotStream(stream),
109+
rerender,
110+
unmount,
111+
}
112+
}
113+
114+
function renderStreamToSnapshotStream<Snapshot>(
115+
stream: RenderStream<{value: Snapshot}, never>,
116+
): Omit<SnapshotStream<Snapshot, any>, 'rerender' | 'unmount'> {
68117
return {
69118
[assertableSymbol]: stream,
70119
renders: stream.renders,
@@ -81,7 +130,5 @@ export function renderHookToSnapshotStream<ReturnValue, Props>(
81130
async waitForNextSnapshot(options) {
82131
return (await stream.waitForNextRender(options)).snapshot.value
83132
},
84-
rerender,
85-
unmount,
86133
}
87134
}

src/renderStream/createRenderStream.tsx

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import * as React from 'rehackt'
22

3-
import {render as baseRender, RenderOptions} from '@testing-library/react'
3+
import {
4+
render as baseRender,
5+
renderAsync as baseRenderAsync,
6+
RenderOptions,
7+
} from '@testing-library/react'
48
import {Assertable, markAssertable} from '../assertable.js'
59
import {RenderInstance, type Render, type BaseRender} from './Render.js'
610
import {type RenderStreamContextValue} from './context.js'
@@ -82,6 +86,7 @@ export interface RenderStreamWithRenderFn<
8286
Q extends Queries = SyncQueries,
8387
> extends RenderStream<Snapshot, Q> {
8488
render: typeof baseRender
89+
renderAsync: typeof baseRenderAsync
8590
}
8691

8792
export type RenderStreamOptions<
@@ -264,6 +269,23 @@ export function createRenderStream<
264269
})
265270
}) as typeof baseRender
266271

272+
const renderAsync = ((
273+
ui: React.ReactNode,
274+
options?: RenderOptions<any, any, any>,
275+
) => {
276+
return baseRenderAsync(ui, {
277+
...options,
278+
wrapper: (props: any) => {
279+
const ParentWrapper = options?.wrapper ?? React.Fragment
280+
return (
281+
<ParentWrapper>
282+
<Wrapper>{props.children}</Wrapper>
283+
</ParentWrapper>
284+
)
285+
},
286+
})
287+
}) as typeof baseRenderAsync
288+
267289
Object.assign<typeof stream, typeof stream>(stream, {
268290
replaceSnapshot,
269291
mergeSnapshot,
@@ -356,6 +378,7 @@ export function createRenderStream<
356378
return nextRender
357379
},
358380
render,
381+
renderAsync,
359382
})
360383
return stream
361384
}

src/renderToRenderStream.ts

+42-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ export function renderToRenderStream<
4040
...options
4141
}: RenderOptions<Snapshot, Q> = {},
4242
): RenderStreamWithRenderResult<Snapshot, Q> {
43-
const {render, ...stream} = createRenderStream<Snapshot, Q>({
43+
const {
44+
render,
45+
renderAsync: _,
46+
...stream
47+
} = createRenderStream<Snapshot, Q>({
4448
onRender,
4549
snapshotDOM,
4650
initialSnapshot,
@@ -55,3 +59,40 @@ export function renderToRenderStream<
5559
)
5660
return {...stream, renderResultPromise}
5761
}
62+
63+
/**
64+
* Render into a container which is appended to document.body. It should be used with cleanup.
65+
*/
66+
export function renderToAsyncRenderStream<
67+
Snapshot extends ValidSnapshot = void,
68+
Q extends Queries = SyncQueries,
69+
>(
70+
ui: React.ReactNode,
71+
{
72+
onRender,
73+
snapshotDOM,
74+
initialSnapshot,
75+
skipNonTrackingRenders,
76+
queries,
77+
...options
78+
}: RenderOptions<Snapshot, Q> = {},
79+
): RenderStreamWithRenderResult<Snapshot, Q> {
80+
const {
81+
renderAsync,
82+
render: _,
83+
...stream
84+
} = createRenderStream<Snapshot, Q>({
85+
onRender,
86+
snapshotDOM,
87+
initialSnapshot,
88+
skipNonTrackingRenders,
89+
queries,
90+
})
91+
// `renderAsync` needs to be called asynchronously here, because the definition of `ui`
92+
// might contain components that reference the return value of `renderToRenderStream`
93+
// itself, e.g. `replaceSnapshot` or `mergeSnapshot`.
94+
const renderResultPromise = Promise.resolve().then(() =>
95+
renderAsync<Q>(ui, {...options, queries}),
96+
)
97+
return {...stream, renderResultPromise}
98+
}

0 commit comments

Comments
 (0)