diff --git a/src/__tests__/renderHookToSnapshotStream.test.tsx b/src/__tests__/renderHookToSnapshotStream.test.tsx index 108da49e8..c42f3a10a 100644 --- a/src/__tests__/renderHookToSnapshotStream.test.tsx +++ b/src/__tests__/renderHookToSnapshotStream.test.tsx @@ -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<{ @@ -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 = stream + // @ts-expect-error should not be assignable + const _test2: SnapshotStream = 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 = stream + const _test2: SnapshotStream = 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 = stream + const _test2: SnapshotStream = 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 = stream + const _test2: SnapshotStream = stream + const _test3: SnapshotStream = stream + await stream.rerender() + await stream.rerender('foo') + } +}) diff --git a/src/renderHookToSnapshotStream.tsx b/src/renderHookToSnapshotStream.tsx index ecf62d382..c911232de 100644 --- a/src/renderHookToSnapshotStream.tsx +++ b/src/renderHookToSnapshotStream.tsx @@ -41,11 +41,21 @@ export interface SnapshotStream extends Assertable { * Does not advance the render iterator. */ waitForNextSnapshot(options?: NextRenderOptions): Promise - rerender: (rerenderCallbackProps: Props) => Promise + rerender: (rerenderCallbackProps: VoidOptionalArg) => Promise unmount: () => void } -export async function renderHookToSnapshotStream( +/** + * if `Arg` can be `undefined`, replace it with `void` to make type represent an optional argument in a function argument position + */ +type VoidOptionalArg = 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( renderCallback: (props: Props) => ReturnValue, {initialProps, ...renderOptions}: RenderHookOptions = {}, ): Promise> { @@ -61,8 +71,9 @@ export async function renderHookToSnapshotStream( renderOptions, ) - function rerender(rerenderCallbackProps: Props) { - return baseRerender() + function rerender(rerenderCallbackProps: VoidOptionalArg) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + return baseRerender() } return {