Support ForwardRef type of work in TestRenderer (#12392)
* Support ForwardRef type of work in TestRenderer and ShallowRenderer. * Release script now updates inter-package dependencies too (e.g. react-test-renderer depends on react-is).
Jason Quense committed
Mar 16, 2018 at 14:18 UTC
e1ff342bf7f451fb995e0ea2bfb10889deef022f
7 files changed
+88
-16
packages/react-is/src/ReactIs.js
+1
-1
@@ -34,7 +34,7 @@ export function typeOf(object: any) {
34
case REACT_STRICT_MODE_TYPE:
35
return type;
36
default:
37
- const $$typeofType = type.$$typeof;
37
+ const $$typeofType = type && type.$$typeof;
38
39
switch ($$typeofType) {
40
case REACT_CONTEXT_TYPE:
packages/react-test-renderer/package.json
+4
-13
@@ -4,11 +4,7 @@
4
"description": "React package for snapshot testing.",
5
"main": "index.js",
6
"repository": "facebook/react",
7
- "keywords": [
8
- "react",
9
- "react-native",
10
- "react-testing"
11
- ],
7
+ "keywords": ["react", "react-native", "react-testing"],
8
"license": "MIT",
9
"bugs": {
10
"url": "https://github.com/facebook/react/issues"
@@ -17,16 +13,11 @@
13
"dependencies": {
14
"fbjs": "^0.8.16",
15
"object-assign": "^4.1.1",
20
- "prop-types": "^15.6.0"
16
+ "prop-types": "^15.6.0",
17
+ "react-is": "^16.3.0-alpha.2"
18
},
19
"peerDependencies": {
20
"react": "^16.0.0 || 16.3.0-alpha.2"
21
},
25
- "files": [
26
- "LICENSE",
27
- "README.md",
28
- "index.js",
29
- "shallow.js",
30
- "cjs/"
31
- ]
22
+ "files": ["LICENSE", "README.md", "index.js", "shallow.js", "cjs/"]
23
}
packages/react-test-renderer/src/ReactShallowRenderer.js
+5
-2
@@ -7,6 +7,7 @@
7
*/
8
9
import React from 'react';
10
+import {isForwardRef} from 'react-is';
11
import {warnAboutDeprecatedLifecycles} from 'shared/ReactFeatureFlags';
12
import describeComponentFrame from 'shared/describeComponentFrame';
13
import getComponentName from 'shared/getComponentName';
@@ -77,7 +78,7 @@ class ReactShallowRenderer {
78
element.type,
79
);
80
invariant(
80
- typeof element.type === 'function',
81
+ isForwardRef(element) || typeof element.type === 'function',
82
'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
83
'components, but the provided element type was `%s`.',
84
Array.isArray(element.type)
@@ -96,7 +97,9 @@ class ReactShallowRenderer {
97
if (this._instance) {
98
this._updateClassComponent(element, this._context);
99
} else {
99
- if (shouldConstruct(element.type)) {
100
+ if (isForwardRef(element)) {
101
+ this._rendered = element.type.render(element.props, element.ref);
102
+ } else if (shouldConstruct(element.type)) {
103
this._instance = new element.type(
104
element.props,
105
this._context,
packages/react-test-renderer/src/ReactTestRenderer.js
+3
@@ -25,6 +25,7 @@ import {
25
ContextConsumer,
26
ContextProvider,
27
Mode,
28
+ ForwardRef,
29
} from 'shared/ReactTypeOfWork';
30
import invariant from 'fbjs/lib/invariant';
31
@@ -372,6 +373,7 @@ function toTree(node: ?Fiber) {
373
case ContextProvider:
374
case ContextConsumer:
375
case Mode:
376
+ case ForwardRef:
377
return childrenToTree(node.child);
378
default:
379
invariant(
@@ -472,6 +474,7 @@ class ReactTestInstance {
474
case ContextProvider:
475
case ContextConsumer:
476
case Mode:
477
+ case ForwardRef:
478
descend = true;
479
break;
480
default:
packages/react-test-renderer/src/__tests__/ReactShallowRenderer-test.js
+22
@@ -168,6 +168,28 @@ describe('ReactShallowRenderer', () => {
168
]);
169
});
170
171
+ it('should handle ForwardRef', () => {
172
+ const testRef = React.createRef();
173
+ const SomeComponent = React.forwardRef((props, ref) => {
174
+ expect(ref).toEqual(testRef);
175
+ return (
176
+ <div>
177
+ <span className="child1" />
178
+ <span className="child2" />
179
+ </div>
180
+ );
181
+ });
182
+
183
+ const shallowRenderer = createRenderer();
184
+ const result = shallowRenderer.render(<SomeComponent ref={testRef} />);
185
+
186
+ expect(result.type).toBe('div');
187
+ expect(result.props.children).toEqual([
188
+ <span className="child1" />,
189
+ <span className="child2" />,
190
+ ]);
191
+ });
192
+
193
it('should enable shouldComponentUpdate to prevent a re-render', () => {
194
let renderCounter = 0;
195
class SimpleComponent extends React.Component {
packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js
+43
@@ -404,6 +404,7 @@ describe('ReactTestRenderer', () => {
404
log.push('Angry render');
405
throw new Error('Please, do not render me.');
406
}
407
+
408
componentDidMount() {
409
log.push('Angry componentDidMount');
410
}
@@ -957,4 +958,46 @@ describe('ReactTestRenderer', () => {
958
}),
959
);
960
});
961
+
962
+ it('supports forwardRef', () => {
963
+ const InnerRefed = React.forwardRef((props, ref) => (
964
+ <div>
965
+ <span ref={ref} />
966
+ </div>
967
+ ));
968
+
969
+ class App extends React.Component {
970
+ render() {
971
+ return <InnerRefed ref={r => (this.ref = r)} />;
972
+ }
973
+ }
974
+
975
+ const renderer = ReactTestRenderer.create(<App />);
976
+ const tree = renderer.toTree();
977
+ cleanNodeOrArray(tree);
978
+
979
+ expect(prettyFormat(tree)).toEqual(
980
+ prettyFormat({
981
+ instance: null,
982
+ nodeType: 'component',
983
+ props: {},
984
+ rendered: {
985
+ instance: null,
986
+ nodeType: 'host',
987
+ props: {},
988
+ rendered: [
989
+ {
990
+ instance: null,
991
+ nodeType: 'host',
992
+ props: {},
993
+ rendered: [],
994
+ type: 'span',
995
+ },
996
+ ],
997
+ type: 'div',
998
+ },
999
+ type: App,
1000
+ }),
1001
+ );
1002
+ });
1003
});
scripts/release/build-commands/update-package-versions.js
+10
@@ -78,6 +78,16 @@ const update = async ({cwd, dry, packages, version}) => {
78
if (prerelease) {
79
json.peerDependencies.react += ` || ${version}`;
80
}
81
+
82
+ // Update inter-package dependencies as well.
83
+ // e.g. react-test-renderer depends on react-is
84
+ if (json.dependencies) {
85
+ Object.keys(json.dependencies).forEach(dependency => {
86
+ if (packages.indexOf(dependency) >= 0) {
87
+ json.dependencies[dependency] = `^${version}`;
88
+ }
89
+ });
90
+ }
91
}
92
93
await writeJson(path, json, {spaces: 2});