react-hooks-testing-library version: 3.2.1react-test-renderer version: 16.9.0react version: 16.9.0node version: 12.9.0npm (or yarn) version: yarn v1.21.1// test.js
import React from "react"
window.doSomethingWithThisDiv = element => {
const newEl = document.createElement("div")
newEl.innerText = "hello world"
element.appendChild(newEl)
}
const context = React.createContext(null)
export const Provider = ({ children }) => {
const myRef = React.useRef(null)
const [showDiv, setShowDiv] = React.useState(false)
const contextValue = React.useMemo(() => {
return {
showDiv,
setShowDiv
}
}, [showDiv, setShowDiv])
React.useEffect(() => {
if (showDiv) {
window.doSomethingWithThisDiv(myRef.current)
}
}, [showDiv])
return (
<context.Provider value={contextValue}>
{showDiv && <div ref={myRef} />}
{children}
</context.Provider>
)
}
export const useTest = () => {
return React.useContext(context)
}
// test.spec.js
import React from "react"
import sinon from "sinon"
import { renderHook } from "@testing-library/react-hooks"
import { Provider, useTest } from "test"
describe("testing context", () => {
it("works", () => {
const spy = sinon.spy(window, "doSomethingWithThisDiv")
const { result } = renderHook(useTest, {
wrapper: ({ children }) => <Provider>{children}</Provider>
})
result.current.setShowDiv(true)
expect(spy.callCount).to.equal(1)
})
})
NODE_ENV=test mocha --opts path/to/opts test.spec.js
Error message due to the ref being null in the effect in test.js
warning Error: Uncaught [TypeError: Cannot read property 'appendChild' of null]
See the code snippets above
Apologies for the super contrived example, but I was luckily able to reproduce the same issue I am seeing in my much more complicated application. Basically I am testing some features of a React context which exposes some state and an API to interact with that data. I am doing so by testing a custom hook which exposes the context to its users. In the Provider, in addition to the children it renders, there is some conditional UI which renders when some state is set to true, this particular div is assigned a ref so that it can be referenced later in an effect (in my real application I mount a sign in widget to this div from a third party identity provider). What is weird is that when I run this example live, I can see the ref is set just fine, but when running the unit tests the ref's value is always null even when the state is set to true.
Hi @E-Kuerschner,
Thanks for taking the time to raise this.
This had me stumped for a while as I it all looked right to me but it was very clearly never setting the ref when rendering. I managed to trace it to a relatively old (likely predating the current ref API) issue with react-test-renderer, where the takeaway is that because there is no DOM that the component gets rendered into, there is nothing for the ref to be set to. While this is annoying it does sort of make sense to me.
The issue goes on to mention a workaround that doesn't help you very much because you have no control over what we pass to react-test-renderer internally.
So where to from here? Well, you could not use this library for testing your hook and use @testing-library/react instead by creating a small test component and use it to render it instead. Given _most_ of the login appears to be in the Provider, this might be the best approach anyway.
Alternatively, there is an in progress PR (which I admittedly haven't touched in a while), for adding the ability to use react-dom to render instead of react-test-renderer, so you might consider holding out for that. (The quickest way to get that moving is to jump into the PR and/or the issues it mentions and give me feedback and encouragement that it is actually useful to someone)
Finally, we _could_ provide an option to allow setting the options when rendering to provide something to createNodeMock, but I'm not sure what that would look like right now and given the PR mentioned above, it's unlikely to be removed after that change goes in anyway.
@mpeyper thanks for the information. Seems like a lot going on. I agree with you that my best option is to probably not use this library to test my scenario for now. However, the ability to use react-dom as a render sounds like an interesting option to have. I may consider looking into that PR when I have some time to see if there is anything that I could do to help.
Feel free to close this or link it to that PR you have open now.