(in)Finite War
Tags: react, testing, javascript
Published: 2019-01-01 23:55:59

---
title: (in)Finite War
published: true
description: And how "Finite React Components" could save your day
tags: react, testing, javascript
cover_image: https://thepracticaldev.s3.amazonaws.com/i/4wgkxnngd7dqgzfmu9oz.jpg
---
## We have a problem
The problem with testing React components is quite fundamental. It’s about the difference between `unit testing` and `integration testing`. It’s about the difference between what we call unit testing and what we call integration testing, the size and the scope.

It's not about testing itself, but about Component Architecture. About the difference between testing __components__, standalone libraries, and final __applications__. 
>You may dive deeper into the problem by reading the [Testing The Finite React Components](https://hackernoon.com/testing-the-finite-react-components-d08ca74eb8c1), or [Why I Always Use Shallow Rendering](https://hackernoon.com/why-i-always-use-shallow-rendering-a3a50da60942), but here let's skip all the sugar.

## Define the Problem
There are 2 different ways to test React Component - `shallow` and everything else, including `mount`, `react-testing-library`, `webdriver` and so on. Only `shallow` is special - the rest behave in the same manner.

And this difference is about _the size, and the scope_ - about WHAT would be tested, and just partially _how_.

In short - `shallow` will only record calls to React.createElement, but not running any side effects, including rendering DOM elements - it's a side(algebraic) effect of React.createElement.

Any other command will run the code you provided with each and every side effect also being executed. As it would be in real, and that's the goal.

And __the problem__ is the following: `you can NOT run each and every side effect`. 

### Why not?
Function purity? Purity and Immutability - the holy cows of today. And you are slaughtering one of them. The axioms of unit testing - no side effects, isolation, mocking, everything under control.

- But that's is _not a problem_ for ... `dumb components`. They are dumb, contains only the presentation layer, but not "side effects".

- But that's _a problem_ for `Containers`. As long they are not dumb, contains whatever they want, and fully about side effects. They are the problem!

Probably, if we define the rules of "The Right Component" we could easily test - it will guide us, and help us.

> TRDL: The Finite Component

## Smart and Dumb components

According to [Dan Abramov Article](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) Presentation Components are:
- Are concerned with how things look.
- May contain both presentational and container components`**` inside, and usually have some DOM markup and styles of their own.
- Often allow containment via this.props.children.
- Have no dependencies on the rest of the app, such as Flux actions or stores.
- Don’t specify how the data is loaded or mutated.
- Receive data and callbacks exclusively via props.
- Rarely have their own state (when they do, it’s UI state rather than data).
- Are written as functional components unless they need state, lifecycle hooks, or performance optimizations.
- Examples: Page, Sidebar, Story, UserInfo, List.
- ....
- And Containers are just data/props providers for these components.

According to the origins: __In the ideal Application…
Containers are the Tree. Components are Tree Leafs.__

#### Find the black cat in the dark room
The secret sauce here, one change we have to amend in this definition, is hidden inside _“May contain both presentational and container components`**`”_, let me cite the original article:
> In an earlier version of this article I claimed that presentational components should only contain other presentational components. I no longer think this is the case. Whether a component is a presentational component or a container is its implementation detail. You should be able to replace a presentational component with a container without modifying any of the call sites. Therefore, both presentational and container components can contain other presentational or container components just fine.

Ok, but what about the rule, which makes presentation components unit testable – _“Have no dependencies on the rest of the app”_?

Unfortunately, by including containers into the presentation components you are making second ones __infinite__, and injecting dependency to the rest of the app.

Probably that's not something you were intended to do. So, I don't have any other choice, but to make dumb component finite:

__PRESENTATION COMPONENTS SHOULD ONLY CONTAIN OTHER PRESENTATION COMPONENTS__

And the only question, you should as: _How?_

#### Solution 1 - DI
Solution 1 is simple - don't contain nested containers in the dumb component - contain `slots`. Just accept "content"(children), as props, and that would solve the problem:
- you are able to test the dumb component without "the rest of your app"
- you are able to test integration with smoke/integration/e2e test, not tests.

```js
// Test me with mount, with "slots emty".
const PageChrome = ({children, aside}) => (
  <section>
    <aside>{aside}</aside>
    {children}
  </section>
);

// test me with shallow, or real integration test
const PageChromeContainer = () => (
  <PageChrome aside={<ASideContainer />}>
    <Page />
  </PageChrome> 
);
```
Approved by Dan himself:
{% twitter 1021850499618955272 %}

DI(both `Dependency Injection` and `Dependency Inversion`), probably, is a most reusable technique here, able to make your life much, much easier.

> Point here - Dumb components are dumb!

#### Solution 2 - Boundaries
This is a quite declarative solution, and could extend `Solution 1` - just declare all _extension_ points. Just wrap them with.. `Boundary`
```js
const Boundary = ({children}) => (
  process.env.NODE_ENV === 'test' ? null : children
  // or `jest.mock`
);

const PageChrome = () => (
  <section>
    <aside><Boundary><ASideContainer /></Boundary></aside>
    <Boundary><Page /></Boundary>
  </section>
);
```
Then - you are able to disable, just zero, `Boundary` to reduce Component scope, and make it _finite_.

> Point here - Boundary is on Dumb component level. Dumb component is controlling how Dumb it is.

### Solution 3 - Tier
Is the same as Solution 2, but with more smart Boundary, able to mock _layer_, or _tier_, or whatever you say:
```js
const checkTier = tier => tier === currentTier;
const withTier = tier => WrapperComponent => (props) => (
  (process.env.NODE_ENV !== ‘test’ || checkTier(tier))
   && <WrapperComponent{...props} />
);
const PageChrome = () => (
  <section>
    <aside><ASideContainer /></aside>
    <Page />
  </section>
);
const ASideContainer = withTier('UI')(...)
const Page = withTier('Page')(...)
const PageChromeContainer = withTier('UI')(PageChrome);
```

> Even if this is almost similar to Boundary example - Dumb component is Dumb, and Containers controlling the visibility of other Containers. 

#### Solution 4 - Separate Concerns
Another solution is just to Separate Concerns! I mean - you already did it, and probably it's time to utilize it.

> By `connect`ing component to Redux or GQL you are producing _well known_ Containers. I mean - with _well-known_ names - `Container(WrapperComponent)`. You may mock them by their names


```js
const PageChrome = () => (
  <section>
    <aside><ASideContainer /></aside>
    <Page />
  </section>
);

// remove all components matching react-redux pattern
reactRemock.mock(/Connect\(\w\)/)
// all any other container
reactRemock.mock(/Container/)
```

This approach is a bit rude - it will wipe _everything_, making harder to test Containers themselves, and you may use a bit more complex mocking to keep the "first one":

```js
import {createElement, remock} from 'react-remock';

// initially "open"
const ContainerCondition = React.createContext(true);

reactRemock.mock(/Connect\(\w\)/, (type, props, children) => (
  <ContainerCondition.Consumer>
   { opened => (
      opened
       ? (
         // "close" and render real component
         <ContainerCondition.Provider value={false}>
          {createElement(type, props, ...children)}
         <ContainerCondition.Provider>
         )      
       // it's "closed"
       : null
   )}
  </ContainerCondition.Consumer>
)
```

> Point here: there is no logic inside nor Presentation, not Container - all logic is outside.

#### Bonus Solution - Separate Concerns

You may keep _tight coupling_ using `defaultProps`, and nullify these props in tests...
```js
const PageChrome = ({Content = Page, Aside = ASideContainer}) => (
  <section>
    <aside><Aside/></aside>
    <Content/>
  </section>
);
```


## So?
So I've just posted a few ways to reduce the scope of any component, and make them much more testable. The simple way to get one `gear` out of the `gearbox`. A simple pattern to make your life easier.

E2E tests are great, but it's hard to simulate some conditions, which could occur inside a deeply nested feature and be ready for them. You have to have unit tests to be able to simulate different scenarios. You have to have integration tests to ensure that everything is wired properly.

You know, as Dan wrote in [his another article](https://overreacted.io/the-elements-of-ui-engineering/):
>For example, if a button can be in one of 5 different states (normal, active, hover, danger, disabled), the code updating the button must be correct for 5×4=20 possible transitions — or forbid some of them. How do we tame the combinatorial explosion of possible states and make visual output predictable?

While the right solution here is state machines, being able to cherry-pick a single atom or molecule and play with it - is the base requirement.

### The main points of this article
1. Presentational components should only contain other presentational components.
2. Containers are the Tree. Components are Tree Leafs.
3. You don't have to _always_ NOT contain Containers inside Presentational ones, but _not contain them_ only in tests.

PS: I would recommend reading (auto-translated) [habr version](https://habr.com/post/434830/) of this post.