@samitouri / QOS-React-2 / commits / c901b1005e

Make createDescriptor return a descriptor for components

This moves all logic around legacy descriptors to ReactLegacyDescriptor. This is responsible for the layer that knows that createClass exports a legacy factory. When passed one of these classes, it unwraps it to be a real class. If it is passed a non legacy factory, it is assumed to be a non-react component that needs to be invoked as a plain function. The semantic change is that a descriptor is now always returned if passed a legacy factory. Even if that factory is a mock. A mock would previously return undefined. For mocks, I treat the factory as the authoritative function. I call it to extract the instance or fill it with an empty component placeholder. Additionally, I make the classes take props as the first argument to the constructor. This is what the new class system will do. We currently need to set up some internals by calling the internal construct method. Instead of doing that automatically in the constructor, I now move that to a second pass so that mocks can get the plain props. This means that we can assert that a mock has been called once it's mounted with it's final props. Instead of the descriptor factory being called.

Sebastian Markbage committed Aug 19, 2014 at 23:16 UTC c901b1005e7c946584487bb8b0bf7b60a773645b
11 files changed +275 -100
src/browser/ReactDOM.js
+2 -2
@@ -43,8 +43,8 @@ var mapObject = require('mapObject');
43 * @private
44 */
45 function createDOMComponentClass(omitClose, tag) {
46 - var Constructor = function(descriptor) {
47 - this.construct(descriptor);
46 + var Constructor = function(props) {
47 + // This constructor and it's argument is currently used by mocks.
48 };
49 Constructor.prototype = new ReactDOMComponent(tag, omitClose);
50 Constructor.prototype.constructor = Constructor;
src/browser/ReactTextComponent.js
+2 -2
@@ -42,8 +42,8 @@ var mixInto = require('mixInto');
42 * @extends ReactComponent
43 * @internal
44 */
45 -var ReactTextComponent = function(descriptor) {
46 - this.construct(descriptor);
45 +var ReactTextComponent = function(props) {
46 + // This constructor and it's argument is currently used by mocks.
47 };
48
49 mixInto(ReactTextComponent, ReactComponent.Mixin);
src/browser/ui/React.js
+11 -8
@@ -35,6 +35,7 @@ var ReactDOM = require('ReactDOM');
35 var ReactDOMComponent = require('ReactDOMComponent');
36 var ReactDefaultInjection = require('ReactDefaultInjection');
37 var ReactInstanceHandles = require('ReactInstanceHandles');
38 +var ReactLegacyDescriptor = require('ReactLegacyDescriptor');
39 var ReactMount = require('ReactMount');
40 var ReactMultiChild = require('ReactMultiChild');
41 var ReactPerf = require('ReactPerf');
@@ -46,20 +47,22 @@ var onlyChild = require('onlyChild');
47
48 ReactDefaultInjection.inject();
49
49 -// TODO: Restore the real create descriptor
50 -// var createDescriptor = ReactDescriptor.createDescriptor;
51 -var createDescriptor = function(type, props, children) {
52 - // Because of issues with mocks, we temporarily execute the factory function
53 - var args = Array.prototype.slice.call(arguments, 1);
54 - return type.apply(null, args);
55 -};
50 +var createDescriptor = ReactDescriptor.createDescriptor;
51 var createFactory = ReactDescriptor.createFactory;
52
53 if (__DEV__) {
59 - // createDescriptor = ReactDescriptorValidator.createDescriptor;
54 + createDescriptor = ReactDescriptorValidator.createDescriptor;
55 createFactory = ReactDescriptorValidator.createFactory;
56 }
57
58 +// TODO: Drop legacy descriptors once classes no longer export these factories
59 +createDescriptor = ReactLegacyDescriptor.wrapCreateDescriptor(
60 + createDescriptor
61 +);
62 +createFactory = ReactLegacyDescriptor.wrapCreateFactory(
63 + createFactory
64 +);
65 +
66 var React = {
67 Children: {
68 map: ReactChildren.map,
src/core/ReactCompositeComponent.js
+4 -2
@@ -1350,8 +1350,10 @@ var ReactCompositeComponent = {
1350 * @public
1351 */
1352 createClass: function(spec) {
1353 - var Constructor = function(props, owner) {
1354 - this.construct(props, owner);
1353 + var Constructor = function(props) {
1354 + // This constructor is overridden by mocks. The argument is used
1355 + // by mocks to assert on what gets mounted. This will later be used
1356 + // by the stand-alone class implementation.
1357 };
1358 Constructor.prototype = new ReactCompositeComponentBase();
1359 Constructor.prototype.constructor = Constructor;
src/core/ReactDescriptor.js
+13 -33
@@ -131,33 +131,9 @@ if (__DEV__) {
131 defineMutationMembrane(ReactDescriptor.prototype);
132 }
133
134 -ReactDescriptor.createDescriptor = function(type, config, children) {
135 - if (type.isReactLegacyFactory) {
136 - // This is probably a legacy factory created by ReactCompositeComponent.
137 - // We unwrap it to get to the underlying class.
138 - // TODO: Drop this check when we drop ReactLegacyDescriptor.
139 - type = type.type;
140 - }
141 -
142 - if (typeof type === 'function') {
143 - var isReactClass =
144 - typeof type.prototype.mountComponent === 'function' &&
145 - typeof type.prototype.receiveComponent === 'function';
146 - if (!isReactClass) {
147 - // This is being called with a plain function we should invoke it
148 - // immediately as if this was used with legacy JSX.
149 - if (__DEV__) {
150 - warning(
151 - false,
152 - 'This JSX uses a plain function. Only React components are valid in' +
153 - 'JSX.'
154 - );
155 - }
156 - var args = Array.prototype.slice.call(arguments, 1);
157 - return type.apply(null, args);
158 - }
159 - }
134 +ReactDescriptor.prototype._isReactDescriptor = true;
135
136 +ReactDescriptor.createDescriptor = function(type, config, children) {
137 var propName;
138
139 // Reserved names are extracted
@@ -212,12 +188,6 @@ ReactDescriptor.createDescriptor = function(type, config, children) {
188 };
189
190 ReactDescriptor.createFactory = function(type) {
215 - if (type.isReactLegacyFactory) {
216 - // This is probably a legacy factory created by ReactCompositeComponent.
217 - // We unwrap it to get to the underlying class.
218 - // TODO: Drop this check when we drop ReactLegacyDescriptor.
219 - type = type.type;
220 - }
191 var factory = ReactDescriptor.createDescriptor.bind(null, type);
192 // Expose the type on the factory and the prototype so that it can be
193 // easily accessed on descriptors. E.g. <Foo />.type === Foo.type.
@@ -264,7 +234,17 @@ ReactDescriptor.isValidFactory = function(factory) {
234 * @final
235 */
236 ReactDescriptor.isValidDescriptor = function(object) {
267 - return object instanceof ReactDescriptor;
237 + // ReactTestUtils is often used outside of beforeEach where as React is
238 + // within it. This leads to two different instances of React on the same
239 + // page. To identify a descriptor from a different React instance we use
240 + // a flag instead of an instanceof check.
241 + var isDescriptor = !!(object && object._isReactDescriptor);
242 + // if (isDescriptor && !(object instanceof ReactDescriptor)) {
243 + // This is an indicator that you're using multiple versions of React at the
244 + // same time. This will screw with ownership and stuff. Fix it, please.
245 + // TODO: We could possibly warn here.
246 + // }
247 + return isDescriptor;
248 };
249
250 module.exports = ReactDescriptor;
src/core/ReactDescriptorValidator.js
-6
@@ -260,12 +260,6 @@ var ReactDescriptorValidator = {
260 },
261
262 createFactory: function(type) {
263 - if (type.isReactLegacyFactory) {
264 - // This is probably a legacy factory created by ReactCompositeComponent.
265 - // We unwrap it to get to the underlying class.
266 - // TODO: Drop this check when we drop ReactLegacyDescriptor.
267 - type = type.type;
268 - }
263 var validatedFactory = ReactDescriptorValidator.createDescriptor.bind(
264 null,
265 type
src/core/ReactLegacyDescriptor.js
+114 -3
@@ -18,9 +18,56 @@
18
19 "use strict";
20
21 +var ReactCurrentOwner = require('ReactCurrentOwner');
22 var ReactDescriptor = require('ReactDescriptor');
23
24 var invariant = require('invariant');
25 +var monitorCodeUse = require('monitorCodeUse');
26 +var warning = require('warning');
27 +
28 +var legacyFactoryLogs = {};
29 +function warnForLegacyFactoryCall() {
30 + if (!ReactLegacyDescriptorFactory._isLegacyCallWarningEnabled) {
31 + return;
32 + }
33 + var owner = ReactCurrentOwner.current;
34 + var name = owner && owner.constructor ? owner.constructor.displayName : 'N/A';
35 + if (legacyFactoryLogs.hasOwnProperty(name)) {
36 + return;
37 + }
38 + legacyFactoryLogs[name] = true;
39 + // TODO: Warn for this.
40 + monitorCodeUse('react_legacy_factory_call', { name: name });
41 +}
42 +
43 +function warnForPlainFunctionType(type) {
44 + var isReactClass =
45 + typeof type.prototype.mountComponent === 'function' &&
46 + typeof type.prototype.receiveComponent === 'function';
47 + if (isReactClass) {
48 + warning(
49 + false,
50 + 'Did not expect to get a React class here. Use `Component` instead ' +
51 + 'of `Component.type` or `this.constructor`.'
52 + );
53 + } else {
54 + if (!type._reactWarnedForThisType) {
55 + try {
56 + type._reactWarnedForThisType = true;
57 + } catch (x) {
58 + // just incase this is a frozen object or some special object
59 + }
60 + monitorCodeUse('react_non_component_in_jsx', { name: type.name });
61 + }
62 + // TODO: This pattern is heavily used by ReactMenu and therefore we
63 + // cannot yet warn without spamming users too much.
64 + // warning(
65 + // false,
66 + // 'This JSX uses a plain function. Only React components are ' +
67 + // 'valid in React\'s JSX transform.'
68 + // );
69 + }
70 +}
71
72 /**
73 * Transfer static properties from the source to the target. Functions are
@@ -50,22 +97,86 @@ function proxyStaticMethods(target, source) {
97 }
98 }
99
100 +// We use an object instead of a boolean because booleans are ignored by our
101 +// mocking libraries when these factories gets mocked.
102 +var LEGACY_MARKER = {};
103 +
104 var ReactLegacyDescriptorFactory = {};
105
106 +ReactLegacyDescriptorFactory.wrapCreateFactory = function(createFactory) {
107 + var legacyCreateFactory = function(type) {
108 + if (typeof type !== 'function') {
109 + // Non-function types cannot be legacy factories
110 + return createFactory(type);
111 + }
112 +
113 + if (type.isReactLegacyFactory) {
114 + // This is probably a legacy factory created by ReactCompositeComponent.
115 + // We unwrap it to get to the underlying class.
116 + return createFactory(type.type);
117 + }
118 +
119 + if (__DEV__) {
120 + warnForPlainFunctionType(type);
121 + }
122 +
123 + // Unless it's a legacy factory, then this is probably a plain function,
124 + // that is expecting to be invoked by JSX. We can just return it as is.
125 + return type;
126 + };
127 + return legacyCreateFactory;
128 +};
129 +
130 +ReactLegacyDescriptorFactory.wrapCreateDescriptor = function(createDescriptor) {
131 + var legacyCreateDescriptor = function(type, props, children) {
132 + if (typeof type !== 'function') {
133 + // Non-function types cannot be legacy factories
134 + return createDescriptor.apply(this, arguments);
135 + }
136 +
137 + if (type.isReactLegacyFactory) {
138 + // This is probably a legacy factory created by ReactCompositeComponent.
139 + // We unwrap it to get to the underlying class.
140 + if (type._isMockFunction) {
141 + // If this is a mock function, people will expect it to be called. We
142 + // will actually call the original mock factory function instead. This
143 + // future proofs unit testing that assume that these are classes.
144 + type.type._mockedReactClassConstructor = type;
145 + }
146 + var args = Array.prototype.slice.call(arguments, 0);
147 + args[0] = type.type;
148 + return createDescriptor.apply(this, args);
149 + }
150 +
151 + if (__DEV__) {
152 + warnForPlainFunctionType(type);
153 + }
154 +
155 + // This is being called with a plain function we should invoke it
156 + // immediately as if this was used with legacy JSX.
157 + return type.apply(null, Array.prototype.slice.call(arguments, 1));
158 + };
159 + return legacyCreateDescriptor;
160 +};
161 +
162 ReactLegacyDescriptorFactory.wrapFactory = function(factory) {
163 invariant(
164 ReactDescriptor.isValidFactory(factory),
165 'This is suppose to accept a descriptor factory'
166 );
167 var legacyDescriptorFactory = function(config, children) {
61 - // This factory should not be called when the new JSX transform is in place.
62 - // TODO: Warning - Use JSX instead of direct function calls.
168 + // This factory should not be called when JSX is used. Use JSX instead.
169 + if (__DEV__) {
170 + warnForLegacyFactoryCall();
171 + }
172 return factory.apply(this, arguments);
173 };
174 proxyStaticMethods(legacyDescriptorFactory, factory.type);
66 - legacyDescriptorFactory.isReactLegacyFactory = true;
175 + legacyDescriptorFactory.isReactLegacyFactory = LEGACY_MARKER;
176 legacyDescriptorFactory.type = factory.type;
177 return legacyDescriptorFactory;
178 };
179
180 +ReactLegacyDescriptorFactory._isLegacyCallWarningEnabled = true;
181 +
182 module.exports = ReactLegacyDescriptorFactory;
src/core/__tests__/ReactDescriptor-test.js
+45 -18
@@ -38,7 +38,7 @@ describe('ReactDescriptor', function() {
38 });
39
40 it('returns a complete descriptor according to spec', function() {
41 - var descriptor = React.createFactory(ComponentClass)();
41 + var descriptor = React.createFactory(ComponentFactory)();
42 expect(descriptor.type).toBe(ComponentClass);
43 expect(descriptor.key).toBe(null);
44 expect(descriptor.ref).toBe(null);
@@ -54,20 +54,20 @@ describe('ReactDescriptor', function() {
54 });
55
56 it('returns an immutable descriptor', function() {
57 - var descriptor = React.createFactory(ComponentClass)();
57 + var descriptor = React.createFactory(ComponentFactory)();
58 expect(() => descriptor.type = 'div').toThrow();
59 });
60
61 it('does not reuse the original config object', function() {
62 var config = { foo: 1 };
63 - var descriptor = React.createFactory(ComponentClass)(config);
63 + var descriptor = React.createFactory(ComponentFactory)(config);
64 expect(descriptor.props.foo).toBe(1);
65 config.foo = 2;
66 expect(descriptor.props.foo).toBe(1);
67 });
68
69 it('extracts key and ref from the config', function() {
70 - var descriptor = React.createFactory(ComponentClass)({
70 + var descriptor = React.createFactory(ComponentFactory)({
71 key: '12',
72 ref: '34',
73 foo: '56'
@@ -79,7 +79,7 @@ describe('ReactDescriptor', function() {
79 });
80
81 it('coerces the key to a string', function() {
82 - var descriptor = React.createFactory(ComponentClass)({
82 + var descriptor = React.createFactory(ComponentFactory)({
83 key: 12,
84 foo: '56'
85 });
@@ -90,7 +90,7 @@ describe('ReactDescriptor', function() {
90 });
91
92 it('preserves the context on the descriptor', function() {
93 - var Component = React.createFactory(ComponentClass);
93 + var Component = React.createFactory(ComponentFactory);
94 var descriptor;
95
96 var Wrapper = React.createClass({
@@ -112,7 +112,7 @@ describe('ReactDescriptor', function() {
112 });
113
114 it('preserves the owner on the descriptor', function() {
115 - var Component = React.createFactory(ComponentClass);
115 + var Component = React.createFactory(ComponentFactory);
116 var descriptor;
117
118 var Wrapper = React.createClass({
@@ -136,7 +136,7 @@ describe('ReactDescriptor', function() {
136 it('merges an additional argument onto the children prop', function() {
137 spyOn(console, 'warn');
138 var a = 1;
139 - var descriptor = React.createFactory(ComponentClass)({
139 + var descriptor = React.createFactory(ComponentFactory)({
140 children: 'text'
141 }, a);
142 expect(descriptor.props.children).toBe(a);
@@ -145,7 +145,7 @@ describe('ReactDescriptor', function() {
145
146 it('does not override children if no rest args are provided', function() {
147 spyOn(console, 'warn');
148 - var descriptor = React.createFactory(ComponentClass)({
148 + var descriptor = React.createFactory(ComponentFactory)({
149 children: 'text'
150 });
151 expect(descriptor.props.children).toBe('text');
@@ -154,7 +154,7 @@ describe('ReactDescriptor', function() {
154
155 it('overrides children if null is provided as an argument', function() {
156 spyOn(console, 'warn');
157 - var descriptor = React.createFactory(ComponentClass)({
157 + var descriptor = React.createFactory(ComponentFactory)({
158 children: 'text'
159 }, null);
160 expect(descriptor.props.children).toBe(null);
@@ -164,14 +164,14 @@ describe('ReactDescriptor', function() {
164 it('merges rest arguments onto the children prop in an array', function() {
165 spyOn(console, 'warn');
166 var a = 1, b = 2, c = 3;
167 - var descriptor = React.createFactory(ComponentClass)(null, a, b, c);
167 + var descriptor = React.createFactory(ComponentFactory)(null, a, b, c);
168 expect(descriptor.props.children).toEqual([1, 2, 3]);
169 expect(console.warn.argsForCall.length).toBe(0);
170 });
171
172 it('warns for keys for arrays of descriptors in rest args', function() {
173 spyOn(console, 'warn');
174 - var Component = React.createFactory(ComponentClass);
174 + var Component = React.createFactory(ComponentFactory);
175
176 Component(null, [ Component(), Component() ]);
177
@@ -183,7 +183,7 @@ describe('ReactDescriptor', function() {
183
184 it('does not warn when the descriptor is directly in rest args', function() {
185 spyOn(console, 'warn');
186 - var Component = React.createFactory(ComponentClass);
186 + var Component = React.createFactory(ComponentFactory);
187
188 Component(null, Component(), Component());
189
@@ -192,7 +192,7 @@ describe('ReactDescriptor', function() {
192
193 it('does not warn when the array contains a non-descriptor', function() {
194 spyOn(console, 'warn');
195 - var Component = React.createFactory(ComponentClass);
195 + var Component = React.createFactory(ComponentFactory);
196
197 Component(null, [ {}, {} ]);
198
@@ -248,12 +248,39 @@ describe('ReactDescriptor', function() {
248 return 21 + x;
249 });
250 expect(factory(21)).toBe(42);
251 - expect(console.warn.argsForCall.length).toBe(1);
252 - expect(console.warn.argsForCall[0][0]).toContain(
253 - 'This JSX uses a plain function.'
254 - );
251 + // TODO: This warning is temporarily disabled
252 + expect(console.warn.argsForCall.length).toBe(0);
253 + // expect(console.warn.argsForCall[0][0]).toContain(
254 + // 'This JSX uses a plain function.'
255 + // );
256 });
257
258 + it('warns but allow a plain function to be immediately invoked', function() {
259 + spyOn(console, 'warn');
260 + var result = React.createDescriptor(function (x, y) {
261 + return 21 + x + y;
262 + }, 11, 10);
263 + expect(result).toBe(42);
264 + // TODO: This warning is temporarily disabled
265 + expect(console.warn.argsForCall.length).toBe(0);
266 + // expect(console.warn.argsForCall[0][0]).toContain(
267 + // 'This JSX uses a plain function.'
268 + // );
269 + });
270 +
271 + it('warns but does not fail on undefined results', function() {
272 + spyOn(console, 'warn');
273 + var fn = function () { };
274 + var result = React.createDescriptor(fn, 1, 2, null);
275 + expect(result).toBe(undefined);
276 + // TODO: This warning is temporarily disabled
277 + expect(console.warn.argsForCall.length).toBe(0);
278 + // expect(console.warn.argsForCall[0][0]).toContain(
279 + // 'This JSX uses a plain function.'
280 + // );
281 + });
282 +
283 +
284 it('should expose the underlying class from a legacy factory', function() {
285 var Legacy = React.createClass({ render: function() { } });
286 var factory = React.createFactory(Legacy);
src/core/instantiateReactComponent.js
+79 -22
@@ -19,45 +19,102 @@
19
20 "use strict";
21
22 -var invariant = require('invariant');
22 +var warning = require('warning');
23 +
24 +var ReactDescriptor = require('ReactDescriptor');
25 +var ReactLegacyDescriptor = require('ReactLegacyDescriptor');
26 +var ReactEmptyComponent = require('ReactEmptyComponent');
27
28 /**
25 - * Validate a `componentDescriptor`. This should be exposed publicly in a follow
26 - * up diff.
29 + * Given `type` and `props` invoke the type function and create an instance from
30 + * it. For the normal case it just runs the constructor. For mocks we need to
31 + * invoke the convenience constructor and resolve that into an instance.
32 *
28 - * @param {object} descriptor
29 - * @return {boolean} Returns true if this is a valid descriptor of a Component.
33 + * @param {function} type
34 + * @param {*} props
35 + * @return {object} A new instance of `type`.
36 + * @protected
37 */
31 -function isValidComponentDescriptor(descriptor) {
32 - return !!descriptor && (
33 - (
34 - typeof descriptor.type === 'function' &&
35 - typeof descriptor.type.prototype.mountComponent === 'function' &&
36 - typeof descriptor.type.prototype.receiveComponent === 'function'
37 - ) || typeof descriptor.type === 'string'
38 - );
38 +function createInstance(type, props) {
39 + if (__DEV__) {
40 + if (type._mockedReactClassConstructor) {
41 + // If this is a mocked class, we treat the legacy factory as if it was the
42 + // class constructor for future proofing unit tests. Because this might
43 + // be mocked as a legacy factory, we ignore any warnings triggerd by
44 + // this temporary hack.
45 + ReactLegacyDescriptor._isLegacyCallWarningEnabled = false;
46 + var instance;
47 + try {
48 + instance = new type._mockedReactClassConstructor(props);
49 + } finally {
50 + ReactLegacyDescriptor._isLegacyCallWarningEnabled = true;
51 + }
52 +
53 + // If the mock implementation was a legacy factory, then it returns a
54 + // descriptor. We need to turn this into a real component instance.
55 + if (ReactDescriptor.isValidDescriptor(instance)) {
56 + type = instance.type;
57 + props = instance.props;
58 + instance = new type(props);
59 + }
60 +
61 + var render = instance.render;
62 + if (!render) {
63 + // For auto-mocked factories, the prototype isn't shimmed and therefore
64 + // there is no render function on the instance. We replace the whole
65 + // component with an empty component instance instead.
66 + var descriptor = ReactEmptyComponent.getEmptyComponent();
67 + type = descriptor.type;
68 + props = descriptor.props;
69 + instance = new type(props);
70 + } else if (render._isMockFunction && !render._getMockImplementation()) {
71 + // Auto-mocked components may have a prototype with a mocked render
72 + // function. For those, we'll need to mock the result of the render
73 + // since we consider undefined to be invalid results from render.
74 + render.mockImplementation(
75 + ReactEmptyComponent.getEmptyComponent
76 + );
77 + }
78 + }
79 + }
80 + // Normal case for non-mocks
81 + return new type(props);
82 }
83
84 /**
85 * Given a `componentDescriptor` create an instance that will actually be
43 - * mounted. Currently it just extracts an existing clone from composite
44 - * components but this is an implementation detail which will change.
86 + * mounted.
87 *
88 * @param {object} descriptor
89 * @return {object} A new instance of componentDescriptor's constructor.
90 * @protected
91 */
92 function instantiateReactComponent(descriptor) {
93 + if (__DEV__) {
94 + warning(
95 + descriptor && (typeof descriptor.type === 'function' ||
96 + typeof descriptor.type === 'string'),
97 + 'Only functions or strings can be mounted as React components.'
98 + // Not really strings yet, but as soon as I solve the cyclic dep, they
99 + // will be allowed here.
100 + );
101 + }
102 +
103 + var instance = createInstance(descriptor.type, descriptor.props);
104
52 - // TODO: Make warning
53 - // if (__DEV__) {
54 - invariant(
55 - isValidComponentDescriptor(descriptor),
56 - 'Only React Components are valid for mounting.'
105 + if (__DEV__) {
106 + warning(
107 + typeof instance.construct === 'function' &&
108 + typeof instance.mountComponent === 'function' &&
109 + typeof instance.receiveComponent === 'function',
110 + 'Only React Components can be mounted.'
111 );
58 - // }
112 + }
113
60 - return new descriptor.type(descriptor);
114 + // This actually sets up the internal instance. This will become decoupled
115 + // from the public instance in a future diff.
116 + instance.construct(descriptor);
117 + return instance;
118 }
119
120 module.exports = instantiateReactComponent;
src/test/ReactTestUtils.js
+3 -2
@@ -31,7 +31,6 @@ var ReactUpdates = require('ReactUpdates');
31 var SyntheticEvent = require('SyntheticEvent');
32
33 var mergeInto = require('mergeInto');
34 -var copyProperties = require('copyProperties');
34
35 var topLevelTypes = EventConstants.topLevelTypes;
36
@@ -246,9 +245,11 @@ var ReactTestUtils = {
245 }
246 });
247
249 - copyProperties(module, ConvenienceConstructor);
248 module.mockImplementation(ConvenienceConstructor);
249
250 + module.type = ConvenienceConstructor.type;
251 + module.isReactLegacyFactory = true;
252 +
253 return this;
254 },
255
src/utils/traverseAllChildren.js
+2 -2
@@ -18,6 +18,7 @@
18
19 "use strict";
20
21 +var ReactDescriptor = require('ReactDescriptor');
22 var ReactInstanceHandles = require('ReactInstanceHandles');
23 var ReactTextComponent = require('ReactTextComponent');
24
@@ -126,8 +127,7 @@ var traverseAllChildrenImpl =
127 // All of the above are perceived as null.
128 callback(traverseContext, null, storageName, indexSoFar);
129 subtreeCount = 1;
129 - } else if (children.type && children.type.prototype &&
130 - children.type.prototype.mountComponentIntoNode) {
130 + } else if (ReactDescriptor.isValidDescriptor(children)) {
131 callback(traverseContext, children, storageName, indexSoFar);
132 subtreeCount = 1;
133 } else {