Improve shallow rendering for use with higher-order components
- Dominant language
- JavaScript
- Stars
- 19.8k
- Forks
- 2k
- PR merge metrics
- No merged PRs in 30d
Description
When using shallow rendering with a component that is wrapped by a higher order component, you need to take some extra steps to make shallow rendering give you the structure you expect. One way is to shallow render the wrapped component, find the unwrapped component within this structure, and then shallow render that. e.g.
``` jsx
const wrapper = shallow().find('Foo').shallow();
```
Of course, you can also export the unwrapped component as a named export, and use that to find by reference as well.
``` jsx
import Foo, { Foo as UnwrappedFoo } from './Foo';
...
const wrapper = shallow().find(UnwrappedFoo).shallow();
```
This bums me out a little, because if you have a bunch of tests for a component, and then later decide to wrap that component in a HOC, you need to go back and update all of your tests in this way. Using the string approach feels less than ideal, and the reference approach feels a bit cumbersome when applied on a large scale. I'm wondering if we can come up with a solution that will work well for this scenario. Here are some thoughts.
- In #250, @lelandrichardson proposed "Mixed-depth shallow rendering mode", which would allow you to pass an `expand` option to `shallow` with references to components to "expand" the shallow render tree into. I think this would work if your component is only wrapped by a single HOC, but if you wrap it in multiple HOCs, you end up with the same problem again, because you have multiple levels that you need to expand, but only a reference to the top level.
- We could add an `until` option to shallow that would take a reference to a component or a string reference. This would reduce some of the boilerplate of `.find('Foo').shallow()` just a little, but I think it has many of the same disadvantages that we currently have.
- Another possibility is to provide a `depth` option to `shallow`, that would take a number of components to drill down into. I think that this would be more comfortable than what we currently do, but it still doesn't fully solve the problem--you still have to know to add this option to every place you want to use shallow rendering with wrapped components. And, if you wrap a component in another HOC, you need to increment all of the values.
- We could add a static property on HOCs that signify that they are HOCs. Enzyme could then look for this static property when shallow rendering, and dig deeper. And, if you find yourself in a situation where you want to avoid this behavior, we could add an option to `shallow` to opt-out, but maybe that's YAGNI. The downside is that this would only work for HOCs that opt in to this behavior, so it likely wouldn't solve the problem when using third-party HOCs--unless it somehow caught on and spread to all corners.
- What if we allowed people to register a list of regexes used to expand components when shallow rendering, matching on their names. Using this, folks could configure their testing environment to do what they want, and then not have to think about it much any more. At Airbnb, [we use a naming convention of `functionName(ComponentName)` for HOCs](https://github.com/airbnb/javascript/tree/master/react#naming) which we could configure all be automatically expanded with a regex like `/\([^\)]+\)/`. I like this option because I think it would solve this issue for us with little configuration, but I dislike it because it makes shallow rendering somewhat magical and might cause unexpected results.
Do any of these sound good? Should we employ multiple strategies? Are there other possibilities?
Contributor guide
Research direction
Start with Enzyme's shallow rendering entry point and the handling of higher-order components. Compare the proposed expand, until, depth, HOC marker, and regex strategies, then review the discussion for a settled direction. Done means agreeing on and implementing a solution that handles wrapped components without requiring every test to be updated manually.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, react
- Domain
- frontend, testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100