Skip to content

[WIP] add functions based on renderAsync #9

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
],
"dependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.0.1",
"@testing-library/react": "https://pkg.csb.dev/testing-library/react-testing-library/commit/571fbc81/@testing-library/react/_pkg.tgz",
"jsdom": "^25.0.1",
"rehackt": "^0.1.0"
},
Expand Down
10 changes: 8 additions & 2 deletions src/pure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ export {useTrackRenders} from './renderStream/useTrackRenders.js'

export type {SyncScreen} from './renderStream/Render.js'

export {renderToRenderStream} from './renderToRenderStream.js'
export {
renderToRenderStream,
renderToAsyncRenderStream,
} from './renderToRenderStream.js'
export type {RenderStreamWithRenderResult} from './renderToRenderStream.js'
export {renderHookToSnapshotStream} from './renderHookToSnapshotStream.js'
export {
renderHookToSnapshotStream,
renderHookToAsyncSnapshotStream,
} from './renderHookToSnapshotStream.js'
export type {SnapshotStream} from './renderHookToSnapshotStream.js'

export type {Assertable} from './assertable.js'
57 changes: 52 additions & 5 deletions src/renderHookToSnapshotStream.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import {RenderHookOptions} from '@testing-library/react'
import {Queries, RenderHookOptions} from '@testing-library/react'
import React from 'rehackt'
import {createRenderStream} from './renderStream/createRenderStream.js'
import {
createRenderStream,
RenderStream,
} from './renderStream/createRenderStream.js'
import {type NextRenderOptions} from './renderStream/createRenderStream.js'
import {Render} from './renderStream/Render.js'
import {Assertable, assertableSymbol, markAssertable} from './assertable.js'
import {SyncQueries} from './renderStream/syncQueries.js'

export interface SnapshotStream<Snapshot, Props> extends Assertable {
/**
Expand Down Expand Up @@ -49,7 +53,11 @@ export function renderHookToSnapshotStream<ReturnValue, Props>(
renderCallback: (props: Props) => ReturnValue,
{initialProps, ...renderOptions}: RenderHookOptions<Props> = {},
): SnapshotStream<ReturnValue, Props> {
const {render, ...stream} = createRenderStream<{value: ReturnValue}, never>()
const {
render,
renderAsync: _,
...stream
} = createRenderStream<{value: ReturnValue}, never>()

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

return {
...renderStreamToSnapshotStream(stream),
rerender,
unmount,
}
}

export async function renderHookToAsyncSnapshotStream<ReturnValue, Props>(
renderCallback: (props: Props) => ReturnValue,
{initialProps, ...renderOptions}: RenderHookOptions<Props> = {},
): Promise<SnapshotStream<ReturnValue, Props>> {
const {
renderAsync,
render: _,
...stream
} = createRenderStream<{value: ReturnValue}, never>()

const HookComponent: React.FC<{arg: Props}> = props => {
stream.replaceSnapshot({value: renderCallback(props.arg)})
return null
}

const {rerender: baseRerender, unmount} = await renderAsync(
<HookComponent arg={initialProps!} />,
renderOptions,
)

function rerender(rerenderCallbackProps: Props) {
return baseRerender(<HookComponent arg={rerenderCallbackProps} />)
}

return {
...renderStreamToSnapshotStream(stream),
rerender,
unmount,
}
}

function renderStreamToSnapshotStream<Snapshot>(
stream: RenderStream<{value: Snapshot}, never>,
): Omit<SnapshotStream<Snapshot, any>, 'rerender' | 'unmount'> {
return {
[assertableSymbol]: stream,
renders: stream.renders,
Expand All @@ -81,7 +130,5 @@ export function renderHookToSnapshotStream<ReturnValue, Props>(
async waitForNextSnapshot(options) {
return (await stream.waitForNextRender(options)).snapshot.value
},
rerender,
unmount,
}
}
25 changes: 24 additions & 1 deletion src/renderStream/createRenderStream.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import * as React from 'rehackt'

import {render as baseRender, RenderOptions} from '@testing-library/react'
import {
render as baseRender,
renderAsync as baseRenderAsync,
RenderOptions,
} from '@testing-library/react'
import {Assertable, markAssertable} from '../assertable.js'
import {RenderInstance, type Render, type BaseRender} from './Render.js'
import {type RenderStreamContextValue} from './context.js'
Expand Down Expand Up @@ -82,6 +86,7 @@ export interface RenderStreamWithRenderFn<
Q extends Queries = SyncQueries,
> extends RenderStream<Snapshot, Q> {
render: typeof baseRender
renderAsync: typeof baseRenderAsync
}

export type RenderStreamOptions<
Expand Down Expand Up @@ -264,6 +269,23 @@ export function createRenderStream<
})
}) as typeof baseRender

const renderAsync = ((
ui: React.ReactNode,
options?: RenderOptions<any, any, any>,
) => {
return baseRenderAsync(ui, {
...options,
wrapper: (props: any) => {
const ParentWrapper = options?.wrapper ?? React.Fragment
return (
<ParentWrapper>
<Wrapper>{props.children}</Wrapper>
</ParentWrapper>
)
},
})
}) as typeof baseRenderAsync

Object.assign<typeof stream, typeof stream>(stream, {
replaceSnapshot,
mergeSnapshot,
Expand Down Expand Up @@ -356,6 +378,7 @@ export function createRenderStream<
return nextRender
},
render,
renderAsync,
})
return stream
}
Expand Down
43 changes: 42 additions & 1 deletion src/renderToRenderStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ export function renderToRenderStream<
...options
}: RenderOptions<Snapshot, Q> = {},
): RenderStreamWithRenderResult<Snapshot, Q> {
const {render, ...stream} = createRenderStream<Snapshot, Q>({
const {
render,
renderAsync: _,
...stream
} = createRenderStream<Snapshot, Q>({
onRender,
snapshotDOM,
initialSnapshot,
Expand All @@ -55,3 +59,40 @@ export function renderToRenderStream<
)
return {...stream, renderResultPromise}
}

/**
* Render into a container which is appended to document.body. It should be used with cleanup.
*/
export function renderToAsyncRenderStream<
Snapshot extends ValidSnapshot = void,
Q extends Queries = SyncQueries,
>(
ui: React.ReactNode,
{
onRender,
snapshotDOM,
initialSnapshot,
skipNonTrackingRenders,
queries,
...options
}: RenderOptions<Snapshot, Q> = {},
): RenderStreamWithRenderResult<Snapshot, Q> {
const {
renderAsync,
render: _,
...stream
} = createRenderStream<Snapshot, Q>({
onRender,
snapshotDOM,
initialSnapshot,
skipNonTrackingRenders,
queries,
})
// `renderAsync` needs to be called asynchronously here, because the definition of `ui`
// might contain components that reference the return value of `renderToRenderStream`
// itself, e.g. `replaceSnapshot` or `mergeSnapshot`.
const renderResultPromise = Promise.resolve().then(() =>
renderAsync<Q>(ui, {...options, queries}),
)
return {...stream, renderResultPromise}
}
Loading
Loading