-
Notifications
You must be signed in to change notification settings - Fork 273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[renderHook] Passing rerender props to the wrapper #1514
Comments
Hello @udeyrishi ! I don't really understand the implementation, passing hook props to the wrapper does not make sense to me, it feels a bit hacky. Maybe we could add another option for wrapper props, I think it would make more sense. That being said I'm not really convinced this feature is needed, do you have a use case for it? I wonder if for such scenarios you could consider writing a test on a component instead |
I agree that that API choice would be cleaner. I was just referring to the existing/related implementation, since this felt like a functionality regression. If I were to start from scratch, then yeah I agree that what you suggested is a better choice.
My use case is to do some assertions on a hook's result, based on a re-render triggered by a wrapping context's value. It's not far off from the example shared in testing-library/react-hooks-testing-library#322. I've tried simplifying my specific use-case by stripping out some business details: // Is there a cleaner way to accomplish this?
type WrapperPropValue = {
foo: number
}
const setup = (initialWrapperPropValue: WrapperPropValue) => {
let updateWrapperPropValue:
| ((_: WrapperPropValue) => void)
| undefined;
const Wrapper: FC<PropsWithChildren> = ({ children }) => {
const [wrapperPropValue, setWrapperPropValue] = useState(initialWrapperPropValue);
useEffect(() => {
updateWrapperPropValue = setWrapperPropValue;
return () => {
updateWrapperPropValue = undefined;
};
}, []);
return <SomeHookWrapper somePropThatNeedsToChange={wrapperPropValue}>{children}</SomeHookWrapper>;
};
const safeUpdateWrapperPropValue = (
updatedWrapperPropValue: WrapperPropValue,
) => {
void act(() => {
updateWrapperPropValue?.(updatedWrapperPropValue);
});
};
const utils = renderHook(useSomeSubjectHook, {
wrapper: Wrapper,
});
return {
...utils,
safeUpdateWrapperPropValue,
};
};
it('do some assertions after context change', () => {
const { result, safeUpdateWrapperPropValue } = setup({foo: 1})
// do assertions on result
safeUpdateWrapperPropValue({foo : 2})
// do assertions on updated result
}) |
It's kind of hard to tell without knowing what the context or the hook do but ideally you'd want to write a test from a users's perspective so trigger an update of the provider's value through a user interaction and do assertions on something visible by the user. I don't know how hard it is to do that in your case though but that would be a more robust test as it would not depend on implementation details and maybe it would be simpler than what you currently have. If you can't easily trigger an update on the provider you could write a test component that would be you wrapper and the component that uses the hook and then rerender that component, it would look like this: const TestComponent = ({providerValue}: {providerValue: ContextValue }) => {
return (<ContextProvider value={providerValue}>
<ComponentThatUsesTheHook />
</ContextProvider value={providerValue}>);
}
test('name of the test', () => {
render(<TestComponent value={initialValue} />);
// do some assertions
screen.rerender(<TestComponent value={newValue} />);
// assert hook did what it was supposed to do
}); |
I understand that intention behind that recommendation, and completely agree with it. However, in my specific use case, I'm trying to write a unit test for 1 specific reusable hook, and verify that it behaves as expected as long as the other connected units do their job. It's not intended to be an integration test.
Yeah that's what I'm doing in the example that I shared above as well--in essence at least. The difference is that in the version that you shared, we'll need to define a |
I understand your point, it's not very elegant indeed. We might add support for the |
@udeyrishi could you briefly describe the change you are proposing in terms of API so that I can understand it better. I got confused by the idea of passing To give you context about our implementation of |
@mdjastrzebski All I need is for some way to send initial and updated props to the wrapper as part of the
I'd imagine it'd look something like this: test('some test', () => {
const { rerender } = renderHook(useMyHook, {
initialProps: { propPassedToHook: 'foo' },
wrapper: ({ children, /** API addition **/ someWrapperProp }) => <SomeWrapper someWrapperProp={someWrapperProp}>{children}</SomeWrapper>,
/** API addition **/ initialWrapperProps: { someWrapperProp: 'bar' }
});
rerender(
{ propPassedToHook: 'foo-updated' },
/** API addition **/ { someWrapperProp: 'bar-updated' },
);
}); This example has these new API additions that don't exist today:
That being said, I was simply pointing to this ticket as a reference, because the same problem was previously solved via a different API approach (which is not as explicit as the one I'm proposing above IMHO). That's an alternative that I'd be happy with as well. I assume that behaviour was removed as part of the "slimming down" process. |
Indeed it seems that RHTL has this "feature" that hook props would be passed to TBH I find this quite strange to mix hook and wrapper props as they are not the same thing. @udeyrishi If you want my personal opinion, I think we should keep the current RTL-based implementation. That implementation seems to be ironed out in a lengthy discussion in their repo. One of our goals in RNTL is to stay compatible with RTL when possible and deviate only when we are compelled by significant value of such decision. By re-using large parts of their code we save time and can focus our modest resources on high impact initiatives like User Event or semantic (a11y) queries. Since this seems to be a rather niche feature, I think the complication to the codebase and API surface is not the right tradeoff here. Could I suggest you check following pattern presented in that discussion:
Let me know how that works for you. |
Fair enough, I understand the desire for RNTL to stay close to RTL to save on maintainence cost. I haven't read that linked discussion fully to understand why this "feature" was dropped, or whether it was intentional vs. accidental; regardless, I think my request would probably need to originate on the RTL side then. This is a niche request indeed, and there are workarounds (3 discussed in this ticket) that let me accomplish the goal for now, so this is a task for some other time. I appreciate your responsiveness, and grace to entertain this random dev on the internet 🙏🏼 |
Describe the Feature
I noticed this change in the legacy
react-hooks-testing-library
version ofrenderHook
, whereby the props sent to thererender
function were also sent to any provided custom wrapper. However, I'm noticing that the@testing-library/react-native
version of therenderHook
util does not have this feature. Not sure if this is a bug or a feature request, so decided to just log this to get the conversation going.Possible Implementations
Similar to testing-library/react-hooks-testing-library#381
Related Issues
testing-library/react-hooks-testing-library#322
The text was updated successfully, but these errors were encountered: