Shotgun Episode 2: Writing Tests that Don’t Break

Eric Elliott
JavaScript Scene
Published in
4 min readMar 18, 2016

--

Photo: Brandon Bailey — Midnight Cowboy (CC-BY-2.0)

Shotgun is a new show that lets you ride shotgun with me while I tackle real programming challenges for real apps and libraries. The show is only available to members of EricElliottJS.com, but I’m journaling the adventures here.

In episode 1 we start a brand new React project — an online course presentation engine with React. We covered unit testing with Tape, auto-lint & test with Watch, and bumped into a glitch with Enzyme.

Still Hopeful about Enzyme

In the first episode, we switched to Cheerio for the DOM tests. It’s probably the 5th time I’ve been derailed by Enzyme bugs. I’m really excited about Enzyme, but be prepared to run into bugs and file bug reports. Please feel free to follow those links, investigate the bugs, and file proper issues & PRs. I’d love to do it if I had the time.

At this early stage, Enzyme will probably slow you down more than Cheerio for most of your tests. But keep in mind, Enzyme is just 4 months old as of this writing, and a lot of smart people are working out the issues and smoothing over the API. In 6 months, I expect it will be a very different story.

Writing UI Tests That Last

I don’t know about you, but I’m constantly making changes to my UI markup while I build apps. When you’re testing UI components, it can be easy for every little change to break a bunch of unit tests.

In order to prevent that, I avoid writing tests that know more about the DOM than they need to know. For example, in the Course Player project, we have a `card-player` div that looks like this:

As you can see, it has a `nav-bar`, a select menu, some card content, and a continue button. I have considered moving the card navigation down below the card content. If I was looking for it in the `nav-bar` element test, moving it down would break that test, and I’d have to refactor more than needed.

When I know that something is likely to change shape, I don’t try to replicate the work of all the child tests by testing the full component output. Instead, for container elements, I simply test that the element can be selected, and that it renders children. Let’s look at an example:

Look at the `output` variable. It selects the `.nav-bar` element, grabs the children collection and checks its `.length` property. The `actual` test simply ensures that `.length` is greater than zero, which tells you whether or not its rendering any children.

You could argue that a nav bar should be checking to see if the navigation options are displayed, but the nav element will have its own tests to ensure that the children passed to it will be rendered, so that test would be redundant, and only serve to make the test suite more brittle than it needs to be.

Now, if I decide to move the nav list out of the `.nav-bar` component, sure, maybe I could rethink calling it nav-anything because at that point it’s more of a title bar than a navigation bar, but we’ll cross that bridge if we ever get there.

Boolean Attributes in JSX

HTML has some boolean attributes. In the course player, we use the `disabled` attribute to disable the continue button if the card requirements have not been met, yet, indicating to the student that the card should be completed before attempting to move on.

When writing HTML, you may be tempted to simply add the disabled attribute like this:

While working on this episode, I tried doing this:

And it just magically worked.

Note the `isCompleted` ternary expression. For a minute, I worried that the empty disabled value would cause the `disabled` attribute to try to render with a falsy value, which is not valid HTML, but I was happily reminded that React does the right thing when you pass a falsy value to a boolean attribute: A convenient shortcut that makes working with boolean attributes a breeze.

I think we all expect things to be harder than they really are sometimes. Thankfully, React devs are lazy, and they want things to “just work” the first time.

If you’re a member, feel free to dive into episode 2 now.

If you’re not yet a member, check out the teaser video, and join us. Shotgun is bundled with the Lifetime Access Pass, which gives you access to all our videos: a webcast series and course content covering topics like TDD, prototypal OO, functional programming, React, universal app development, ES6+ and more.

Shotgun Episode 3: Looping Over Child Components in React

Learn JavaScript from Eric Elliott
Become a Lifetime Access Member:
Webcasts
Video experiences
Books & more…

Eric Elliott is the author of “Programming JavaScript Applications” (O’Reilly), and “Learn Universal JavaScript App Development with Node & React”. He has contributed to software experiences for Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher,Frank Ocean, Metallica, and many more.

He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.

--

--