Skip to content

Commit 6003495

Browse files
authored
Merge pull request #14 from testing-library/jerel/fix-non-optional-props
fix: Make props optional in `rerender` function returned from `renderHookToSnapshotStream`
2 parents b209c2e + ac0b317 commit 6003495

File tree

2 files changed

+64
-5
lines changed

2 files changed

+64
-5
lines changed

src/__tests__/renderHookToSnapshotStream.test.tsx

+49-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
import {EventEmitter} from 'node:events'
44
import {scheduler} from 'node:timers/promises'
55
import {test, expect} from '@jest/globals'
6-
import {renderHookToSnapshotStream} from '@testing-library/react-render-stream'
6+
import {
7+
renderHookToSnapshotStream,
8+
SnapshotStream,
9+
} from '@testing-library/react-render-stream'
710
import * as React from 'react'
811

912
const testEvents = new EventEmitter<{
@@ -72,3 +75,48 @@ test.each<[type: string, initialValue: unknown, ...nextValues: unknown[]]>([
7275
expect(await takeSnapshot()).toBe(nextValue)
7376
}
7477
})
78+
79+
test.skip('type test: render function without an argument -> no argument required for `rerender`', async () => {
80+
{
81+
// prop type has nothing to infer on - defaults to `void`
82+
const stream = await renderHookToSnapshotStream(() => {})
83+
const _test1: SnapshotStream<void, void> = stream
84+
// @ts-expect-error should not be assignable
85+
const _test2: SnapshotStream<void, string> = stream
86+
await stream.rerender()
87+
// @ts-expect-error invalid argument
88+
await stream.rerender('foo')
89+
}
90+
{
91+
// prop type is implicitly set via the render function argument
92+
const stream = await renderHookToSnapshotStream((_arg1: string) => {})
93+
// @ts-expect-error should not be assignable
94+
const _test1: SnapshotStream<void, void> = stream
95+
const _test2: SnapshotStream<void, string> = stream
96+
// @ts-expect-error missing argument
97+
await stream.rerender()
98+
await stream.rerender('foo')
99+
}
100+
{
101+
// prop type is implicitly set via the initialProps argument
102+
const stream = await renderHookToSnapshotStream(() => {}, {
103+
initialProps: 'initial',
104+
})
105+
// @ts-expect-error should not be assignable
106+
const _test1: SnapshotStream<void, void> = stream
107+
const _test2: SnapshotStream<void, string> = stream
108+
// @ts-expect-error missing argument
109+
await stream.rerender()
110+
await stream.rerender('foo')
111+
}
112+
{
113+
// argument is optional
114+
const stream = await renderHookToSnapshotStream((_arg1?: string) => {})
115+
116+
const _test1: SnapshotStream<void, void> = stream
117+
const _test2: SnapshotStream<void, string> = stream
118+
const _test3: SnapshotStream<void, string | undefined> = stream
119+
await stream.rerender()
120+
await stream.rerender('foo')
121+
}
122+
})

src/renderHookToSnapshotStream.tsx

+15-4
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,21 @@ export interface SnapshotStream<Snapshot, Props> extends Assertable {
4141
* Does not advance the render iterator.
4242
*/
4343
waitForNextSnapshot(options?: NextRenderOptions): Promise<Snapshot>
44-
rerender: (rerenderCallbackProps: Props) => Promise<void>
44+
rerender: (rerenderCallbackProps: VoidOptionalArg<Props>) => Promise<void>
4545
unmount: () => void
4646
}
4747

48-
export async function renderHookToSnapshotStream<ReturnValue, Props>(
48+
/**
49+
* if `Arg` can be `undefined`, replace it with `void` to make type represent an optional argument in a function argument position
50+
*/
51+
type VoidOptionalArg<Arg> = Arg extends any // distribute members of a potential `Props` union
52+
? undefined extends Arg
53+
? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
54+
void
55+
: Arg
56+
: Arg
57+
58+
export async function renderHookToSnapshotStream<ReturnValue, Props = void>(
4959
renderCallback: (props: Props) => ReturnValue,
5060
{initialProps, ...renderOptions}: RenderHookOptions<Props> = {},
5161
): Promise<SnapshotStream<ReturnValue, Props>> {
@@ -61,8 +71,9 @@ export async function renderHookToSnapshotStream<ReturnValue, Props>(
6171
renderOptions,
6272
)
6373

64-
function rerender(rerenderCallbackProps: Props) {
65-
return baseRerender(<HookComponent arg={rerenderCallbackProps} />)
74+
function rerender(rerenderCallbackProps: VoidOptionalArg<Props>) {
75+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
76+
return baseRerender(<HookComponent arg={rerenderCallbackProps as any} />)
6677
}
6778

6879
return {

0 commit comments

Comments
 (0)