diff --git a/docs/api/render.md b/docs/api/render.md index dab1cf262..3123b25c3 100644 --- a/docs/api/render.md +++ b/docs/api/render.md @@ -19,7 +19,6 @@ constructors. import { render } from 'enzyme'; describe('', () => { - it('renders three `.foo-bar`s', () => { const wrapper = render(); expect(wrapper.find('.foo-bar')).to.have.length(3); @@ -30,5 +29,19 @@ describe('', () => { expect(wrapper.text()).to.contain("unique"); }); + it('can pass in context', () => { + const SimpleComponent = React.createClass({ + contextTypes: { + name: React.PropTypes.string, + }, + render() { + return
{this.context.name}
; + }, + }); + + const context = { name: 'foo' }; + const wrapper = render(, { context }); + expect(wrapper.text()).to.equal('foo'); + }); }); ``` diff --git a/src/render.jsx b/src/render.jsx index 0ba17df60..ac98fa359 100644 --- a/src/render.jsx +++ b/src/render.jsx @@ -1,3 +1,5 @@ +import React from 'react'; +import objectAssign from 'object.assign'; import cheerio from 'cheerio'; import { renderToStaticMarkup } from './react-compat'; @@ -11,9 +13,34 @@ import { renderToStaticMarkup } from './react-compat'; * thus I'd like to keep this API in here even though it's not really "ours". * * @param node + * @param options * @returns {Cheerio} */ -export default function render(node) { + +function createContextWrapperForNode(node, context, childContextTypes) { + class ContextWrapper extends React.Component { + getChildContext() { + return context; + } + render() { + return node; + } + } + ContextWrapper.childContextTypes = childContextTypes; + return ContextWrapper; +} + +export default function render(node, options = {}) { + if (options.context && (node.type.contextTypes || options.childContextTypes)) { + const childContextTypes = objectAssign( + {}, + node.type.contextTypes || {}, + options.childContextTypes, + ); + const ContextWrapper = createContextWrapperForNode(node, options.context, childContextTypes); + const html = renderToStaticMarkup(); + return cheerio.load(html).root(); + } const html = renderToStaticMarkup(node); return cheerio.load(html).root(); } diff --git a/test/staticRender-spec.jsx b/test/staticRender-spec.jsx new file mode 100644 index 000000000..39a1c663d --- /dev/null +++ b/test/staticRender-spec.jsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { expect } from 'chai'; +import { describeWithDOM, describeIf } from './_helpers'; +import { render } from '../src/'; +import { REACT013 } from '../src/version'; + +describeWithDOM('render', () => { + describeIf(!REACT013, 'context', () => { + it('can pass in context', () => { + const SimpleComponent = React.createClass({ + contextTypes: { + name: React.PropTypes.string, + }, + render() { + return
{this.context.name}
; + }, + }); + + const context = { name: 'foo' }; + const wrapper = render(, { context }); + expect(wrapper.text()).to.equal('foo'); + }); + it('can pass context to the child of mounted component', () => { + const SimpleComponent = React.createClass({ + contextTypes: { + name: React.PropTypes.string, + }, + render() { + return
{this.context.name}
; + }, + }); + const ComplexComponent = React.createClass({ + render() { + return
; + }, + }); + + const childContextTypes = { + name: React.PropTypes.string.isRequired, + }; + const context = { name: 'foo' }; + const wrapper = render(, { context, childContextTypes }); + expect(wrapper.children()).to.have.length(1); + expect(wrapper.children().first().text()).to.equal('foo'); + }); + it('should not throw if context is passed in but contextTypes is missing', () => { + const SimpleComponent = React.createClass({ + render() { + return
{this.context.name}
; + }, + }); + + const context = { name: 'foo' }; + expect(() => render(, { context })).to.not.throw(Error); + }); + }); +});