testing-library/testing-library-docs

Rerender with a wrapper

lithin opened this issue · 1 comments

  • @testing-library/react version: 13.4.0
  • Testing Framework and version: jest @ 29.0.3
  • DOM Environment: jsdom @ 20.0.0

Relevant code or config:

// in test utils
const customRender = (
  ui: ReactElement,
  apolloMocks?: ApolloMocks,
  options?: Omit<RenderOptions, 'wrapper'>
) =>
  render(ui, {
    wrapper: () => ui, // this would include our providers wrapped around ui but this demonstrates the issue in a cleaner way
    ...options,
  });

// in test file

const Comp = ({ number }: { number: number }) => <p>{number}</p>;

it('check render', () => {
    const { rerender } = customRender(<Comp number={1} />);
    rerender(<Comp number={2} />);
    expect(screen.getByText('2')).toBeInTheDocument();
  });

What you did:

Rerendering a component that was originally rendered out with the wrapper option, combining two different guides in the docs.

What happened:

No props are updated. The component does rerender, however it does so with the "old" props. (So in the example above, the test fails because 1 is present instead of 2.)

Reproduction:

Happy to add this if necessary.

Problem description:

We can't actually re-render stuff :) The workaround we're using is to put the wrapper directly into the test but that sort of defeats having any wrapper to begin with.

Suggested solution:

Not sure how the internals work and why the wrapper would interfere with the props. I imagine we'd need to see why the props aren't being passed correctly and fix it on that level.

Note the

render(ui, {
    wrapper: () => ui,

This means that your wrapper will always render the initial element not the element given to rerender.

Remember that wrapper is treated as a normal React component. What happens internally is just normal React:

<Wrapper>
{element}
</Wrapper>

But in your example element will always be the initial ui.

What you want instead is

render(ui, {
    wrapper: (props) => props.children,

children will be what you give to render(children) and rerender(children).

I'll move this to the docs to add an example that highlights the importance of handling children.