diff --git a/packages/enzyme-test-suite/test/Utils-spec.jsx b/packages/enzyme-test-suite/test/Utils-spec.jsx index c6a2a27cb..55e23aa37 100644 --- a/packages/enzyme-test-suite/test/Utils-spec.jsx +++ b/packages/enzyme-test-suite/test/Utils-spec.jsx @@ -2,6 +2,7 @@ import React from 'react'; import { expect } from 'chai'; import wrap from 'mocha-wrap'; import sinon from 'sinon-sandbox'; +import cheerio from 'cheerio'; import { childrenToSimplifiedArray, nodeEqual, @@ -14,6 +15,7 @@ import { isEmptyValue, renderedDive, isCustomComponent, + loadCheerioRoot, } from 'enzyme/build/Utils'; import getAdapter from 'enzyme/build/getAdapter'; import EnzymeAdapter from 'enzyme/build/EnzymeAdapter'; @@ -1073,4 +1075,17 @@ describe('Utils', () => { expect(() => isCustomComponent({}, {})).to.throw(Error); }); }); + + describe('loadCheerioRoot', () => { + it('always returns a Cheerio instance', () => { + expect(loadCheerioRoot()).to.be.an.instanceOf(cheerio); + expect(loadCheerioRoot(null)).to.be.an.instanceOf(cheerio); + expect(loadCheerioRoot("")).to.be.an.instanceOf(cheerio); + expect(loadCheerioRoot("foo")).to.be.an.instanceOf(cheerio); + expect(loadCheerioRoot("123")).to.be.an.instanceOf(cheerio); + expect(loadCheerioRoot("
bar
")).to.be.an.instanceOf(cheerio); + expect(loadCheerioRoot("leading text")).to.be.an.instanceOf(cheerio); + expect(loadCheerioRoot("
malformed< { }); const context = { name: 'foo' }; - expect(() => render(, { context })).to.not.throw(Error); + expect(() => render(, { context })).not.to.throw(); + }); + }); + + describe('rendering non-elements', () => { + it('can render strings', () => { + const StringComponent = createClass({ + render() { + return 'foo'; + }, + }); + + const getWrapper = (options) => render(, options); + if (is('>= 16')) { + expect(getWrapper).to.not.throw(); + + const wrapper = getWrapper(); + expect(wrapper.text()).to.equal('foo'); + expect(wrapper.html()).to.equal('foo'); + expect(String(wrapper)).to.equal('foo'); + expect(wrapper).to.have.lengthOf(1); + } else { + expect(getWrapper).to.throw(); + } + }); + + it('can render numbers', () => { + const NumberComponent = createClass({ + render() { + return 42; + }, + }); + + const getWrapper = (options) => render(, options); + if (is('>= 16')) { + expect(getWrapper).to.not.throw(); + + const wrapper = getWrapper(); + expect(wrapper.text()).to.equal('42'); + expect(wrapper.html()).to.equal('42'); + expect(String(wrapper)).to.equal('42'); + expect(wrapper).to.have.lengthOf(1); + } else { + expect(getWrapper).to.throw(); + } }); }); diff --git a/packages/enzyme/package.json b/packages/enzyme/package.json index 7a3dc4e2a..5787f9b6f 100644 --- a/packages/enzyme/package.json +++ b/packages/enzyme/package.json @@ -36,7 +36,7 @@ "license": "MIT", "dependencies": { "array.prototype.flat": "^1.2.1", - "cheerio": "^1.0.0-rc.2", + "cheerio": "^1.0.0-rc.3", "enzyme-shallow-equal": "^1.0.0", "function.prototype.name": "^1.1.0", "has": "^1.0.3", diff --git a/packages/enzyme/src/ReactWrapper.js b/packages/enzyme/src/ReactWrapper.js index 16980eecd..1e7987df3 100644 --- a/packages/enzyme/src/ReactWrapper.js +++ b/packages/enzyme/src/ReactWrapper.js @@ -1,4 +1,3 @@ -import cheerio from 'cheerio'; import flat from 'array.prototype.flat'; import has from 'has'; @@ -15,6 +14,7 @@ import { cloneElement, renderedDive, isCustomComponent, + loadCheerioRoot, } from './Utils'; import getAdapter from './getAdapter'; import { debugNodes } from './Debug'; @@ -650,7 +650,7 @@ class ReactWrapper { */ render() { const html = this.html(); - return html === null ? cheerio() : cheerio.load('')(html); + return loadCheerioRoot(html); } /** diff --git a/packages/enzyme/src/ShallowWrapper.js b/packages/enzyme/src/ShallowWrapper.js index 7776ec10b..7bb437223 100644 --- a/packages/enzyme/src/ShallowWrapper.js +++ b/packages/enzyme/src/ShallowWrapper.js @@ -1,5 +1,4 @@ import flat from 'array.prototype.flat'; -import cheerio from 'cheerio'; import has from 'has'; import shallowEqual from 'enzyme-shallow-equal'; @@ -20,6 +19,7 @@ import { cloneElement, spyMethod, isEmptyValue, + loadCheerioRoot, } from './Utils'; import getAdapter from './getAdapter'; import { debugNodes } from './Debug'; @@ -1103,7 +1103,8 @@ class ShallowWrapper { * @returns {CheerioWrapper} */ render() { - return this.type() === null ? cheerio() : cheerio.load('')(this.html()); + const html = this.html(); + return loadCheerioRoot(html); } /** diff --git a/packages/enzyme/src/Utils.js b/packages/enzyme/src/Utils.js index 935c069d3..aa0d2edf1 100644 --- a/packages/enzyme/src/Utils.js +++ b/packages/enzyme/src/Utils.js @@ -6,6 +6,8 @@ import functionName from 'function.prototype.name'; import has from 'has'; import flat from 'array.prototype.flat'; import trim from 'string.prototype.trim'; +import cheerio from 'cheerio'; +import { isHtml } from 'cheerio/lib/utils'; import { get } from './configuration'; import { childrenOfNode } from './RSTTraversal'; @@ -350,3 +352,16 @@ export function renderedDive(nodes) { return isEmptyValue(n); }); } + +export function loadCheerioRoot(html) { + if (!html) { + return cheerio.root(); + } + + if (!isHtml(html)) { + // use isDocument=false to create fragment + return cheerio.load(html, null, false).root(); + } + + return cheerio.load('')(html); +} diff --git a/packages/enzyme/src/render.js b/packages/enzyme/src/render.js index bd3871feb..69e12e2b2 100644 --- a/packages/enzyme/src/render.js +++ b/packages/enzyme/src/render.js @@ -1,5 +1,5 @@ -import cheerio from 'cheerio'; import getAdapter from './getAdapter'; +import { loadCheerioRoot } from './Utils'; /** * Renders a react component into static HTML and provides a cheerio wrapper around it. This is @@ -19,5 +19,5 @@ export default function render(node, options = {}) { const adapter = getAdapter(options); const renderer = adapter.createRenderer({ mode: 'string', ...options }); const html = renderer.render(node, options.context); - return cheerio.load('')(html); + return loadCheerioRoot(html); }