How to you test a redux dumb component that renders smart components? - reactjs

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
})

Related

Testing React Components that get state + setState properties passed by parent

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.

How to test a component composed of other components with react-testing-library?

I am completely new to react-testing-library. I just started reading all the various "Getting Started" documentation and blog posts I could find after I had no success testing a component with Enzyme. Most of the examples I could find are pretty simple, like those in the "Introducing the react-testing-library" blog post. I would like to see examples of how to test a component that itself is composed of other components, since Component composition is one of the greatest things about React (in this SO post I will call an example of such ComposedComponent for lack of a better name).
When I wrote tests for a ComposedComponented in Enzyme, I could just assert that the correct props were passed to some ChildComponent and trust that ChildComponent had its own tests and I would not have to be concerned with what ChildComponent actually rendered to the DOM within my tests for ComposedComponent. But with react-testing-library, I am concerned that since "rather than dealing with instances of rendered react components, your tests will work with actual DOM nodes", I will also have to test the behavior of ChildComponent by making assertions about the DOM nodes it renders in response to its relationship to ComposedComponent. That would mean that the higher up I go in the Component hierarchy in a React application, the longer and more exhaustive my tests would become. The gist of my question is this: How can I test the behavior of a component that has other components as children without also testing the behavior of those child components?
I truly hope that I am just suffering from a failure of imagination and somebody can help me figure out how to properly use this library that has gained such a following as a replacement for Enzyme.
What I do when testing components that happen to render other (already tested) components is mock them. For example, I have a component that displays some text, a button, and a modal. The modal itself is already tested so I don't want to test it again.
import React from 'react';
import { render, fireEvent } from '#testing-library/react';
import { ComponentUnderTest } from '.';
// Mock implementation of a sub component of the component being tested
jest.mock('../Modals/ModalComponent', () => {
return {
__esModule: true,
// the "default export"
default: ({ isOpen, onButtonPress }) =>
isOpen && (
// Add a `testid` data attribute so it is easy to target the "modal's" close button
<button data-testid="close" onClick={onButtonPress} type="button" />
),
};
});
describe('Test', () => {
// Whatever tests you need/want
});

What is meant by "one level deep"?

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>

Testing mounted components with react-router v4

I'm migrating our application to react-router#4.x, and I'm having troubles with getting the tests that are using enzyme's mount function.
Whenever I mount a component that has a withRouter-wrapped sub-component, I run into trouble.
Here's an example of a simplified situation of what I'm testing:
class SomePage extends React.Component {
componentDidMount() {
this.props.getData();
}
render() {
return (
<div>
<ComponentWrappedInWithRouter />
</div>
);
}
}
const Component = (props) => (
<button onClick={() => this.props.history.push('/new-route') }>
Click to navigate
</button>
);
const ComponentWrappedInWithRouter = withRouter(Component);
Now, I want to test that SomePage calls its prop getData after it's mounted. Stupid example, I know, but the structure should be sufficient.
Whenever I write a test that uses enzyme's mount, I get the following error:
TypeError: Cannot read property 'route' of undefined
at Route.computeMatch (node_modules/react-router/Route.js:68:22)
at new Route (node_modules/react-router/Route.js:47:20)
Now, I think the reason this happens is because I try to call withRouter for a component that does not have router on the context - i.e. it has not been wrapped in <BrowserRouter /> or one of its siblings.
This wasn't an issue with react-router#3.x, but since the current major was a full rewrite, I totally understand that these issues will arise.
Any ideas as to how I can fix this?
Pretty easy: wrap your component being tested in a MemoryRouter from react-router-dom and you're good to go.
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/MemoryRouter.md

How can I find all nested Components using React/Redux?

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.

Resources