enzymejs / enzyme

JavaScript Testing utilities for React
https://enzymejs.github.io/enzyme/
MIT License
19.95k stars 2.01k forks source link

render(...).html() outputs inner HTML: inconsistent with other html() methods #2442

Open bennettwork opened 4 years ago

bennettwork commented 4 years ago

Current behavior

render(...).html() behaves counterintuitively and inconsistently with the other html() functions.

mount(node).html() and shallow(node).html() will output the node's outer HTML (including root node), but render(node).html() will output only the inner HTML.

const jsx = <div><span>content</span></div>;
// These succeed as you would expect
expect(mount  (jsx).html(), 'mount'  ).to.equal('<div><span>content</span></div>');
expect(shallow(jsx).html(), 'shallow').to.equal('<div><span>content</span></div>');
// This fails because CheerioWrapper's html() outputs only the inner HTML: "<span>content</span>"
expect(render( jsx).html(), 'render' ).to.equal('<div><span>content</span></div>');

Expected behavior

This could be resolved by doing one of the following:

  1. Alter render(node).html() to output the node's outer HTML. (This would be a breaking change. render could return a wrapper around the CheerioWrapper that wraps the node in a div before calling Cheerio's html())

  2. Add a method render(node).outerHtml() that outputs the node's outer HTML. (Again could be done with a wrapper.)

  3. Add a new static method, something like outerHTML(wrapper), that would take a ReactWrapper, ShallowWrapper or CheerioWrapper and output the outer HTML consistently in all three cases.

Your environment

API

Version

library version
enzyme 3.11.0
react 16.13.1
react-dom 16.13.1
react-test-renderer 16.13.1
adapter (below) 1.15.3

Adapter

ljharb commented 4 years ago

render produces a cheerio wrapper, which is exceedingly different from a mount/shallow wrapper, so inconsistencies are expected.

This change was actually an expected breaking change in v3, because cheerio doesn't provide any way i'm aware of to achieve the result you're looking for. A PR to make that happen would definitely be considered!

bennettwork commented 4 years ago

Yes, that was explained well in the docs. It is unfortunate that the Cheerio wrapper has an html() method that has the same name as the Enzyme wrapper method but a different result (inner vs. outer HTML).

It's useful for render to return a Cheerio object as that allows us to utilise all of Cheerio's functionality. If I get time I will investigate wrapping this and adding an outerHtml() method, something like:

outerHtml: function() { return this.wrap('<div></div>').parent().html(); }
ljharb commented 4 years ago

Note that to add anything to a render wrapper, it would have to be added to cheerio itself, not to enzyme.