Closed StefanoDeVuono closed 3 years ago
If the test is timing out, that suggests that there are no state updates to trigger the hook to rerender. How many times does this log "renderer"?
const { waitForNextUpdate, result } = renderHook(() => {
console.log("rendered")
return useStripe()
}, {
wrapper,
})
You could also try using waitFor
which is less prone to errors when the number of renders required to reach the desierd state changes:
const { waitFor, result } = renderHook(() => useStripe(), {
wrapper,
})
await waitFor(() => result.current !== null)
expect(result.current).not.toBeNull() // or asserting the value you expect to be here instead
Thank you for your help! This is a great suggestion. Here are my findings
renderHook
doesn't log when using waitFor
:
const { waitFor, result } = renderHook(() => {
console.log('rendered')
return useStripe()
},
{ wrapper }
)
await waitFor(() => result.current !== null)
renderHook
doesn't log when using waitForNextUpdate
:
const { waitForNextUpdate, result } = renderHook(() => {
console.log('rendered')
return useStripe()
}, {
wrapper,
})
await waitForNextUpdate()
I think that's the crux of the problem. If I put console.log('render CheckoutForm')
in my CheckoutForm.js, it shows it's rendering twice in the browser and only once in my test. Digging deeper into the Elements.tsx file of Stripe, I see that it takes the stripe promise and sets the context once the promise is resolved if stripe
is available and isMounted.current
is truthy:
// from Elements.tsx
parsed.stripePromise.then(function (stripe) {
if (stripe && isMounted.current) {
// Only update Elements context if the component is still mounted
// and stripe is not null. We allow stripe to be null to make
// handling SSR easier.
setContext({
stripe: stripe,
elements: stripe.elements(options)
});
}
});
When I debug the test, I see that the parsed.stripePromise
object exists as a promise and , but the callback never executes. Is renderHook
throwing away my Element
component before it has a chance to resolve the promise within it?
No, renderHook
doesn't throw anything away. I've just noticed that App
does not render children
at all, so const wrapper = ({ children }) => <App>{children}</App>
is not going to work in this case. I think you want o be doing something like this:
const wrapper = ({ children }) => <Elements stripe={mockedStripePromise}>{children}</Elements>
Unless your intention is actually not to be testing useStripe
(which would make sense not to test a third party hook) but rather to test your App
or CheckoutForm
components. If that's the case then you are using the wrong library and should just be using @testing-library/react
and rendering the component.
@StefanoDeVuono , have you ever got to resolve this issue? I could really use some help here. Exact same issue here, i don't get stripe
, seems like the Promise never resolves.
Hey @Natalia504, if you share some more details about your test and hook code I’m happy to take a look and see if anything stands out. Perhaps consider raising a new issue so we don’t keep notifying others with it though.
I'm testing a hook that calls methods on the
stripe
object returned by theuseStripe()
hook. As such, I'm trying to retrieve thestripe
object fromuseStripe()
.The problem is the context it's provided from gets a promise which later resolves. So
useStripe
starts by returningnull
and then returns astripe
objectHere's the provider:
And here's my test
No dice. The test just times out. Any ideas?