5 ms·
Idiomatic React Testing Patterns
- jitl 10y agoSee also Enzyme, a testing library specifically for React, that allows you to easy assert on both deep and shallow renders of the React DOM. https://github.com/airbnb/enzyme#basic-usage https://github.com/airbnb/enzyme#basic-usage
- jfdk 10y agoWe haven't tried Enzyme, but we tend to prefer not adding more JS tools when we don't need to. JS is already a land of wayyyy too many tools and minimizing when possible can be a huge advantage when onboarding new devs onto a project. Also the DOM api is actually pretty simple to use when it comes to traversing the DOM. No need for "jQuery mimicking." Keep it simple.
- eagsalazar2 10y agoYou have to learn some tool (react test utils at least) to access and interact with those React components either way. Enzyme is 100% better and more powerful than using the react test utils and way easier to onboard new devs to. All IMO but I def think you should at least check it out.
- bgxor 10y agoI would really encourage you to give it a try. The "jQuery mimicking" is actually not even its best feature. I didn't think much of it at the beginning, but it pretty much makes React's test utils really pleasant to work with. All in all, it basically codifies and gives a reusable api to most of what you say in your gist.
- Klathmon 10y agoThis is a bit off topic, but why such aversion to purpose built tools in JS land? In my experience it's much harder to onboard devs to a custom-ish process than it is to hand them a purpose built tool with proper documentation and lots of examples of real-world usage to learn from. I tend to try to use already made tools over doing it myself* as it makes onboarding easier, lightens my cognitive load, reduces my testing surface, and is generally quicker than coming up with my own solution. * A bit of a disclaimer... I mean well made, well tested, and well supported tools taking into account the time cost of doing it myself, the complexity of the tool, how important/ingrained it will be in my application, the number of contributors in the project, the test coverage of the project, the speed/ease it can be switched out, how well it actually solves my problem at hand, and a ton of other things. I do not mean that you should blindly use every tools you can whenever possible, or that you should use it because Facebook/Google/Other-Company uses it.
- jfdk 10y agoWhat I should have said is "minimize tools when it makes sense" rather than "when possible." There are some tools that are more trouble than they're worth (for example, I feel this strongly about Jest). Enzyme isn't necessarily one of those, like I said I haven't used it, but I also haven't found a need to. Some abstractions over TestUtils' event simulation would certainly be valuable. What I am trying to present here are patterns of different testing scenarios in a format that should be useful regardless of the testing tools you may be using.
- analyst74 10y agoIf you use shallow render for your unit tests, Enzyme is much much better than Test Utilities. Just to name a few reasons: - better event simulation - easier to update prop - allow setting and getting state - easier to refresh after triggering changes - comprehensive selector support
- cjcenizal 10y agoI've found the best testing pattern is to test the interface of the component, not the implementation. This means treating the component as an opaque function with inputs (props) and outputs (the rendered result). Your tests just need to that verify that different prop values result in the DOM changes or callbacks that you expect.
- jfdk 10y agoAgree 100%. However if you are using component state you will need to test how interactions impact rendering output on the next render pass. I wouldn't consider that implementation detail since you are only asserting against render output. In the case of testing instance methods, this is definitely a special edge-case scenario, but actually one of the main reasons I put this together. They inevitably happen, but are rare and I tend to forget how to set those tests up. To give you an idea of how we use this: our application is a "website designer" where the preview is rendered inside an iframe. We use a react component to push CSS changes directly into the iframe via document.styleSheets. Using instance method testing allows us to test the main output results of this functionality without having to render real iframes pointing to external server in our tests.
- shepmaster 10y agoDo you use any tools to make the assertions on the resulting DOM simpler? What about any components that maintain internal state; do you just step them through the states and assert the DOM state as well?
- cjcenizal 10y agoI built this testing tool at a previous employer: https://github.com/smaato/react-test-kit https://github.com/smaato/react-test-kit. It's very very simple, it just exposes jQuery-like methods for querying the DOM (and internally uses Sizzle). Here's an example of how we used react-test-kit to test a SearchBox component: https://github.com/smaato/ui-framework/blob/develop/src/framework/searchBox/SearchBox.spec.jsx https://github.com/smaato/ui-framework/blob/develop/src/fram... Here's the interactive component example: http://smaato.github.io/ui-framework/#/searchbox http://smaato.github.io/ui-framework/#/searchbox
- pietro 10y agoFrom what Dan Abramov has been posting on Twitter recently, findDOMNode() is in the process of being deprecated, so rather than writing const component = ReactDOM.findDOMNode(TestUtils.renderIntoDocument( <MyComponent {...props} /> )); we should be writing let node; const component = TestUtils.renderIntoDocument( <MyComponent {...props} ref={n => node = n}/> ); https://gist.github.com/gaearon/7f0e03d3028016bfabfad641720d3de1 https://gist.github.com/gaearon/7f0e03d3028016bfabfad641720d...
- jfdk 10y agoGood to know, will update the examples when I have time. Not sure I'm a big fan of it though, doesn't seem as clear to a React noob what is going on with ref?
- deleted 10y ago[deleted]
- tengbretson 10y agoIn my experience, as long as you have a well tested data model and use proptypes/Flow/TypeScript, testing the components themselves becomes almost entirely irrelevant. However, I can see the utility of component testing if I were wrapping something like Ace editor or a jQuery plugin or something of that nature.
- shepmaster 10y agoDo you use anything like Redux? When writing Redux state reducers and actions, it all seems so... simple. There's a lot of code like `return { ...currentState, newProp }` which seems too silly to test.
- tengbretson 10y agoI often leave off tests for strictly "synchronous" actions like `return { ...currentState, newProp }`. Most of my tests are for confirming that the right paths are taken for actions that trigger one or more async operations to ensure correct failure case handling.
- jfdk 10y agoJS tests like this are so stupid cheap that we still write them for even the most basic test. Not sure I'm convinced it's worth it yet and I might regret it the first time we refactor a larger reducer.
- deleted 10y ago[deleted]
- jfdk 10y agoIf your application has few or very simple interactions then this may make sense. If it does have complex interactions (I consider a text input updating a model field as complex) then I think tests are necessary, especially if working with a team. You want to know when you break things. This becomes even more important if you're developing generic UI components that may be re-used in different scenarios throughout your app or company. These types of library components need to be well tested as they often have more complex interactions and are going to be used in potentially very different ways.
- haukur 10y agoIt can be very helpful to define all the different states (as props) for the set of components you're building. The data can be static or the result of dynamic calls to API endpoints (both approaches have benefits and trade-offs). For instance, if you're building a page with a list of items and at most 10 should be shown at a time, you could define the empty state (0 items), the half-full (1-10 items) and the overloaded state (11+ items, requiring pagination). Then you can implement the actual UI. When this is done (and you're happy with the way it looks), you can make your test suite iterate over each of the different states and capture a screenshot of the UI. When something changes, you will know (the test suite should diff it). This approach is obviously mostly for presentation rather than functionality. The benefits are not limited to testing, this is also very helpful in development, since you could switch between different states very quickly without having to constantly change URLs (for different API results). One method is using a dropdown overlay (only present in the development build). It's also very helpful during code review.
- djacobs 10y agoI looked through the patterns and I wonder what makes them 'idiomatic'? I've found it useful to use wrapper libraries like Enzyme [0] and Teaspoon [1] when testing React components and interactions. [0] https://github.com/airbnb/enzyme https://github.com/airbnb/enzyme [1] https://github.com/jquense/teaspoon https://github.com/jquense/teaspoon
- sotojuan 10y agoCool post but I'll play devil's advocate and ask what's so idiomatic about this. Can someone comment if this is what most the community is going? Not blaming the author at all, but skeptical of anything called "idiomatic" nowadays.
- lhnz 10y agoDo others agree with the `getComponent` pattern described there? I do like it but I'm wary of moving away from the `beforeEach` pattern. The `beforeEach` pattern is much more common and is a consistent interface that engineers can easily pickup and won't need to recreate in every single test file.
- jfdk 10y agoI've found beforeEach breaks down super quickly as soon as you need to change the input props. Keeping things as purely functional as possible also helps manage complexity when writing tests in a large suite. You don't have to trace through all the beforeEach of each describe/context block. That said we use a healthy combination of both, as with everything know when to use the right tool.