@samitouri / QOS-React / commits / 85b0377bfd

Refactor ShallowRenderer (#7739)

* Separate ReactShallowRenderer from TestUtils * Use ES classes to ReactShallowRenderer

Toru Kobayashi committed Oct 4, 2016 at 20:28 UTC 85b0377bfd1b7f3598b7ae5ccea3234a6453a0eb
2 files changed +140 -136
src/test/ReactShallowRenderer.js new
+139
@@ -0,0 +1,139 @@
1 +/**
2 + * Copyright 2013-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactShallowRenderer
10 + */
11 +
12 +'use strict';
13 +
14 +var React = require('React');
15 +var ReactDefaultInjection = require('ReactDefaultInjection');
16 +var ReactCompositeComponent = require('ReactCompositeComponent');
17 +var ReactReconciler = require('ReactReconciler');
18 +var ReactUpdates = require('ReactUpdates');
19 +
20 +var emptyObject = require('emptyObject');
21 +var invariant = require('invariant');
22 +
23 +var nextDebugID = 1;
24 +
25 +class NoopInternalComponent {
26 + constructor(element) {
27 + this._renderedOutput = element;
28 + this._currentElement = element;
29 +
30 + if (__DEV__) {
31 + this._debugID = nextDebugID++;
32 + }
33 + }
34 + mountComponent() {}
35 + receiveComponent(element) {
36 + this._renderedOutput = element;
37 + this._currentElement = element;
38 + }
39 + unmountComponent() {}
40 + getHostNode() {
41 + return undefined;
42 + }
43 + getPublicInstance() {
44 + return null;
45 + }
46 +}
47 +
48 +var ShallowComponentWrapper = function(element) {
49 + // TODO: Consolidate with instantiateReactComponent
50 + if (__DEV__) {
51 + this._debugID = nextDebugID++;
52 + }
53 +
54 + this.construct(element);
55 +};
56 +Object.assign(
57 + ShallowComponentWrapper.prototype,
58 + ReactCompositeComponent, {
59 + _constructComponent:
60 + ReactCompositeComponent._constructComponentWithoutOwner,
61 + _instantiateReactComponent: function(element) {
62 + return new NoopInternalComponent(element);
63 + },
64 + _replaceNodeWithMarkup: function() {},
65 + _renderValidatedComponent:
66 + ReactCompositeComponent
67 + ._renderValidatedComponentWithoutOwnerOrContext,
68 + }
69 +);
70 +
71 +function _batchedRender(renderer, element, context) {
72 + var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true);
73 + renderer._render(element, transaction, context);
74 + ReactUpdates.ReactReconcileTransaction.release(transaction);
75 +}
76 +
77 +class ReactShallowRenderer {
78 + _instance = null;
79 + getMountedInstance() {
80 + return this._instance ? this._instance._instance : null;
81 + }
82 + render(element, context) {
83 + // Ensure we've done the default injections. This might not be true in the
84 + // case of a simple test that only requires React and the TestUtils in
85 + // conjunction with an inline-requires transform.
86 + ReactDefaultInjection.inject();
87 +
88 + invariant(
89 + React.isValidElement(element),
90 + 'ReactShallowRenderer render(): Invalid component element.%s',
91 + typeof element === 'function' ?
92 + ' Instead of passing a component class, make sure to instantiate ' +
93 + 'it by passing it to React.createElement.' :
94 + ''
95 + );
96 + invariant(
97 + typeof element.type !== 'string',
98 + 'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
99 + 'components, not primitives (%s). Instead of calling `.render(el)` and ' +
100 + 'inspecting the rendered output, look at `el.props` directly instead.',
101 + element.type
102 + );
103 +
104 + if (!context) {
105 + context = emptyObject;
106 + }
107 + ReactUpdates.batchedUpdates(_batchedRender, this, element, context);
108 +
109 + return this.getRenderOutput();
110 + }
111 + getRenderOutput() {
112 + return (
113 + (this._instance && this._instance._renderedComponent &&
114 + this._instance._renderedComponent._renderedOutput)
115 + || null
116 + );
117 + }
118 + unmount() {
119 + if (this._instance) {
120 + ReactReconciler.unmountComponent(this._instance, false);
121 + }
122 + }
123 + _render(element, transaction, context) {
124 + if (this._instance) {
125 + ReactReconciler.receiveComponent(
126 + this._instance,
127 + element,
128 + transaction,
129 + context
130 + );
131 + } else {
132 + var instance = new ShallowComponentWrapper(element);
133 + ReactReconciler.mountComponent(instance, transaction, null, null, context, 0);
134 + this._instance = instance;
135 + }
136 + }
137 +}
138 +
139 +module.exports = ReactShallowRenderer;
src/test/ReactTestUtils.js
+1 -136
@@ -16,17 +16,14 @@ var EventPluginHub = require('EventPluginHub');
16 var EventPluginRegistry = require('EventPluginRegistry');
17 var EventPropagators = require('EventPropagators');
18 var React = require('React');
19 -var ReactDefaultInjection = require('ReactDefaultInjection');
19 var ReactDOM = require('ReactDOM');
20 var ReactDOMComponentTree = require('ReactDOMComponentTree');
21 var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
23 -var ReactCompositeComponent = require('ReactCompositeComponent');
22 var ReactInstanceMap = require('ReactInstanceMap');
25 -var ReactReconciler = require('ReactReconciler');
23 var ReactUpdates = require('ReactUpdates');
24 var SyntheticEvent = require('SyntheticEvent');
25 +var ReactShallowRenderer = require('ReactShallowRenderer');
26
29 -var emptyObject = require('emptyObject');
27 var findDOMNode = require('findDOMNode');
28 var invariant = require('invariant');
29
@@ -365,138 +362,6 @@ var ReactTestUtils = {
362 SimulateNative: {},
363 };
364
368 -/**
369 - * @class ReactShallowRenderer
370 - */
371 -var ReactShallowRenderer = function() {
372 - this._instance = null;
373 -};
374 -
375 -ReactShallowRenderer.prototype.getMountedInstance = function() {
376 - return this._instance ? this._instance._instance : null;
377 -};
378 -
379 -var nextDebugID = 1;
380 -
381 -var NoopInternalComponent = function(element) {
382 - this._renderedOutput = element;
383 - this._currentElement = element;
384 -
385 - if (__DEV__) {
386 - this._debugID = nextDebugID++;
387 - }
388 -};
389 -
390 -NoopInternalComponent.prototype = {
391 -
392 - mountComponent: function() {
393 - },
394 -
395 - receiveComponent: function(element) {
396 - this._renderedOutput = element;
397 - this._currentElement = element;
398 - },
399 -
400 - getHostNode: function() {
401 - return undefined;
402 - },
403 -
404 - unmountComponent: function() {
405 - },
406 -
407 - getPublicInstance: function() {
408 - return null;
409 - },
410 -};
411 -
412 -var ShallowComponentWrapper = function(element) {
413 - // TODO: Consolidate with instantiateReactComponent
414 - if (__DEV__) {
415 - this._debugID = nextDebugID++;
416 - }
417 -
418 - this.construct(element);
419 -};
420 -Object.assign(
421 - ShallowComponentWrapper.prototype,
422 - ReactCompositeComponent, {
423 - _constructComponent:
424 - ReactCompositeComponent._constructComponentWithoutOwner,
425 - _instantiateReactComponent: function(element) {
426 - return new NoopInternalComponent(element);
427 - },
428 - _replaceNodeWithMarkup: function() {},
429 - _renderValidatedComponent:
430 - ReactCompositeComponent
431 - ._renderValidatedComponentWithoutOwnerOrContext,
432 - }
433 -);
434 -
435 -ReactShallowRenderer.prototype.render = function(element, context) {
436 - // Ensure we've done the default injections. This might not be true in the
437 - // case of a simple test that only requires React and the TestUtils in
438 - // conjunction with an inline-requires transform.
439 - ReactDefaultInjection.inject();
440 -
441 - invariant(
442 - React.isValidElement(element),
443 - 'ReactShallowRenderer render(): Invalid component element.%s',
444 - typeof element === 'function' ?
445 - ' Instead of passing a component class, make sure to instantiate ' +
446 - 'it by passing it to React.createElement.' :
447 - ''
448 - );
449 - invariant(
450 - typeof element.type !== 'string',
451 - 'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
452 - 'components, not primitives (%s). Instead of calling `.render(el)` and ' +
453 - 'inspecting the rendered output, look at `el.props` directly instead.',
454 - element.type
455 - );
456 -
457 - if (!context) {
458 - context = emptyObject;
459 - }
460 - ReactUpdates.batchedUpdates(_batchedRender, this, element, context);
461 -
462 - return this.getRenderOutput();
463 -};
464 -
465 -function _batchedRender(renderer, element, context) {
466 - var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true);
467 - renderer._render(element, transaction, context);
468 - ReactUpdates.ReactReconcileTransaction.release(transaction);
469 -}
470 -
471 -ReactShallowRenderer.prototype.getRenderOutput = function() {
472 - return (
473 - (this._instance && this._instance._renderedComponent &&
474 - this._instance._renderedComponent._renderedOutput)
475 - || null
476 - );
477 -};
478 -
479 -ReactShallowRenderer.prototype.unmount = function() {
480 - if (this._instance) {
481 - ReactReconciler.unmountComponent(this._instance, false);
482 - }
483 -};
484 -
485 -ReactShallowRenderer.prototype._render = function(element, transaction, context) {
486 - if (this._instance) {
487 - ReactReconciler.receiveComponent(
488 - this._instance,
489 - element,
490 - transaction,
491 - context
492 - );
493 - } else {
494 - var instance = new ShallowComponentWrapper(element);
495 - ReactReconciler.mountComponent(instance, transaction, null, null, context, 0);
496 - this._instance = instance;
497 - }
498 -};
499 -
365 /**
366 * Exports:
367 *