Re:Unit testing React components without a DOM
by drcode on Monday June 15, 2015 @09:57AM
(#9719274)
Though OP's approach has definite use cases, I'd recommend another approach in most instances: Break down your React rendering into two steps: "state->JSON", then "JSON->DOM".
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.
Re:Unit testing React components without a DOM
by masklinn on Monday June 15, 2015 @12:01PM
(#9720183)
> 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)
Re:Unit testing React components without a DOM
by zenojevski on Monday June 15, 2015 @12:07PM
(#9720233)
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.
Re:Unit testing React components without a DOM
by guscost on Monday June 15, 2015 @11:54AM
(#9720136)
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, 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.
Re:Unit testing React components without a DOM
by guscost on Monday June 15, 2015 @01:05PM
(#9720606)
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.
Re:Unit testing React components without a DOM
by curveship on Monday June 15, 2015 @12:57PM
(#9720561)
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.
Re:Unit testing React components without a DOM
by GordyMD on Monday June 15, 2015 @10:06AM
(#9719319)
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.
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.
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)
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()).
{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.
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.
[1] https://github.com/facebook/react/blob/master/src/test/React...