diff --git a/docs/docs/addons-test-utils.md b/docs/docs/addons-test-utils.md index 7f4d251e1c3..d1055d847be 100644 --- a/docs/docs/addons-test-utils.md +++ b/docs/docs/addons-test-utils.md @@ -304,10 +304,10 @@ Same as [`scryRenderedComponentsWithType()`](#scryrenderedcomponentswithtype) bu ### `createRenderer()` ```javascript -createRenderer() +createRenderer([options]) ``` -Call this in your tests to create a [shallow renderer](#shallow-rendering). +Call this in your tests to create a [shallow renderer](#shallow-rendering). Optionally pass `{createNodeMock: element => mock}` as an optional argument for creating mock refs. * * * diff --git a/src/test/ReactShallowRenderer.js b/src/test/ReactShallowRenderer.js index ee50d9d6efc..00da52730de 100644 --- a/src/test/ReactShallowRenderer.js +++ b/src/test/ReactShallowRenderer.js @@ -32,7 +32,9 @@ class NoopInternalComponent { this._debugID = getNextDebugID(); } } - mountComponent() {} + mountComponent(transaction, hostParent, hostContainerInfo) { + this._hostContainerInfo = hostContainerInfo; + } receiveComponent(element) { this._renderedOutput = element; this._currentElement = element; @@ -42,7 +44,14 @@ class NoopInternalComponent { return undefined; } getPublicInstance() { - return null; + var element = this._currentElement; + var hostContainerInfo = this._hostContainerInfo; + invariant( + hostContainerInfo, + 'hostContainerInfo should be populated before ' + + 'getPublicInstance is called.' + ); + return hostContainerInfo.createNodeMock(element); } } @@ -77,6 +86,14 @@ function _batchedRender(renderer, element, context) { class ReactShallowRenderer { _instance = null; + constructor(options) { + var defaultOptions = { + createNodeMock: function() { + return null; + }, + }; + this._options = Object.assign({}, defaultOptions, options); + } getMountedInstance() { return this._instance ? this._instance._instance : null; } @@ -136,7 +153,8 @@ class ReactShallowRenderer { ); } else { var instance = new ShallowComponentWrapper(element); - ReactReconciler.mountComponent(instance, transaction, null, null, context, 0); + ReactReconciler.mountComponent(instance, transaction, null, this._options, context, 0); + transaction.getReactMountReady().notifyAll(); this._instance = instance; } } diff --git a/src/test/ReactTestUtils.js b/src/test/ReactTestUtils.js index 1a393d426b2..01a49c96b57 100644 --- a/src/test/ReactTestUtils.js +++ b/src/test/ReactTestUtils.js @@ -411,8 +411,8 @@ var ReactTestUtils = { }; }, - createRenderer: function() { - return new ReactShallowRenderer(); + createRenderer: function(options) { + return new ReactShallowRenderer(options); }, Simulate: null, diff --git a/src/test/__tests__/ReactTestUtils-test.js b/src/test/__tests__/ReactTestUtils-test.js index d38caa49c96..d5a33867464 100644 --- a/src/test/__tests__/ReactTestUtils-test.js +++ b/src/test/__tests__/ReactTestUtils-test.js @@ -130,6 +130,33 @@ describe('ReactTestUtils', () => { shallowRenderer.render(); }); + it('can shallow render with a ref and createNodeMock', () => { + var mockInstance = { click: () => {} }; + function createNodeMock(element) { + switch (element.type) { + case 'div': + return mockInstance; + default: + return null; + } + } + + var divRef = null; + class SomeComponent extends React.Component { + render() { + return ( +
{ + divRef = node; + }} /> + ); + } + } + + var shallowRenderer = ReactTestUtils.createRenderer({createNodeMock}); + shallowRenderer.render(); + expect(divRef).toBe(mockInstance); + }); + it('lets you update shallowly rendered components', () => { class SomeComponent extends React.Component { state = {clicked: false};