Learning testing with React, and I came across this point from this article: https://reactjs.org/docs/shallow-renderer.html
When writing unit tests for React, shallow rendering can be helpful.
Shallow rendering lets you render a component “one level deep” and
assert facts about what its render method returns, without worrying
about the behavior of child components, which are not instantiated or
rendered. This does not require a DOM.
Can someone explain the concept behind "levels deep"? Does this have any relation to objects and how many levels deep they are?
The depth of a component is the number of children and grand children it has:
const Level1Component = () => <Component /> // No children
const Level2Component = ({children}) => <Component>{children}</Component>
And if it's children have children, then it's depth = 3 and so on.
It means when testing a component with another component inside, you can just focus on the target component you want to test, and ignore the contents of it's child, grandchild, ... etc components.
For example, now I want to test a component called <ParentComponent>, which has a <ChildComponent /> inside :
<div>
<h1>Hi</h1>
<ChildComponent />
</div>
When testing with <ParentComponent />, it will not render the JSX part of <ChildComponent />, so the testing code can be more simple and pure:
import ShallowRenderer from 'react-test-renderer/shallow';
// in your test:
const renderer = new ShallowRenderer();
renderer.render(<ParentComponent />);
const result = renderer.getRenderOutput();
expect(result.type).toBe('div');
expect(result.props.children).toEqual([
<h1>Hi</h1>,
<ChildComponent /> // don't need to worry about what's inside
]);
( this example is similar to the React Doc )
It is saying you can check the state of your parent-component with out rendering your child component state/data by just rendering the component. That make sense? One-level in this case the top level / shallow.
<parent-component>
{parent-data}
<child-component-1>{child-1-data}</child-component-1>
<child-component-2>{child-2-data}</child-component-2>
</parent-component>
Related
How would you test React components that accept state hooks as properties?
For example
In the app, this ChildComponent is rendered like so:
<App>
<OtherComponent />
<div>
<ChildComponent selectedProperty={selectedProperty}
setSelectedProperty={setSelectedProperty} />
</div>
</App>
In my test, i'm trying to do this:
component = await render(
<ChildComponent selectedProperty={selectedProperty}
setSelectedProperty={setSelectedProperty} />
);
However I don't know how I would pass in these two properties selectedProperty and setSelectedProperty which in the app is handled by the parent component.
Thank you.
As a minimum example, fulfilling only the requirements you specified, this should work:
const selectedProperty = 'whatever';
const setSelectedProperty = () => {};
component = await render(
<ChildComponent selectedProperty={selectedProperty}
setSelectedProperty={setSelectedProperty} />
);
In case you need to verify that ChildComponent actually called setSelectedProperty, you can use a jest mock.
const selectedProperty = 'whatever';
const setSelectedProperty = jest.fn();
component = await render(
<ChildComponent selectedProperty={selectedProperty}
setSelectedProperty={setSelectedProperty} />
);
expect(setSelectedProperty).toHaveBeenCalled();
And of course, the whole of Jest function mocks are available to you (documented here: https://jestjs.io/docs/mock-functions).
------ Edit -------
I think you're actually asking: "How can I change state passed to a component in response to that component calling a set...?". Excellent question! You can either not (see more below) or check answers to this question: How to test a prop update on React component
The reason I would suggest to not to is because 1. your test is growing too much and 2. it's not necessary. Presumably you want to test two things:
When something happens, setSelectedProperty is called, and
The component renders properly for different values of selectedProperty.
There is no need to test those together; test them separately. If your component holds so much state that you feel you need to test them together, it may be that your component is too stateful. React should be as "functional" as possible and without side effects. If your component is becoming unmanageable and difficult to test in this regard, don't give up testing, redesign the component.
This is a part of Think in React.
Thinking in React is the hard part for me because I see many developers do React with different mindsets.
When I was writing code for the Notification component that will be used by developers, suddenly I've noticed that there are different experiences to use the component:
Passing many Props like Bootstrap
<Notification
title="New Feature"
body={message}
action={action}/>
Passing one Prop as an Object
const data = {
title:"",
subtitle:"",
message:""
}
<Notification data={data}/>
Passing nested Children
<Notification>
<Title></Title>
<Body><Body/>
<Action><Action>
</Notification>
I followed the passing nested Children because ( I guess) It seems if I scale the component, I don't need to provide a Bootstrap-like experience for the developers.
import React from "react"
import { Wrapper, Text } from "./Styled"
const Body = ({ message }) => (
<Wrapper>
<Text>{message}</Text>
</Wrapper>
)
export default Body
The problem is I'm thinking about it is when I want to scale the Component and let's say adding 3 additional features that require 3 additional props
I'm confused about the reasons why each approach might be chosen, and what's the "best" developer experience.
To answer this question let's review all possibilities given React Element and a Function Component:
const c1 = <div>React Element</div>;
const C2 = () => <div>Function Component</div>;
Notice that from performance perspective, every component can be memoized and not cause useless renders.
Pass React element through props
const ObjectProps = ({ component }) => {
console.log("render object props");
return component;
};
<ObjectProps component={c1} />
Pros
Simple.
Lets you define the exact usage of passed component (contract).
For example you might decide "messages" have to be on top of "actions"
Cons
No lazy rendering
Passing heavy component may cause performance issues.
Hard to inject props (need to use React.cloneElement).
As a library writer you would like to inject your styles and refs.
Passing Function Component
const FunctionComponentProps = ({ FunctionComponent }) => {
console.log("render function component");
return <FunctionComponent />;
};
<FunctionComponentProps FunctionComponent={C2} />
Pros
Lazy rendering.
Easy to pass props and inject props for inner implementation.
Lets you define the exact usage of passed component (contract).
Cons
Confusing
Children Render
const ChildrenRender = ({ children }) => {
console.log("render function component");
return children;
};
<ChildrenRender>
{c1}
<C2 />
</ChildrenRender>
Pros
No restriction for the developer (no contract)
Cons
Hard to inject children (need to use React.Children API + React.cloneElement combo)
No contract
The developer might pass "buttons" and then "messages" and break the view.
Implementing ChildrenRender usually comes with component instances which results a minimal "contract" mentioned above.
const ChildrenRender = ({ children }) => {...};
ChildrenRender.InnerComp1 = <SomeComponent .../>
ChildrenRender.InnerComp2 = <SomeComponent2 .../>
<ChildrenRender>
<ChildrenRender.InnerComp1>{c1}</ChildrenRender.InnerComp1>
<ChildrenRender.InnerComp2><C2/></ChildrenRender.InnerComp2>
</ChildrenRender>
In Conclusion
It heavily depends on the component's usage, usually the hybrid approach suits well - passing components through props and add an option for passing children too.
Another technique is Render Props.
I am still fairly new to Reactjs and I am struggling with one thing.
I have built a small React app that consists of:
App.js at the very top –the only class component that controls all the states
3 stateless components ( no1 , no2, no3 rendered in App.js (all with smaller components inside them, but that’s irrelevant)
App.js state includes 3 arrays all of which are used by those 3 stateless components rendered.
And then, in App.js I have around 400 lines of methods where I am modifying state by calling setState. That’s quite long....
My question is: is there anyway to split this file? To move methods to their respective components: no 1, 2 and 3.
It seems impossible to me as having all the states in one class requires calling setState (having setState methods) in the same class only.
This might be a stupid question but:
Is it possible to modify state outside parent that holds this state (App.js), for instance, modify it in a stateless component no 1, and still keep parent updated about the change so that it can inform stateless components no 2 and no 3 about the change.
What’s the best practice in my case?
thanks
What i do for code/logic splitting is:
Keep the App.js as simple as possible
If there is a lot of logic in a file/Component, i split the file to index.js and Component.js and keep the logic in index.js and the JSX/HTML in the Component.js
In your case you can:
Remove all logic from App.js
Create 3 folders no1, no2 and no3
Inside each folder create two files - index.js and ComponentNo1.js etc
In the index.js create a Component with state and in ComponentNo1.js create a stateless component that returns the JSX/HTML.
This is what I would recommend. If you find it hard to do it, post your App.js logic so that I could help you do it.
Sure something like this is completely valid and is a common React practice.
I've written a sandbox to give you an idea of how this works:
https://codesandbox.io/s/zxl2owp2np
But to explain in detail, let's assume you have the following components:
class App extends React.Component {
state = {
value: 5
};
increaseValue = () => {
this.setState({
value: this.state.value + 1
});
};
render() {
return (
<div className="App">
<Example1 value={this.state.value} increaseValue={this.increaseValue} />
<Example2 value={this.state.value} />
<Example3 value={this.state.value} />
</div>
);
}
}
const Example1 = (props) => {
const value = props.value;
return (
<div>
I am Example1. The value is {value}
<button onClick={() => props.increaseValue()}>Click</button>
</div>
);
}
const Example2 = (props) => {
const value = props.value;
return (
<div>
I am Example2. The value is {value}
</div>
);
}
const Example3 = (props) => {
const value = props.value;
return (
<div>
I am Example3. The value is {value}
</div>
);
}
Our main App component has a state value of 5 that we pass into our 3 child components. The child components are all using that value to display data. In the App component, we defined a state-updating function called increaseValue, which we pass in to Example1 as property. Now Example1 can use increaseValue by calling props.increaseValue()
props.increaseValue() is bound to our App component's execution context. So it will update the value in App's component state. Now with the updated value, it gets shared across all our Example components for use.
Regarding your question about moving methods to the components that are using them. This is not a common practice. Typically you define the function inside the component where the state is going to be updated. Meaning, if you have a function that is meant to update the App component, it should be defined in the app component.
A "dumb" React view can be testing by passing it props before rendering it with enzyme/jsdom. Snapshot testing can then be used to validate the behavior (as in jest).
A smart component composed of a 'dumb view' connected with mapStateToProps/mapDispatchToProps can be tested by:
unit testing mapXxxToProps to check the logic is right
testing the dumb view
and optionnaly:
render the smart component by wrapping it in a Provider
However, this seems to break whenever a dumb view starts to nest other smart containers ; the rendering of the dumb view is not possible simply with props, since some child components down the chain might need a store.
Is there a way around that ?
Am I missing something ?
With enzyme, you can use a shallow render to test the dumb component is rendering the expected smart components, without actually rendering them completely.
Component (Bar is a smart component):
const Foo = () => {
return (
<div>
<Bar />
</div>
)
}
Test:
import { shallow } from 'enzyme';
...
it('should render <Foo /> component', () => {
const wrapper = shallow(<Foo />)
expect(wrapper.contains(<Bar />)).to.be.true
})
I am looking to validate a form with Redux. I am trying to use make a form component which will iterate through children and find various input components (not to be confused with a native <input>.
I know there are a lot of open source solutions, but I'd like to understand some mechanics before jumping into picking any. I have a Form component setup to test like this:
import React from 'react';
export default class Component extends React.Component {
componentDidMount() {
this._iterate(this.props.children);
}
render(){
return (
<form {...this.props}>{this.props.children}</form>
);
}
_iterate(children) {
React.Children.forEach(children, child => {
console.log(child);
if (child.props.children) {
console.log('get children');
this._iterate(child.props.children);
}
});
}
};
I then have another Component with a render like this:
render() {
return (
<div>
<Form>
<ComponentA />
<ComponentB />
</Form>
</div>
);
}
Now ComponentA or ComponentB might have a component that nests more components down the line. Within those components would be a React component I have made for Text, Select, etc.
The code above would just console.log the components, and any children of them, that are in this specific render. It does not jump down into ComponentA children.
Is there a solution to that?
This isn't a problem you really want to solve.
The power in react is largely around the design pattern it encourages, and what you're doing is breaking that pattern; Component's should only talk to their immediate children and respond to their immediate parents. If you need to go deeper than that, then the component in the middle needs to be responsible for passing that data.
Rather than trying to dig into the innards of ComponentA and ComponentB, those component's themselves should have the accessibility props that you need. I.e., <ComponentA onChange={whatever} errorMessage={whatever}/> etc. and then hooking those props to their children should occur within ComponentA.