DEV Community

kasper573
kasper573

Posted on • Updated on

Simulate React fast-refresh in automated tests

I needed to do this today and found this topic, which didn't make me much wiser. Since I found no documentation on how to test react-refresh, I checked out the react-refresh test suite and started reverse engineering. Took me a while to figure the ins and outs of it, but I managed to make it work eventually, even while using testing-library (the react-refresh test suite was not using testing-library). Here's my implementation:

https://github.com/kasper573/yas/blob/194f87e433bfc924b66969a3283376e3d1c90562/packages/react-composable-form/src/__test__/reactFastRefresh.test.tsx

It was an interesting day of reverse engineering. I wish there was more docs about this, so I'll share my work and some thoughts in case someone else needs to work with this:
Using react-refresh/runtime to simulate react-refresh in your tests is brittle

To properly make your tests mimic how react-refresh works in a development server you need to be intimately aware with how react-refresh actually utilizes its runtime functions. If you don't do it exactly right, you will get false positives (or negatives). I stuggled with this a lot until I got it to work.

Make sure you call RefreshRuntime.register for each component in the component tree that you pass to testing-library/render, not just the root component.

It was not clear to me that this was a requirement when I looked through the react-refresh test suite, but I learned that this is how react-refresh works by booting up vite with react and testing a number of fast refreshes and inspecting the network tab in my dev tools to see what the actual javascript that was being sent on each update looked like. There I could observe that indeed every component in the updated module got picked up by react-refresh and had its own RefreshRuntime.register call added.

Ideas for a less brittle end-to-end test approach

I only needed a few simple tests, so using react-refresh/runtime in jest was a good trade-off for me. But I considered the idea of using playwright instead and test against a dev server with react-refresh enabled, and have my tests actually emulate the developer process by making code changes to the files being served by vite, and trigger fast refresh that way instead. This approach would avoid needing to replicate the implementation details of react-refresh, which would make the tests way less brittle. If I were to do this whole thing again, or if I needed to write a much larget test suite, I'd definitely try the playwright approach instead.

Top comments (0)