From 2c673a780f0302025f9924dcafbef177867964c2 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Thu, 25 Apr 2024 01:29:25 +0200 Subject: [PATCH] Stop restricting `container` option based on `hydrate` --- types/index.d.ts | 131 +++++++++++++++++++++-------------------------- types/test.tsx | 26 ++++++++-- 2 files changed, 79 insertions(+), 78 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 78302693..b200841c 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -43,10 +43,48 @@ export type RenderResult< asFragment: () => DocumentFragment } & {[P in keyof Q]: BoundFunction} -export interface BaseRenderOptions< +/** @deprecated */ +export type BaseRenderOptions< Q extends Queries, Container extends RendererableContainer | HydrateableContainer, BaseElement extends Element | DocumentFragment, +> = RenderOptions + +type RendererableContainer = ReactDOMClient.Container +type HydrateableContainer = Parameters[0] +/** @deprecated */ +export interface ClientRenderOptions< + Q extends Queries, + Container extends Element | DocumentFragment, + BaseElement extends Element | DocumentFragment = Container, +> extends BaseRenderOptions { + /** + * If `hydrate` is set to `true`, then it will render with `ReactDOM.hydrate`. This may be useful if you are using server-side + * rendering and use ReactDOM.hydrate to mount your components. + * + * @see https://testing-library.com/docs/react-testing-library/api/#hydrate) + */ + hydrate?: false | undefined +} +/** @deprecated */ +export interface HydrateOptions< + Q extends Queries, + Container extends Element | DocumentFragment, + BaseElement extends Element | DocumentFragment = Container, +> extends BaseRenderOptions { + /** + * If `hydrate` is set to `true`, then it will render with `ReactDOM.hydrate`. This may be useful if you are using server-side + * rendering and use ReactDOM.hydrate to mount your components. + * + * @see https://testing-library.com/docs/react-testing-library/api/#hydrate) + */ + hydrate: true +} + +export interface RenderOptions< + Q extends Queries = typeof queries, + Container extends RendererableContainer | HydrateableContainer = HTMLElement, + BaseElement extends Element | DocumentFragment = Container, > { /** * By default, React Testing Library will create a div and append that div to the document.body. Your React component will be rendered in the created div. If you provide your own HTMLElement container via this option, @@ -93,44 +131,6 @@ export interface BaseRenderOptions< wrapper?: React.JSXElementConstructor<{children: React.ReactNode}> } -type RendererableContainer = ReactDOMClient.Container -type HydrateableContainer = Parameters[0] -export interface ClientRenderOptions< - Q extends Queries, - Container extends Element | DocumentFragment, - BaseElement extends Element | DocumentFragment = Container, -> extends BaseRenderOptions { - /** - * If `hydrate` is set to `true`, then it will render with `ReactDOM.hydrate`. This may be useful if you are using server-side - * rendering and use ReactDOM.hydrate to mount your components. - * - * @see https://testing-library.com/docs/react-testing-library/api/#hydrate) - */ - hydrate?: false | undefined -} - -export interface HydrateOptions< - Q extends Queries, - Container extends Element | DocumentFragment, - BaseElement extends Element | DocumentFragment = Container, -> extends BaseRenderOptions { - /** - * If `hydrate` is set to `true`, then it will render with `ReactDOM.hydrate`. This may be useful if you are using server-side - * rendering and use ReactDOM.hydrate to mount your components. - * - * @see https://testing-library.com/docs/react-testing-library/api/#hydrate) - */ - hydrate: true -} - -export type RenderOptions< - Q extends Queries = typeof queries, - Container extends RendererableContainer | HydrateableContainer = HTMLElement, - BaseElement extends Element | DocumentFragment = Container, -> = - | ClientRenderOptions - | HydrateOptions - type Omit = Pick> /** @@ -138,19 +138,11 @@ type Omit = Pick> */ export function render< Q extends Queries = typeof queries, - Container extends RendererableContainer = HTMLElement, - BaseElement extends Element | DocumentFragment = Container, ->( - ui: React.ReactNode, - options: ClientRenderOptions, -): RenderResult -export function render< - Q extends Queries = typeof queries, - Container extends HydrateableContainer = HTMLElement, + Container extends RendererableContainer | HydrateableContainer = HTMLElement, BaseElement extends Element | DocumentFragment = Container, >( ui: React.ReactNode, - options: HydrateOptions, + options: RenderOptions, ): RenderResult export function render( ui: React.ReactNode, @@ -179,19 +171,15 @@ export interface RenderHookResult { unmount: () => void } -export interface BaseRenderHookOptions< +/** @deprecated */ +export type BaseRenderHookOptions< Props, Q extends Queries, Container extends RendererableContainer | HydrateableContainer, BaseElement extends Element | DocumentFragment, -> extends BaseRenderOptions { - /** - * The argument passed to the renderHook callback. Can be useful if you plan - * to use the rerender utility to change the values passed to your hook. - */ - initialProps?: Props -} +> = RenderHookOptions +/** @deprecated */ export interface ClientRenderHookOptions< Props, Q extends Queries, @@ -207,6 +195,7 @@ export interface ClientRenderHookOptions< hydrate?: false | undefined } +/** @deprecated */ export interface HydrateHookOptions< Props, Q extends Queries, @@ -222,14 +211,18 @@ export interface HydrateHookOptions< hydrate: true } -export type RenderHookOptions< +export interface RenderHookOptions< Props, Q extends Queries = typeof queries, - Container extends Element | DocumentFragment = HTMLElement, + Container extends RendererableContainer | HydrateableContainer = HTMLElement, BaseElement extends Element | DocumentFragment = Container, -> = - | ClientRenderHookOptions - | HydrateHookOptions +> extends BaseRenderOptions { + /** + * The argument passed to the renderHook callback. Can be useful if you plan + * to use the rerender utility to change the values passed to your hook. + */ + initialProps?: Props +} /** * Allows you to render a hook within a test React component without having to @@ -239,21 +232,11 @@ export function renderHook< Result, Props, Q extends Queries = typeof queries, - Container extends RendererableContainer = HTMLElement, - BaseElement extends Element | DocumentFragment = Container, ->( - render: (initialProps: Props) => Result, - options?: ClientRenderHookOptions, -): RenderHookResult -export function renderHook< - Result, - Props, - Q extends Queries = typeof queries, - Container extends HydrateableContainer = HTMLElement, + Container extends RendererableContainer | HydrateableContainer = HTMLElement, BaseElement extends Element | DocumentFragment = Container, >( render: (initialProps: Props) => Result, - options?: HydrateHookOptions, + options?: RenderHookOptions, ): RenderHookResult /** diff --git a/types/test.tsx b/types/test.tsx index 734d70e7..f8cf4aad 100644 --- a/types/test.tsx +++ b/types/test.tsx @@ -166,6 +166,24 @@ export function wrappedRenderC( return pure.render(ui, {wrapper: AppWrapperProps, ...options}) } +export function wrappedRenderHook( + hook: () => unknown, + options?: pure.RenderHookOptions, +) { + interface AppWrapperProps { + children?: React.ReactNode + userProviderProps?: {user: string} + } + const AppWrapperProps: React.FunctionComponent = ({ + children, + userProviderProps = {user: 'TypeScript'}, + }) => { + return
{children}
+ } + + return pure.renderHook(hook, {...options}) +} + export function testBaseElement() { const {baseElement: baseDefaultElement} = render(
) expectType(baseDefaultElement) @@ -213,22 +231,22 @@ export function testRenderHookProps() { export function testContainer() { render('a', {container: document.createElement('div')}) render('a', {container: document.createDocumentFragment()}) - // @ts-expect-error Only allowed in React 19 + // Only allowed in React 19 render('a', {container: document}) render('a', {container: document.createElement('div'), hydrate: true}) - // @ts-expect-error Only allowed for createRoot + // Only allowed for createRoot but typing `render` appropriately makes it harder to compose. render('a', {container: document.createDocumentFragment(), hydrate: true}) render('a', {container: document, hydrate: true}) renderHook(() => null, {container: document.createElement('div')}) renderHook(() => null, {container: document.createDocumentFragment()}) - // @ts-expect-error Only allowed in React 19 + // Only allowed in React 19 renderHook(() => null, {container: document}) renderHook(() => null, { container: document.createElement('div'), hydrate: true, }) - // @ts-expect-error Only allowed for createRoot + // Only allowed for createRoot but typing `render` appropriately makes it harder to compose. renderHook(() => null, { container: document.createDocumentFragment(), hydrate: true,