Or components, or components with , or components, or components or components you just can just test. And be happy with testing. limited depth well know boundaries isolated scoped Define the problem with testing React components is quite fundamental. It’s about the difference between and . It’s about the difference between what we unit testing and what we call integration testing, the size and the scope. And, while for ages they were no more than different parts of The Testing, now there is a WAR of different testing philosophies. The problem unit testing integration testing call . Browser based testing from one of your’s application — the ,— and to another — the deepest deeps. Testing your app as your customer would do. Testing a full spectrum – UI, styles, backend. The only testing kind, which , that’s why it’s so cool. E2E Integration testing End entry point End would actually test your application . Testing a very small(or scoped) components, usually in isolated or fully mocked environment. Testing nothing but a single and simple “thing” – a unit, “thing” by “thing”, that’s why its easy to write and it’s unbound from the rest of the application Unit tests ship a well tested “thing” – Which? When? And here are the philosophical problems: You cannot use integration tests before your application is ready – these tests are to ensure that app is working correctly, but it does not . You probably could keep them red, to guide you in a TDD manner, but you should not rely on implementation details you haven’t written yet. And yes — label on the button could be considered as implementation detail, unless design is well established, and all button labels are known. Usually they are, but if you are working in a big team(or productive manager) – are the subject to change. YET details Unit tests could be created before application, which would lead to coverage, and you will probably redo everything in the future, which is what YAGNY about — . premature testing You aren’t gonna need it In other words — unit and integration tests have their own benefits and issues, and are not interchangeable, and aimed not to solve different tasks, but to work on different scopes — low component level and high application level. Just because E2E Test is an overpower for a component level, while unit testing frameworks are not capable to handle a thing bigger than a module (but you will try). approach Testing pyramid Symbiosis between units tests and integration — this is what Testing Pyramid should mean. E2E test to ensure cross stack connectivity, Integrations tests, for testing how your application was assembled, and Unit tests, for testing how component work. each and every But you can not test “each and every” anywhere, except the unit level due to “combinatorial explosion”. that Let’s imagine you have one component with 2 different states. Only 2 cases to test. Let’s imagine you have 2 components to test — 2x2=4! Let’s imagine 3 components. 3x2 = 6! Just a 6 test cases. You can test every component by it’s own, independently, and just sum all the test cases to got the required number of tests — linear O(n) growth. For integration tests 3 components already formed 8(2x2x2) combinations, as long as you are testing them simultaneously, and this EXPLOSION — O(n²). So the rule is simple — use unit tests to test components in isolation, , and integration/E2E to test them . Not to test — ensure that combination is “right”, and wired properly— you may tests happy path only, for example. Or even smoke tests. one-by-one together Having only integration testing is less than ideal though as unit tests help us design more robust software by easily testing alternate code and failure paths. We should save integration tests for larger “does it really work” kinds of tests. SendGrid Unit tests are great, as long as in the end you can assemble your application from well unit tested pieces, and then verify the result by a integration test. This is something I like about node modules – well unit tested pieces, I could rely on. And the point of everything above is super simple: You can’t skip units testing. They have their purpose. You have to use unit tests, to make your app predictable in unpredicted conditions. You shall unit test your application. For the sake of quality. But there is a problem... The Unit Problems First problem — Enzyme vs Webdriver The majority thinks that , to be more concrete , is the way to test. That’s partially true — gives you ability to test only your component, as long as it does not perform a “full” render. Enzyme shallow unit unit shallow is a way to only your piece of code. But there are so many disadvantages of shallow testing, like RenderProps or Context incompatibility. shallow unit test Mount does not have these disadvantages, but has others, like testing . Usually it’s a blocker, as long as it common today that something below you, will require something above you — Redux Store, I18nProvider, Context, Apollo, Styled Theme… just everything. And not just to exists, but to have values. everything below mount point right For a last year I was adding one more wrapper for my test every month. I would just ask — if you have a simple Button component, is there any difference between shallow and mount? const Button = ({children, onClick}) => (<button onClick={onClick} className='my-button'>{children}</button>) 😉 — for small components there is no difference between shallow, which just record your React.createElement (result of JSX transpilation) calls, and mount, executed these calls, ie performs a full render. And even there is no difference from browser based tests like webdriver or Cypress. For small components they all the same. For small component the same code could work everywhere. Why? Why??!! Second problem — define unit So — the game changer here is WHAT we call a UNIT we could easily unit test, and “why”. I mean — you can unit test some component, cos it’s unit testable. Very obviously. Why they are unit testable? Cos the are small? Probably no, this time it’s not so obvious. Probably, if we define what does “unit” means — we would be able to understand how to archive a better unit tests by making our components more . You probably already understand the idea from the title of this article, but.. unit, more finite Finite React Components React Presentation Components, or Dumb Components — they are quite heavy described in the past, and separation between Smart and Dumb Components was(and is) a Big Thing, especially in Redux applications. According to Presentation Components are: Dan Abramov Article 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 unless they need state, lifecycle hooks, or performance optimizations. functional components Examples: Page, Sidebar, Story, UserInfo, List. And are just a data/props providers for these components. Containers In the ideal Application… Containers are the Tree. Components are Tree Leafs. The secret sauce here, a one change we have to amend in this definition is hidden inside , let me cite original article “May contain both presentational and container components**” ** 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 inside components you are making second and injecting dependecy . containers presentation infinite, to the rest of the app You may know how to mock, setup and feed your , and how to render your component, but if it will another container, or(usually) containers — you will be unable to unit test your one. It will be already integration tests, and it would require much more work to setup proper environment for ALL containers you actually used and assert the result. container presentation contain So — it’s simple — PRESENTATION COMPONENTS SHOULD ONLY CONTAIN OTHER PRESENTATION COMPONENTS. And then — you will be able to unit test your container or your dumb component as a separated, isolated, scoped, and finite thing — A UNIT. By removing containers from presentation layer you might make your tests easier. But, probably right now you are looking on your code, with lots of containers nested inside Dumb components, and the question you have — “HOW” How??!! Finity War Solution 1 — Dependency Injection This is my favourite one. DI, Slots and Rock-n-Roll. If you need to contain another Container inside Presentation Component — pass it as or another slot . As result you will be able to test it with these slots . In this case it would be . children prop empty finite // test me with mount and empty slotsconst PageChrome = ({children, aside}) => (<section><aside>{aside}</aside>{children}</section>); // test me with shallow, I am shallow testableconst PageChromeContainer = () => (<PageChrome aside={<ASideContainer />}><Page /></Page>); DI probably is the most solution you can imagine — you are free to “wire” your application differently. This is programing technique, which may make better both your code, and testing. reusable ☝️Containers are the Tree. Components are Tree Leafs. Solution 2 — The Boundary DI sometimes could be a bit overpower. But what if you will able to contain inside in Production, but not in Testing environment? Containers Presentation const Boundary = ({children}) => (process.env.NODE_ENV === 'test' ? null : children); const PageChrome = () => (<section><aside><Boundary><ASideContainer /></Boundary></aside><Boundary><Page /></Boundary></section>); const PageChromeContainer = () => (<PageChrome /> // lets assume that we still need this container :P); Here it would work “as expected” in dev or prod, but in test env it will not render nested Containers, making PageChrome . Just add more granule control over Boundary — and that’s the deal. finite ☝️Presentation Component will not contain Containers. But only in test environment. Solution 2.5 — M Boundary ultitier Almost the same, but with a taste of — just for every container define Tier, and if Tier is not matching the “current” one — do not render it. Layered Architecture 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(2)(...)const Page = withTier(3)(...) const PageChromeContainer = withTier(1)(PageChrome); here could be almost anything — module, feature, actually “Tier”. In this case Presentation Component could look as “usual”, and Containers themselves would decide should they exists during the tests, or not. Tier Then you are testing a Component — it’s probably a part of a feature, and could contain another containers from the same feature. You may keep containers you are aware of, and remove others. Let me cite Dan’s Article yet again: Remember, They only need to provide composition boundaries between UI concerns. components don’t have to emit DOM. Feel free to add these . boundaries Solution 3 — Separate Concerns The base of concern separation is actually — separation, and your ability to distinguish one thing, from another. Usually it could be done according to the components name. Let’s assume, that all our Containers has a pattern in their name, and that’s true for the ones, connected to Redux — they all are . Connect(ComponentName) Redux is quite good example of the — “connect” is the beginning of everything and the end. It’s a by design. finite idea Boundary const PageChrome = () => (<section><aside><ASideContainer /></aside><Page /></section>); const PageChromeContainer = connect()(PageChrome); // remove all components matching react-redux patternreactRemock.mock(/Connect\(\w\)/) Using this approach you will be able to test , but not as long as it would be also removed. Let’s create a better example: PageChrome PageChromeContainer {createElement, remock} 'react-remock'; import from // initially allowedconst ContainerCondition = React.createContext(true); reactRemock.mock(/Connect\(\w\)/, (type, props, children) => (<ContainerCondition.Consumer>{ opened => (opened? (<ContainerCondition.Provider value={false}>// "close" and render real element{createElement(type, props, ...children)}<ContainerCondition.Provider>): null)}</ContainerCondition.Consumer>) It’s a bit more complex — replaces every with React.Context based condition, which would render only first encountered container, any nested one would be rendered as , thus — your Presentation Components will become “finite” in the testing environment, without any actual code change. connect null PS: reactRemock here is https://github.com/theKashey/react-remock In the end By the end of a day — you will establish a well known boundaries across different entities, layers, features, modules, or components separated by any other principle. You will be able to use any testing tool — shallow, mount or even webdriver based tools — the tool will not matter anymore. There are different ways to achive it — more declarative and explicit, like DI, or invisible like remocking. It will not only give you a better testing, but you will be able to create a more scoped Storybooks. Test the thing you build, focus on details, pick gear by gear. And the only thing you need for it — ability to “pick” a single gear and test it. A single gear, not all the gearbox. Just Boundaries and Separation. PS: And yet again — you may test a single gear, and a whole gearbox — but you cant test a half of gearbox, starting from some random stuff in the middle. Read more about containers/presentation _You’ll find your components much easier to reuse and reason about if you divide them into two categories._medium.com Presentational and Container Components Read more about shallow rendering _Tests should help me be confident that my application is working and there are better ways to do that than shallow…_hackernoon.com Why I Always Use Shallow Rendering Read more about power of mocking _Or breaking free from side effects and singletons in nodejs and webpack. Long story short – let me explain some things…_hackernoon.com SSR: Dependency mocking is the answer! PS: This article was written as a response to this comment by on React RFC. Good testing is not bound to React API Dave! Dave Schinkel _View formatted RFC Note: I just wrote up the RFC. The semantics were designed by @sebmarkbage._github.com contextType: convenience API for reading context in a class by gaearon · Pull Request #65 ·…