Unit testing React components without a DOM(simonsmith.io)
simonsmith.io
Unit testing React components without a DOM
http://simonsmith.io/unit-testing-react-components-without-a-dom/
4 comments
> Break down your React rendering into two steps: "state->JSON", then "JSON->DOM".
Er… that's exactly how React works in the first place, your "JSON" is react's "VDOM". The point of the shallow renderer is to perform a single level of rendering rather than recursively rendering all components to the final VDOM (so sub-components will appear as sub-components, not as their rendered vdom)
Er… that's exactly how React works in the first place, your "JSON" is react's "VDOM". The point of the shallow renderer is to perform a single level of rendering rather than recursively rendering all components to the final VDOM (so sub-components will appear as sub-components, not as their rendered vdom)
He means to preprocess your props+state into a simple dictionary, so that you have moved 90% of logic from `render()` to a different, more testable function.
I think the JSON that drcode describes doesn't need to be DOM-like - it doesn't need to contain spans, divs etc. Look at the example he gave.
Could you give an example of this? Looking at my code it appears that the JSON would usually be the same as this.props (as long as the component is stateless).
Now there are some components which derive other properties in render(), but the majority of code in that method tends to be JSX (calls to React.createElement()).
Now there are some components which derive other properties in render(), but the majority of code in that method tends to be JSX (calls to React.createElement()).
Right, so let's say your state looks like this:
{customers:[{name:"bob",age:21,id:345},{name:"lisa",age:22,id:2992}],selected_customer:345}
Now, in this UI if "bob" is selected that's all you see. So the intermediary JSON looks like this:
{customer:{name:"bob",age:21}}
Since neither the internal UI, the full customer list, nor the selection cursor are visible at this point in the UI, all that info can be preprocessed and omitted, leaving only the bare UI-relevant information.
You are right though, many people use "props" in a way that overlaps with what I'm proposing... If you were to write an app where 100% of data is stuffed into props for all components (including the root component) with no direct reference to the state, it would be similar to my suggested approach.
{customers:[{name:"bob",age:21,id:345},{name:"lisa",age:22,id:2992}],selected_customer:345}
Now, in this UI if "bob" is selected that's all you see. So the intermediary JSON looks like this:
{customer:{name:"bob",age:21}}
Since neither the internal UI, the full customer list, nor the selection cursor are visible at this point in the UI, all that info can be preprocessed and omitted, leaving only the bare UI-relevant information.
You are right though, many people use "props" in a way that overlaps with what I'm proposing... If you were to write an app where 100% of data is stuffed into props for all components (including the root component) with no direct reference to the state, it would be similar to my suggested approach.
Ah, OK, thanks. Although all my components below the top level receive everything as props rather than referencing the application state directly, I do have cases where some props may or may not be used depending on whether some UI is visible. I've thought maybe it means I should break up those components into sub-components but your suggestion might be a good alternative.
What you call JSON is what I've usually heard called a ViewModel: a logical representation of the state of your view. I've found it very useful as well.
Well, isn't the idea of those vDOM toolkits (like React) to be that "JSON description"?
As an old interlopers.net member it's been really fun to keep happening upon these little gem articles by Simon recently. This looks very interesting!
Simon, if you read this I regularly have the lyrics to one of your ancient tunes pop into my head to this day. Stephen Hawking Need Not Apply.
Simon, if you read this I regularly have the lyrics to one of your ancient tunes pop into my head to this day. Stephen Hawking Need Not Apply.
Thanks for this. Noticed whilst testing that renderIntoDocument in ReactTestUtils doesn't even render the ReactComponent into the DOM either and is due to be renamed. [1] Shallow rendering looks like the correctly renamed approach... I'll be updating my tests accordingly.
[1] https://github.com/facebook/react/blob/master/src/test/React...
[1] https://github.com/facebook/react/blob/master/src/test/React...
How would you handle dom events with this method (such as click, hover etc.)?
There is a simulate event method in React TestUtils: https://facebook.github.io/react/docs/test-utils.html
So basically, try to come up with a JSON description for your UI that answers the question "If I created a UI that only consisted of JSON, but had the same information as my DOM UI, what would it look like?"
Chances are, 80% of your rendering code will be in the "state->JSON" part, and that part of the code is SUPER easy to unit test.
Plus, when the day comes you want to adopt ReactNative, you already have the perfect in-between data structures to add this, you simply need to write some extra JSON->Native code.