Testing Component Methods that Return JSX in React

Kevin Simpson
3 min readApr 1, 2019

In my previous article on basic unit testing React components, I hit the most typical kinds of things that need testing: basic snapshots, checking to see that methods are being called, and to see that state changes are happening properly. There was arguably one big thing that was missing from that article, and it’s the thing that makes front end testing notoriously difficult, and that is testing your markup, or in the case of React, JSX.

JSX, for the uninitiated, looks an awful lot like your run-of-the-mill HTML, save that you can often find JavaScript expressions like variables, function calls, or ternaries sprinkled throughout. This is a big part of what gives React its power, its ability to leverage JSX as a means to use JavaScript more easily when generating content or granting users quick-and-easy interactivity with your application.

One of the most common ways you see React used is by mapping over arrays passed down as props to quickly create a collection of several small chunks of content with a single template. This is typically handled through a method that is called in your JSX like so:

import React, { Component} from 'react';class List extends Component {  generateListItems = () => {
return this.props.list.map((item, index) => {
return <li className='list-item' key={index}>{item}</li>
})
}
render() { return(
<div>
<ul>
{this.generateListItems()}
</ul>
</div>
)
}
}

If you want to properly test this component, you can’t simply stop with your snapshot. You have a method that returns something, and that calls for a test, but how do you evaluate an array of JSX? Normal attempts to look at something like what is returned from an array of two list items would give you something like this:

[ { '$$typeof': Symbol(react.element),
type: 'li',
key: '0',
ref: null,
props:
{ className: 'list-item',
children: 'First list item' },
_owner: null,
_store: {} },
{ '$$typeof': Symbol(react.element),
type: 'li',
key: '1',
ref: null,
props:
{ className: 'list-item',
children: 'Second list item' },
_owner: null,
_store: {}
} ]

This is effectively impossible to test as-is, so we need another solution. Since the whole point of the JSX is to allow us to eventually have some HTML that will render to the DOM, that’s ultimately what we’re really interested in looking at. So, how do we take above, and turn it into just a simple string of HTML that can be evaluated by our testing suite?

First, we want to use the shallow() method from Enzyme in the same way that we simulate rendering our components with normal unit testing:

it("should return some jsx", () => {  const result = wrapper
.instance()
.generateListItems()
.map(point => {
return shallow(point);
});
console.log(result);});

Using map() will allow us to iterate over each returned object and properly call shallow() on it. Without that map() you’ll be trying to call shallow() on an array, and that dog won’t hunt.

The above test will print the following to the console:

[ ShallowWrapper {}, ShallowWrapper {} ]

So, this isn’t really something we can evaluate for testing by itself, not until we dig into the Enzyme docs and look at what methods shallow() provides us with. The one method that we’re specifically interested in here is html() .

This method returns a string of the rendered HTML markup of the entire current render tree, making it handy not only for testing the above generateListItems() method, but also for testing methods that return an array of child React components.

If we change our above test to leverage the html() method:

it("should return some jsx", () => {const result = wrapper
.instance()
.generateListItems()
.map(point => {
return shallow(point).html();
});
console.log(result);});

… we’ll instead log something like this:

[ 
'<li className="list-item">\n First list item \n</li>',
'<li className="list-item">\n Second list item \n</li>'
]

Now we’re in business! We can now actually anticipate what will be returned by shallow().html() and read it like a human being, which means we can test it appropriately!

it("should return some jsx", () => {
const expected = [
'<li className="list-item">\n First list item \n</li>',
'<li className="list-item">\n Second list item \n</li>'
]
const result = wrapper
.instance()
.generateListItems()
.map(point => {
return shallow(point).html();
});
expect(result).toEqual(expected);
});

And that’s it, how you test something that returns JSX!

--

--

Kevin Simpson

Front End/JS Developer for Trimble SketchUp, Turing School graduate, 8th-level Bard