Skip to content

Commit

Permalink
Merge pull request #14 from testing-library/jerel/fix-non-optional-props
Browse files Browse the repository at this point in the history
fix: Make props optional in `rerender` function returned from `renderHookToSnapshotStream`
  • Loading branch information
jerelmiller authored Jan 16, 2025
2 parents b209c2e + ac0b317 commit 6003495
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 5 deletions.
50 changes: 49 additions & 1 deletion src/__tests__/renderHookToSnapshotStream.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import {EventEmitter} from 'node:events'
import {scheduler} from 'node:timers/promises'
import {test, expect} from '@jest/globals'
import {renderHookToSnapshotStream} from '@testing-library/react-render-stream'
import {
renderHookToSnapshotStream,
SnapshotStream,
} from '@testing-library/react-render-stream'
import * as React from 'react'

const testEvents = new EventEmitter<{
Expand Down Expand Up @@ -72,3 +75,48 @@ test.each<[type: string, initialValue: unknown, ...nextValues: unknown[]]>([
expect(await takeSnapshot()).toBe(nextValue)
}
})

test.skip('type test: render function without an argument -> no argument required for `rerender`', async () => {
{
// prop type has nothing to infer on - defaults to `void`
const stream = await renderHookToSnapshotStream(() => {})
const _test1: SnapshotStream<void, void> = stream
// @ts-expect-error should not be assignable
const _test2: SnapshotStream<void, string> = stream
await stream.rerender()
// @ts-expect-error invalid argument
await stream.rerender('foo')
}
{
// prop type is implicitly set via the render function argument
const stream = await renderHookToSnapshotStream((_arg1: string) => {})
// @ts-expect-error should not be assignable
const _test1: SnapshotStream<void, void> = stream
const _test2: SnapshotStream<void, string> = stream
// @ts-expect-error missing argument
await stream.rerender()
await stream.rerender('foo')
}
{
// prop type is implicitly set via the initialProps argument
const stream = await renderHookToSnapshotStream(() => {}, {
initialProps: 'initial',
})
// @ts-expect-error should not be assignable
const _test1: SnapshotStream<void, void> = stream
const _test2: SnapshotStream<void, string> = stream
// @ts-expect-error missing argument
await stream.rerender()
await stream.rerender('foo')
}
{
// argument is optional
const stream = await renderHookToSnapshotStream((_arg1?: string) => {})

const _test1: SnapshotStream<void, void> = stream
const _test2: SnapshotStream<void, string> = stream
const _test3: SnapshotStream<void, string | undefined> = stream
await stream.rerender()
await stream.rerender('foo')
}
})
19 changes: 15 additions & 4 deletions src/renderHookToSnapshotStream.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,21 @@ export interface SnapshotStream<Snapshot, Props> extends Assertable {
* Does not advance the render iterator.
*/
waitForNextSnapshot(options?: NextRenderOptions): Promise<Snapshot>
rerender: (rerenderCallbackProps: Props) => Promise<void>
rerender: (rerenderCallbackProps: VoidOptionalArg<Props>) => Promise<void>
unmount: () => void
}

export async function renderHookToSnapshotStream<ReturnValue, Props>(
/**
* if `Arg` can be `undefined`, replace it with `void` to make type represent an optional argument in a function argument position
*/
type VoidOptionalArg<Arg> = Arg extends any // distribute members of a potential `Props` union
? undefined extends Arg
? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
void
: Arg
: Arg

export async function renderHookToSnapshotStream<ReturnValue, Props = void>(
renderCallback: (props: Props) => ReturnValue,
{initialProps, ...renderOptions}: RenderHookOptions<Props> = {},
): Promise<SnapshotStream<ReturnValue, Props>> {
Expand All @@ -61,8 +71,9 @@ export async function renderHookToSnapshotStream<ReturnValue, Props>(
renderOptions,
)

function rerender(rerenderCallbackProps: Props) {
return baseRerender(<HookComponent arg={rerenderCallbackProps} />)
function rerender(rerenderCallbackProps: VoidOptionalArg<Props>) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
return baseRerender(<HookComponent arg={rerenderCallbackProps as any} />)
}

return {
Expand Down

0 comments on commit 6003495

Please sign in to comment.