AI-powered search: From keywords to conversations
By now, everyone’s had the opportunity to experiment with AI tools like ChatGPT or Midjourney and ponder their inner ...
Director, Product Marketing
By now, everyone’s had the opportunity to experiment with AI tools like ChatGPT or Midjourney and ponder their inner ...
Director, Product Marketing
Search has been around for a while, to the point that it is now considered a standard requirement in many ...
Senior Machine Learning Engineer
With the advent of artificial intelligence (AI) technologies enabling services such as Alexa, Google search, and self-driving cars, the ...
VP Corporate Marketing
It’s no secret that B2B (business-to-business) transactions have largely migrated online. According to Gartner, by 2025, 80 ...
Sr. SEO Web Digital Marketing Manager
Twice a year, B2B Online brings together industry leaders to discuss the trends affecting the B2B ecommerce industry. At the ...
Director of Product Marketing & Strategy
This is Part 2 of a series that dives into the transformational journey made by digital merchandising to drive positive ...
Benoit Reulier &
Reshma Iyer
Get ready for the ride: online shopping is about to be completely upended by AI. Over the past few years ...
Director, User Experience & UI Platform
Remember life before online shopping? When you had to actually leave the house for a brick-and-mortar store to ...
Search and Discovery writer
If you imagine pushing a virtual shopping cart down the aisles of an online store, or browsing items in an ...
Sr. SEO Web Digital Marketing Manager
Remember the world before the convenience of online commerce? Before the pandemic, before the proliferation of ecommerce sites, when the ...
Search and Discovery writer
Artificial intelligence (AI) is no longer just the stuff of scary futuristic movies; it’s recently burst into the headlines ...
Search and Discovery writer
Imagine you are the CTO of a company that has just undergone a massive decade long digital transformation. You’ve ...
CTO @Algolia
Did you know that the tiny search bar at the top of many ecommerce sites can offer an outsized return ...
Director, Digital Marketing
Artificial intelligence (AI) has quickly moved from hot topic to everyday life. Now, ecommerce businesses are beginning to clearly see ...
VP of Product
We couldn’t be more excited to announce the availability of our breakthrough product, Algolia NeuralSearch. The world has stepped ...
Chief Executive Officer and Board Member at Algolia
The ecommerce industry has experienced steady and reliable growth over the last 20 years (albeit interrupted briefly by a global ...
CTO @Algolia
As an ecommerce professional, you know the importance of providing a five-star search experience on your site or in ...
Sr. SEO Web Digital Marketing Manager
Hashing. Yep, you read that right. Not hashtags. Not golden, crisp-on-the-outside, melty-on-the-inside hash browns ...
Search and Discovery writer
Nov 3rd 2015 engineering
React was designed to solve one problem—how to build applications with data that changes over time. Considering the as-you-type search experience offered by Algolia wherein whole results pages, hits and refinement links alike, are updated at each keystroke, React was the obvious choice when we needed a tool to build out our new library of UI widgets: instantsearch.js.
We quickly struggled, however, with the unit test best practices for React components. We jumped from Github issues in facebook/react to blog posts and discuss.reactjs.org but couldn’t find a clear unit testing strategy.
Now that we’re happy with our testing stack, we wanted to share it with the community to hopefully make your testing process a bit easier. Feel free to also check out the unit testing tips we shared a few months ago.
Before digging into the whole testing stack, how do we test a React component?
If you search for “React unit testing”, you’ll quickly find the popular React discussion—What’s the preferred way to test React.js components? In the thread, React developer Ben Alpert advises testing React components using a technique known as shallow rendering.
Here’s an example of a Button and a Label component tested with mocha:
And here is the output when you run it:
What about failing test cases? Let’s make it fail by changing our test:
Not too bad. Shallow rendering provides a way to render a React element only one level deep. This means that if you have children elements (like Label in our Button), it will not trigger their render methods. Very nice for unit testing!
The shallow rendering technique is simple to use and well suited for unit testing as it takes a React Element as INPUT and produces a React Element as OUTPUT.
There are other techniques available, but this is the currently recommended one and we expect (?) the React team to develop more tools around it in the future.
But wait, it’s not over! Did you see that diff? You passed some nice expected JSX (<div><Label name=”Marie” /></div>), and all you got was a weird object output diff.
This is because JSX is transpiled to a React.createElement call that then returns a React element (a JavaScript object). So when doing expect(something).toEqual(somethingElse), you are just comparing two JavaScript objects.
It would be better to get something like this:
Let’s make it happen! OK, we need a bit of tooling to get there.
After we found out about shallow rendering, we needed a good stack to make assertions and run the tests. We decided to have a look at what rackt, the Github org responsible for react-router and redux (two very popular react libraries) was using. After all, the closer you are to the tools of your community, the easier it is to get contributions.
The rackt team is using mochajs/mocha to run the tests and mjackson/expect to write assertions. They also follow the facebook/jest convention of putting tests next to the files they are testing:
After choosing mjackson/expect as our assertion library and mochajs/mocha as our test runner, we wanted better JSX diffs instead of long object diffs when our tests were failing.
We asked the React community how to do this and got some great feedback. In fact, another assertion library already did it—bruderstein/unexpected-react-shallow. alexlande/react-to-jsx was also a candidate for implementing the JSX string diff in the expect assertion library.
Unfortunately, those libraries were not meeting our expectations. So…we built algolia/expect-jsx.
Let’s enhance our previous test with this new module:
expect-jsx transforms the passed React elements to JSX strings to nicely compare them. This seems a rather naive approach, but this is completely OK for unit testing.
Using expect-jsx will save you a good amount of time and spare you from having to write things like expect(result.props.children[0].props.children.className).toEqual(‘U mad?’);
expect-jsx is based on algolia/react-element-to-jsx-string. This means that if you’re using tape, chaijs or jasmine, you can easily build the same assertions goodness within a day and publish it to npm.
Since we released react-element-to-jsx-string, developers have implemented JSX diff in multiple assertion libraries:
Warning: If you use Karma runner to launch mocha tests within browsers, you will not have any nice object or string diff. This is currently an issue in the html-reporter.
As of today, the shallow rendering technique does not support simulating clicks using React test utilities Simulate.
This means you have to resort to directly calling the underlying function of your handlers props. Doing so doesn’t introduce any test-specific nonsense, as it’s the same thing Simulate would do in the end.
Let’s change our Button component to illustrate this:
Our test now looks like:
As you can see on line 24, we’re just calling the props.onClick handler directly to check that our custom handler has been called properly. Easy, right?
Well, that’s the way we unit test our component handlers. If you have a better solution, leave it in the comments!
Shallow rendering does not have access to any references you may have defined in your Component, so you cannot use them when testing with the shallow rendering technique. This is being investigated by the React team.
In the meantime test your refs dependent Components using the standard Test Utilities.
At Algolia, we try to minimize the entry cost to a project for any developer. All projects have an npm run test:watch task that we can use to TDD with a rapid feedback loop.
You can easily get one by adding the following to your package.json:
Your development workflow will then look like this:
The whole code used in this article can be found at algolia/react-test-boilerplate.
If you need some DOM features in your tests, check out tmpvar/jsdom and rstacruz/mocha-jsdom.
If you need to run your tests in real browsers, you can use karma-runner or defunctzombie/zuul coupled with Sauce Labs or Browser Stack.
If you liked this post and are interested in a follow-up article about those subjects, leave a comment or tweet @algolia.
Happy coding!
Update November 02 2015
We did a talk about this at ReactJS Paris, here are the slides:
Sources
Create a full-featured search experience in no time.
Powered by Algolia Recommend