@samitouri / QOS-React / commits / e1ff342bf7

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});