testing-library/react-hooks-testing-library

Package to support React 18

snowystinger opened this issue · 18 comments

Describe the feature you'd like:

React 18 alpha is out, our library is starting to determine what we'll need to do to support it. We use this library for tests and I don't see an issue for it already nor do I see a PR for it.

Suggested implementation:

I think just changing over to create is most of the work reactwg/react-18#5
I don't know if this would need the work that Testing Library is doing as well for concurrent mode, I don't know enough about how that works with this. testing-library/react-testing-library#937

We did have #217 raised at one point but to be honest I'm not sure how much we'll need to do for concurrent mode as we already support suspense so, and my naive understanding of how it all fits together may be showing here, if we can support rendering with ReactDOM. createRoot instead of ReactDOM.render, then it should be all that's needed?

I think we should continue any discussions in #655 than here so we can see where the issues are when the code is updated.

I need to confirm my lib works properly with strict effects. Right now, only @testing-library/react@alpha supports it.

// pass
import { act, render } from '@testing-library/react'; // @testing-library/react@13.0.0-alpha.5
import { StrictMode, useEffect } from 'react';

const Foo = (props: { log: () => void; effect: () => void; clean: () => void }) => {
  props.log();
  useEffect(() => {
    props.effect();
    return props.clean;
  });
  return null;
};

describe('test renderer', function () {
  it('should be in strict mode', function () {
    const fn = jest.fn();
    const effect = jest.fn();
    const clean = jest.fn();
    const {unmount} = render(
      <StrictMode>
        <Foo log={fn} effect={effect} clean={clean}/>
      </StrictMode>,
    );
      expect(fn).toHaveBeenCalledTimes(2);
      expect(effect).toHaveBeenCalledTimes(2);
      expect(clean).toHaveBeenCalledTimes(1);
      act(() => {
          unmount();
      });
      expect(clean).toHaveBeenCalledTimes(2);
  });
});
import { act, renderHook } from '@testing-library/react-hooks'; // @7.0.2 or @8.0.0-alpha.1
import React, { StrictMode, useEffect } from 'react';

describe('test renderer', function () {
  it('should be in strict mode', function () {
    const fn = jest.fn();
    const effect = jest.fn();
    const clean = jest.fn();
    const { unmount } = renderHook(
      () => {
        fn();
        useEffect(() => {
          effect();
          return clean;
        });
      },
      { wrapper: StrictMode },
    );
    expect(fn).toHaveBeenCalledTimes(2);
    expect(effect).toHaveBeenCalledTimes(2); // fail: Received number of calls: 1
    expect(clean).toHaveBeenCalledTimes(1);
    act(() => {
      unmount();
    });
    expect(clean).toHaveBeenCalledTimes(2);
  });
});

Hi @smmoosavi,

@testing-library/react@alpha should have it's own renderHook export now that supports react 18 features. Please try it out but let us know if there are any issues.

Hi,
The testing-library/react-testing-library#991 is not merged yet, so I created my own renderHook inside my lib until merge of 991.

It enables strict mode by default and has better typescript types.

React 18 has now officially been released: https://reactjs.org/blog/2022/03/29/react-v18.html

Now that react 18 is out this package doesn't work any longer because of peer dependencies supporting react 17 as the latest.

There's #655 still open, suggesting that with react 18 out, RTL should have already had a renderHook function available, but this doesn't seem to be the case. See testing-library/react-testing-library#991.

How are people handling this?

Hey @simoneb,

I’ve closed that PR now to help remove the confusion about what we are doing. The official position of this library is that we are expecting the RTL and RNTL to take over the renderHook API, but you are correct, neither have actually merged their PRs yet. I know RNTL is waiting for RTL to merge theirs first, but I’m not sure what is holding up RTL from moving forward with it (considering how adamant they were that it was going to be the path forward).

As for how to handle this, I’d suggest currently the only option, if waiting is unacceptable, is to copy the implementation in the RTL PR into your project and use that until the official version is released. It’s a very thin layer over RTL so there would be very little risk of incompatibilities or massive API changes making moving over after release difficult.

function renderHook(renderCallback, options = {}) {
  const {initialProps, wrapper} = options
  const result = React.createRef()

  function TestComponent({renderCallbackProps}) {
    const pendingResult = renderCallback(renderCallbackProps)

    React.useEffect(() => {
      result.current = pendingResult
    })

    return null
  }

  const {rerender: baseRerender, unmount} = render(
    <TestComponent renderCallbackProps={initialProps} />,
    {wrapper},
  )

  function rerender(rerenderCallbackProps) {
    return baseRerender(
      <TestComponent renderCallbackProps={rerenderCallbackProps} />,
    )
  }

  return {result, rerender, unmount}
}

I do understand that this is less than ideal, but I appreciate everyone’s patience as we make this transition.

@mpeyper thanks for the detailed answer!

The release of @testing-library/react version 13.1.0 includes the renderHook API. Please migrate to that for React 18 support now if you are testing for react-dom.

Any chance the RenderHookResult type is in there? This is a helpful type that gets exported in @testing-library/react-hooks. I don't see it exported in @testing-library/react.

@mpeyper Correct. It's not exported and it looks to be an altogether different type (interface) than this one.

Ah yes, I missed that detail. Please open an issue in RTL and consider making a PR to resolve it.

As for type vs interface, it’s likely that using interface is more consistent with their type defs. If the difference is problematic for you, please add that detail to the issue/PR.

My current problem is that the renderHook from @testing-library/react is not supporting the waitForNextUpdate method I require. Is there any help on that?

My current problem is that the renderHook from @testing-library/react is not supporting the waitForNextUpdate method I require. Is there any help on that?

You'd have to take it up with @testing-library/react but we tried to in the initial implementation, this was the response testing-library/react-testing-library#991 (comment)

Guys,

Are there any plans for support the renderHook into Server-Side Rendering? 🥺

Guys,

Are there any plans for support the renderHook into Server-Side Rendering? 🥺

@drianoaz this should be asked in a new issue please, this is not relate to react-18.

Infact, I'm going to lock this issue, if you want to see the discussion with RTL then here's the PR – testing-library/react-testing-library#991 this is the direction that the library is going in (as seen on the README).

Any issues related to anything else should be a new one please.