React-testing-library: How to do Custom Render with typescript

Created on 9 Apr 2020  路  5Comments  路  Source: testing-library/react-testing-library

I want an instruction for custom render with typescript

This is the doc for custom render: https://testing-library.com/docs/react-testing-library/setup#custom-render. But no typescript version. I don't know what is the wrapper's type.

Most helpful comment

I've been trying to solve this all day and just came across this. An example for future readers:

function wrappedRender(
  ui: ReactElement,
  options?: CustomOptions
): CustomRenderResult {
  // Wrap dispatch in a mock so it can be spied on.
  const store = createStore(rootReducer, options?.state);
  store.dispatch = jest.fn(store.dispatch);

  function AllProviders({ children }: AllProvidersProps): ReactElement {
    return (
      <Provider store={store}>
        {children}
      </Provider>
    );
  }

  const returns = render(ui, {
    wrapper: AllProviders as ComponentType,
    ...options,
  });

  return { store, ...returns };
}

The key part being wrapper: AllProviders as ComponentType at the end.

All 5 comments

Hi there @ZhouHansen,

If you look at this line, you'll see its type: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/testing-library__react/index.d.ts#L37

Does it make sense now?

I've been trying to solve this all day and just came across this. An example for future readers:

function wrappedRender(
  ui: ReactElement,
  options?: CustomOptions
): CustomRenderResult {
  // Wrap dispatch in a mock so it can be spied on.
  const store = createStore(rootReducer, options?.state);
  store.dispatch = jest.fn(store.dispatch);

  function AllProviders({ children }: AllProvidersProps): ReactElement {
    return (
      <Provider store={store}>
        {children}
      </Provider>
    );
  }

  const returns = render(ui, {
    wrapper: AllProviders as ComponentType,
    ...options,
  });

  return { store, ...returns };
}

The key part being wrapper: AllProviders as ComponentType at the end.

I had to do something very similar or I get an error.

type TableProps = {
  children: NonNullable<React.ReactNode>;
};

function Table({ children }: TableProps) {
  return (
    <table>
      <tbody>{children}</tbody>
    </table>
  );
}

describe('row component', () => {
  it('displays a row cells', () => {
    const { getByText } = render(<tr><td>hello</td></tr>, {
      wrapper: Table as React.FunctionComponent,
    });

    expect(getByText('hello')).toBeTruthy();
  });
});

Error

error TS2769: No overload matches this call.
  Overload 1 of 2, '(ui: ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)>, options?: Pick<...> | undefined): RenderResult<...>', gave the following error.
    Type '({ children }: TableProps) => Element' is not assignable to type 'ComponentClass<{}, any> | FunctionComponent<{}> | undefined'.
      Type '({ children }: TableProps) => Element' is not assignable to type 'FunctionComponent<{}>'.
        Types of parameters '__0' and 'props' are incompatible.
          Type '{ children?: ReactNode; }' is not assignable to type 'TableProps'.
            Types of property 'children' are incompatible.
              Type 'ReactNode' is not assignable to type 'string | number | boolean | {} | ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)> | ReactNodeArray | ReactPortal'.
                Type 'undefined' is not assignable to type 'string | number | boolean | {} | ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)> | ReactNodeArray | ReactPortal'.
  Overload 2 of 2, '(ui: ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)>, options: RenderOptions<...>): RenderResult<...>', gave the following error.
    Type '({ children }: TableProps) => Element' is not assignable to type 'ComponentClass<{}, any> | FunctionComponent<{}> | undefined'.
      Type '({ children }: TableProps) => Element' is not assignable to type 'FunctionComponent<{}>'.

34       wrapper: Table,
         ~~~~~~~

In the example above I think it would be easier to do the following, which leads to no typecasting:

import React from "react";

const Table: React.ComponentType = ({ children }) => {
  return (
    <table>
      <tbody>{children}</tbody>
    </table>
  );
}

describe('row component', () => {
  it('displays a row cells', () => {
    const { getByText } = render(<tr><td>hello</td></tr>, {
      wrapper: Table,
    });

    expect(getByText('hello')).toBeTruthy();
  });

Looks like we've got solutions and there's nothing we can do in this repo to help further so I'll close this. Thanks!

Was this page helpful?
0 / 5 - 0 ratings