We have a problem. The problem with testing. The problem with testing React components, and it 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.  Everyone knows how to test simple components(they are simple), probably know how to test Applications(E2E). How to test Finite and Infinite things…  There is 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 following: you can NOT run each and every side effect.  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. According to Dan Abramov Article Presentation Components are: According to the origins: In the ideal Application…
Containers are the Tree. Components are Tree Leafs. 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 original article: 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 ask (looking into your current code base): How? :tableflip:?! Today Presentation Components and Containers are not just entangled, but sometimes just not extracted as "pure" entities (hello GraphQL). 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: Approved by Dan himself:
{% twitter 1021850499618955272 %} DI(both Dependecy Injection and Dependency Inversion), probably, is a most reusable technique here, able to make your life much, much easier. This is a quite declarative solution, and could extend Solution 1 — just declare all extension points. Just wrap them with… Boundary Then — you are able to disable, just zero, Boundary to reduce Component scope, and make it finite. Is the same as Solution 2, but with more smart Boundary, able to mock layer, or tier, or whatever you say: Another solution is just to Separate Concerns! I mean — you already did it, and probably it's time to utilize it. This approach is a bit rude — it will wipe everything, making harder to test Contaiers themselves, and you may use a bit more complex mocking to keep the "first one": You may keep tight coupling using defaultProps, and nullify these props in tests... 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: 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. PS: This is a translation of ru-habr article habr version. javascript, webgl, maps, react, орфография(нет)