testing-library / react-testing-library

🐐 Simple and complete React DOM testing utilities that encourage good testing practices.
https://testing-library.com/react
MIT License
18.94k stars 1.1k forks source link

`RenderHookResult` doesn't match return value of `renderHook` #1113

Closed mattbrandlysonos closed 1 year ago

mattbrandlysonos commented 2 years ago

Relevant code or config:

If I write a small renderHook test and log the result.current value immediately after calling renderHook, this will show that the value is null.

const { result } = renderHook(() => useMyHook())
console.log(result.current) // => null

According to the provided RenderHookResult type, that value should be of type Result, but null is not a valid instance of type Result.

https://github.com/testing-library/react-testing-library/blob/c80809a956b0b9f3289c4a6fa8b5e8cc72d6ef6d/types/index.d.ts#L101-L114

Suggested solution:

Either the type could be updated:

current: Result | null

Or the renderHook implementation could change such that it synchronously returns a value of type Result.

eps1lon commented 2 years ago

It doesn't look like this bug report has enough info for one of us to reproduce it.

Please provide a CodeSandbox (https://react.new), or a link to a repository on GitHub.

Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve

ntucker commented 1 year ago

@eps1lon This happens if there's an act call within the hook call stack.

E.g.,

const { result } = renderHook(() => {
  act(() => {});
  return { data: 1 };
});
// this is true, but probably shouldn't be
result.current === null;

https://codesandbox.io/s/gifted-fire-n8scc9?file=/index.test.js

I don't know how to turn this sandbox into a test runner as it tries to run react in the window instead.

eps1lon commented 1 year ago

@ntucker Calling act within a hook is a bit odd considering act is a testing utility. It doesn't even work in production.

I'll try to figure out why it behaves at runtime like this. Ideally, we'd warn about it I think.

Could you elaborate why you're using act inside a hook?

ntucker commented 1 year ago

Could you elaborate why you're using act inside a hook?

Async callstack (say a network response) triggering setstate. Since it's async the test itself cannot be inlining the act call. This is achieved to only occur during tests as the test setup has dependency injection

eps1lon commented 1 year ago

Could you give a complete example for this? I don't really see why the nested act is required as opposed to waiting with e.g. waitFor

ntucker commented 1 year ago

According to https://reactjs.org/docs/test-utils.html#act it "This makes your test run closer to how React works in the browser." I don't really know what that means, but I assume that means it flushes the macro task buffer for batched renders. Without it the react updates don't happen.

eps1lon commented 1 year ago

Closing since this is unrelated to types and you don't need to run act inside hooks (since it's a dev-only tool).