8

My React component has a suggestionRenderer property that allows to specify how the component is rendered. For example:

<Autosuggest suggestions={getSuburbs}
             suggestionRenderer={renderLocation} />
function renderLocation(suggestion, input) {
  return (
    <span><strong>{suggestion.slice(0, input.length)}</strong>{suggestion.slice(input.length)}</span>
  );
}

Now, I'd like to write a jest test to make sure that suggestionRenderer does its job. Inspecting myElement.getDOMNode().innerHTML reveals:

<span data-reactid=".9.1.$suggestion0.0"><strong data-reactid=".9.1.$suggestion0.0.0">M</strong><span data-reactid=".9.1.$suggestion0.0.1">ill Park</span></span>

which is not particularly useful.

Is there a way to get a clean HTML, without React attributes?

Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746

2 Answers2

6

You can use React.renderToStaticMarkup for this.

expect(React.renderToStaticMarkup(
  <Autosuggest ... suggestionRenderer{renderLocation}/>
))
.to.be('<div>...')

Or just grab innerHTML and strip it manually, but I don't know how reliable that will be cross-browser:

var reactAttrs = / data-react[-\w]+="[^"]+"/g

myElement.getDOMNode().innerHTML.replace(reactAttrs, '')

I used to use React.renderComponentToString and manually strip out the data-react- attrs prior to React.renderToStaticMarkup being added.

Jonny Buchanan
  • 61,926
  • 17
  • 143
  • 150
  • 2
    `React.renderToStaticMarkup` gets `ReactElement` as a parameter, while I have a `ReactComponent` (the result of `TestUtils.scryRenderedDOMComponentsWithClass` is array of `ReactComponent`s). Any idea how to get `ReactElement` from `ReactComponent`? – Misha Moroshko Mar 11 '15 at 10:25
  • You don't need to render to DOM to test with it if you just want to assert the correct output was rendered: `expect(React.renderToStaticMarkup()).to.be('
    ...')` - your component needs to support having any data it renders passed as props, though.
    – Jonny Buchanan Mar 11 '15 at 10:57
  • The element that I want to test is rendered as a response to user events (e.g. user types `'m'`). This is why I render it to DOM. Still wondering if there is a better way that stripping `data-react-*` attributes manually... – Misha Moroshko Mar 11 '15 at 23:04
  • 1
    Use `ReactDOMServer.renderToStaticMarkup` as `React.renderToStaticMarkup.renderToStaticMarkup` is deprecated. – Felipe Cruz Sep 27 '17 at 12:32
2

I generally don't unit test HTML (I figure if React's unit tests are passing, then the HTML generated is good plus I intend to have integration test with selenium to test the HTML anyways) but I do test that the component is generating the correct virtual DOM.

I have a similar component and the way I test auto complete items looks like this.

var testAutoCompleteItems = [{
  display: 'test 1',
  value: 1
}, {
  display: 'test 2',
  value: 2
}, {
  display: 'test 3',
  value: 3
}];

//...

it('should set items based on pass getData property', function(done) {
  Fiber(function() {
    testGlobals.component = React.render(<ExtendText onChange={testHelper.noop} getData={getData} />, div);
    var input = TestUtils.findRenderedDOMComponentWithClass(testGlobals.component, 'extend-text__display-input');

    TestUtils.Simulate.focus(input);

    testHelper.sleep(5);

    var autoCompleteContainer = TestUtils.findRenderedDOMComponentWithClass(testGlobals.component, 'extend-text__auto-complete-container');
    var autoCompleteItems = TestUtils.scryRenderedDOMComponentsWithTag(autoCompleteContainer, 'li');

    //make sure elements are correct
    autoCompleteItems.forEach(function(item, key) {
      expect(item.props['data-key']).to.equal(key);
      expect(item.props.children).to.equal(testAutoCompleteItems[key].display);
    });

    //make sure there is the correct number of elements
    expect(autoCompleteItems.length).to.equal(3);
    done();
  }).run();
});
ryanzec
  • 27,284
  • 38
  • 112
  • 169