UNPKG

23 kBJavaScriptView Raw
1'use strict';
2
3var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
4
5var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
6
7var _displayNamesByType;
8
9var _object = require('object.assign');
10
11var _object2 = _interopRequireDefault(_object);
12
13var _react = require('react');
14
15var _react2 = _interopRequireDefault(_react);
16
17var _reactDom = require('react-dom');
18
19var _reactDom2 = _interopRequireDefault(_reactDom);
20
21var _server = require('react-dom/server');
22
23var _server2 = _interopRequireDefault(_server);
24
25var _shallow = require('react-test-renderer/shallow');
26
27var _shallow2 = _interopRequireDefault(_shallow);
28
29var _testUtils = require('react-dom/test-utils');
30
31var _testUtils2 = _interopRequireDefault(_testUtils);
32
33var _reactIs = require('react-is');
34
35var _enzyme = require('enzyme');
36
37var _Utils = require('enzyme/build/Utils');
38
39var _enzymeAdapterUtils = require('enzyme-adapter-utils');
40
41var _reflection = require('react-reconciler/reflection');
42
43function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
44
45function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
46
47function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
48
49function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
50
51function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
52
53function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /* eslint no-use-before-define: 0 */
54
55// eslint-disable-next-line import/no-unresolved
56
57// eslint-disable-next-line import/no-unresolved
58
59// eslint-disable-next-line import/no-unresolved
60
61
62var HostRoot = 3;
63var ClassComponent = 2;
64var FragmentType = 10;
65var FunctionalComponent = 1;
66var HostPortal = 4;
67var HostComponent = 5;
68var HostText = 6;
69var Mode = 11;
70
71function nodeAndSiblingsArray(nodeWithSibling) {
72 var array = [];
73 var node = nodeWithSibling;
74 while (node != null) {
75 array.push(node);
76 node = node.sibling;
77 }
78 return array;
79}
80
81var displayNamesByType = (_displayNamesByType = {}, _defineProperty(_displayNamesByType, _reactIs.Fragment, 'Fragment'), _defineProperty(_displayNamesByType, _reactIs.Portal, 'Portal'), _displayNamesByType);
82
83function flatten(arr) {
84 var result = [];
85 var stack = [{ i: 0, array: arr }];
86 while (stack.length) {
87 var n = stack.pop();
88 while (n.i < n.array.length) {
89 var el = n.array[n.i];
90 n.i += 1;
91 if (Array.isArray(el)) {
92 stack.push(n);
93 stack.push({ i: 0, array: el });
94 break;
95 }
96 result.push(el);
97 }
98 }
99 return result;
100}
101
102function nodeTypeFromType(type) {
103 if (type === _reactIs.Portal) {
104 return 'portal';
105 }
106
107 return (0, _enzymeAdapterUtils.nodeTypeFromType)(type);
108}
109
110function elementToTree(el) {
111 if (!(0, _reactIs.isPortal)(el)) {
112 return (0, _enzymeAdapterUtils.elementToTree)(el, elementToTree);
113 }
114
115 var children = el.children,
116 containerInfo = el.containerInfo;
117
118 var props = { children: children, containerInfo: containerInfo };
119
120 return {
121 nodeType: 'portal',
122 type: _reactIs.Portal,
123 props: props,
124 key: (0, _enzymeAdapterUtils.ensureKeyOrUndefined)(el.key),
125 ref: el.ref || null,
126 instance: null,
127 rendered: elementToTree(el.children)
128 };
129}
130
131function toTree(vnode) {
132 if (vnode == null) {
133 return null;
134 }
135 // TODO(lmr): I'm not really sure I understand whether or not this is what
136 // i should be doing, or if this is a hack for something i'm doing wrong
137 // somewhere else. Should talk to sebastian about this perhaps
138 var node = (0, _reflection.findCurrentFiberUsingSlowPath)(vnode);
139 switch (node.tag) {
140 case HostRoot:
141 // 3
142 return childrenToTree(node.child);
143 case HostPortal:
144 {
145 // 4
146 var containerInfo = node.stateNode.containerInfo,
147 children = node.memoizedProps;
148
149 var props = { containerInfo: containerInfo, children: children };
150 return {
151 nodeType: 'portal',
152 type: _reactIs.Portal,
153 props: props,
154 key: (0, _enzymeAdapterUtils.ensureKeyOrUndefined)(node.key),
155 ref: node.ref,
156 instance: null,
157 rendered: childrenToTree(node.child)
158 };
159 }
160 case ClassComponent:
161 return {
162 nodeType: 'class',
163 type: node.type,
164 props: (0, _object2['default'])({}, node.memoizedProps),
165 key: (0, _enzymeAdapterUtils.ensureKeyOrUndefined)(node.key),
166 ref: node.ref,
167 instance: node.stateNode,
168 rendered: childrenToTree(node.child)
169 };
170 case FunctionalComponent:
171 // 1
172 return {
173 nodeType: 'function',
174 type: node.type,
175 props: (0, _object2['default'])({}, node.memoizedProps),
176 key: (0, _enzymeAdapterUtils.ensureKeyOrUndefined)(node.key),
177 ref: node.ref,
178 instance: null,
179 rendered: childrenToTree(node.child)
180 };
181 case HostComponent:
182 {
183 // 5
184 var renderedNodes = flatten(nodeAndSiblingsArray(node.child).map(toTree));
185 if (renderedNodes.length === 0) {
186 renderedNodes = [node.memoizedProps.children];
187 }
188 return {
189 nodeType: 'host',
190 type: node.type,
191 props: (0, _object2['default'])({}, node.memoizedProps),
192 key: (0, _enzymeAdapterUtils.ensureKeyOrUndefined)(node.key),
193 ref: node.ref,
194 instance: node.stateNode,
195 rendered: renderedNodes
196 };
197 }
198 case HostText:
199 // 6
200 return node.memoizedProps;
201 case FragmentType: // 10
202 case Mode:
203 // 11
204 return childrenToTree(node.child);
205 default:
206 throw new Error('Enzyme Internal Error: unknown node with tag ' + String(node.tag));
207 }
208}
209
210function childrenToTree(node) {
211 if (!node) {
212 return null;
213 }
214 var children = nodeAndSiblingsArray(node);
215 if (children.length === 0) {
216 return null;
217 }
218 if (children.length === 1) {
219 return toTree(children[0]);
220 }
221 return flatten(children.map(toTree));
222}
223
224function _nodeToHostNode(_node) {
225 // NOTE(lmr): node could be a function component
226 // which wont have an instance prop, but we can get the
227 // host node associated with its return value at that point.
228 // Although this breaks down if the return value is an array,
229 // as is possible with React 16.
230 var node = _node;
231 while (node && !Array.isArray(node) && node.instance === null) {
232 node = node.rendered;
233 }
234 if (Array.isArray(node)) {
235 // TODO(lmr): throw warning regarding not being able to get a host node here
236 throw new Error('Trying to get host node of an array');
237 }
238 // if the SFC returned null effectively, there is no host node.
239 if (!node) {
240 return null;
241 }
242 return _reactDom2['default'].findDOMNode(node.instance);
243}
244
245var eventOptions = { animation: true };
246
247function getEmptyStateValue() {
248 // this handles a bug in React 16.0 - 16.2
249 // see https://github.com/facebook/react/commit/39be83565c65f9c522150e52375167568a2a1459
250 // also see https://github.com/facebook/react/pull/11965
251
252 // eslint-disable-next-line react/prefer-stateless-function
253 var EmptyState = function (_React$Component) {
254 _inherits(EmptyState, _React$Component);
255
256 function EmptyState() {
257 _classCallCheck(this, EmptyState);
258
259 return _possibleConstructorReturn(this, (EmptyState.__proto__ || Object.getPrototypeOf(EmptyState)).apply(this, arguments));
260 }
261
262 _createClass(EmptyState, [{
263 key: 'render',
264 value: function () {
265 function render() {
266 return null;
267 }
268
269 return render;
270 }()
271 }]);
272
273 return EmptyState;
274 }(_react2['default'].Component);
275
276 var testRenderer = new _shallow2['default']();
277 testRenderer.render(_react2['default'].createElement(EmptyState));
278 return testRenderer._instance.state;
279}
280
281var ReactSixteenTwoAdapter = function (_EnzymeAdapter) {
282 _inherits(ReactSixteenTwoAdapter, _EnzymeAdapter);
283
284 function ReactSixteenTwoAdapter() {
285 _classCallCheck(this, ReactSixteenTwoAdapter);
286
287 var _this2 = _possibleConstructorReturn(this, (ReactSixteenTwoAdapter.__proto__ || Object.getPrototypeOf(ReactSixteenTwoAdapter)).call(this));
288
289 var lifecycles = _this2.options.lifecycles;
290
291 _this2.options = (0, _object2['default'])({}, _this2.options, {
292 enableComponentDidUpdateOnSetState: true, // TODO: remove, semver-major
293 lifecycles: (0, _object2['default'])({}, lifecycles, {
294 componentDidUpdate: {
295 onSetState: true
296 },
297 setState: {
298 skipsComponentDidUpdateOnNullish: true
299 }
300 })
301 });
302 return _this2;
303 }
304
305 _createClass(ReactSixteenTwoAdapter, [{
306 key: 'createMountRenderer',
307 value: function () {
308 function createMountRenderer(options) {
309 (0, _enzymeAdapterUtils.assertDomAvailable)('mount');
310 var attachTo = options.attachTo,
311 hydrateIn = options.hydrateIn;
312
313 var domNode = hydrateIn || attachTo || global.document.createElement('div');
314 var instance = null;
315 var adapter = this;
316 return {
317 render: function () {
318 function render(el, context, callback) {
319 if (instance === null) {
320 var type = el.type,
321 props = el.props,
322 ref = el.ref;
323
324 var wrapperProps = (0, _object2['default'])({
325 Component: type,
326 props: props,
327 context: context
328 }, ref && { ref: ref });
329 var ReactWrapperComponent = (0, _enzymeAdapterUtils.createMountWrapper)(el, (0, _object2['default'])({}, options, { adapter: adapter }));
330 var wrappedEl = _react2['default'].createElement(ReactWrapperComponent, wrapperProps);
331 instance = hydrateIn ? _reactDom2['default'].hydrate(wrappedEl, domNode) : _reactDom2['default'].render(wrappedEl, domNode);
332 if (typeof callback === 'function') {
333 callback();
334 }
335 } else {
336 instance.setChildProps(el.props, context, callback);
337 }
338 }
339
340 return render;
341 }(),
342 unmount: function () {
343 function unmount() {
344 _reactDom2['default'].unmountComponentAtNode(domNode);
345 instance = null;
346 }
347
348 return unmount;
349 }(),
350 getNode: function () {
351 function getNode() {
352 return instance ? toTree(instance._reactInternalFiber).rendered : null;
353 }
354
355 return getNode;
356 }(),
357 simulateError: function () {
358 function simulateError(nodeHierarchy, rootNode, error) {
359 var _ref = nodeHierarchy.find(function (x) {
360 return x.instance && x.instance.componentDidCatch;
361 }) || {},
362 catchingInstance = _ref.instance;
363
364 (0, _enzymeAdapterUtils.simulateError)(error, catchingInstance, rootNode, nodeHierarchy, nodeTypeFromType, adapter.displayNameOfNode);
365 }
366
367 return simulateError;
368 }(),
369 simulateEvent: function () {
370 function simulateEvent(node, event, mock) {
371 var mappedEvent = (0, _enzymeAdapterUtils.mapNativeEventNames)(event, eventOptions);
372 var eventFn = _testUtils2['default'].Simulate[mappedEvent];
373 if (!eventFn) {
374 throw new TypeError('ReactWrapper::simulate() event \'' + String(event) + '\' does not exist');
375 }
376 // eslint-disable-next-line react/no-find-dom-node
377 eventFn(_nodeToHostNode(node), mock);
378 }
379
380 return simulateEvent;
381 }(),
382 batchedUpdates: function () {
383 function batchedUpdates(fn) {
384 return fn();
385 // return ReactDOM.unstable_batchedUpdates(fn);
386 }
387
388 return batchedUpdates;
389 }()
390 };
391 }
392
393 return createMountRenderer;
394 }()
395 }, {
396 key: 'createShallowRenderer',
397 value: function () {
398 function createShallowRenderer() /* options */{
399 var adapter = this;
400 var renderer = new _shallow2['default']();
401 var isDOM = false;
402 var cachedNode = null;
403 return {
404 render: function () {
405 function render(el, context) {
406 cachedNode = el;
407 /* eslint consistent-return: 0 */
408 if (typeof el.type === 'string') {
409 isDOM = true;
410 } else {
411 isDOM = false;
412 var Component = el.type;
413
414
415 var isStateful = Component.prototype && (Component.prototype.isReactComponent || Array.isArray(Component.__reactAutoBindPairs) // fallback for createClass components
416 );
417
418 if (!isStateful && typeof Component === 'function') {
419 var wrappedEl = (0, _object2['default'])(function () {
420 return Component.apply(undefined, arguments);
421 }, // eslint-disable-line new-cap
422 Component);
423 return (0, _enzymeAdapterUtils.withSetStateAllowed)(function () {
424 return renderer.render((0, _object2['default'])({}, el, { type: wrappedEl }), context);
425 });
426 }
427 if (isStateful) {
428 // fix react bug; see implementation of `getEmptyStateValue`
429 var emptyStateValue = getEmptyStateValue();
430 if (emptyStateValue) {
431 Object.defineProperty(Component.prototype, 'state', {
432 configurable: true,
433 enumerable: true,
434 get: function () {
435 function get() {
436 return null;
437 }
438
439 return get;
440 }(),
441 set: function () {
442 function set(value) {
443 if (value !== emptyStateValue) {
444 Object.defineProperty(this, 'state', {
445 configurable: true,
446 enumerable: true,
447 value: value,
448 writable: true
449 });
450 }
451 return true;
452 }
453
454 return set;
455 }()
456 });
457 }
458 }
459 return (0, _enzymeAdapterUtils.withSetStateAllowed)(function () {
460 return renderer.render(el, context);
461 });
462 }
463 }
464
465 return render;
466 }(),
467 unmount: function () {
468 function unmount() {
469 renderer.unmount();
470 }
471
472 return unmount;
473 }(),
474 getNode: function () {
475 function getNode() {
476 if (isDOM) {
477 return elementToTree(cachedNode);
478 }
479 var output = renderer.getRenderOutput();
480 return {
481 nodeType: nodeTypeFromType(cachedNode.type),
482 type: cachedNode.type,
483 props: cachedNode.props,
484 key: (0, _enzymeAdapterUtils.ensureKeyOrUndefined)(cachedNode.key),
485 ref: cachedNode.ref,
486 instance: renderer._instance,
487 rendered: Array.isArray(output) ? flatten(output).map(function (el) {
488 return elementToTree(el);
489 }) : elementToTree(output)
490 };
491 }
492
493 return getNode;
494 }(),
495 simulateError: function () {
496 function simulateError(nodeHierarchy, rootNode, error) {
497 (0, _enzymeAdapterUtils.simulateError)(error, renderer._instance, cachedNode, nodeHierarchy.concat(cachedNode), nodeTypeFromType, adapter.displayNameOfNode);
498 }
499
500 return simulateError;
501 }(),
502 simulateEvent: function () {
503 function simulateEvent(node, event) {
504 for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
505 args[_key - 2] = arguments[_key];
506 }
507
508 var handler = node.props[(0, _enzymeAdapterUtils.propFromEvent)(event, eventOptions)];
509 if (handler) {
510 (0, _enzymeAdapterUtils.withSetStateAllowed)(function () {
511 // TODO(lmr): create/use synthetic events
512 // TODO(lmr): emulate React's event propagation
513 // ReactDOM.unstable_batchedUpdates(() => {
514 handler.apply(undefined, _toConsumableArray(args));
515 // });
516 });
517 }
518 }
519
520 return simulateEvent;
521 }(),
522 batchedUpdates: function () {
523 function batchedUpdates(fn) {
524 return fn();
525 // return ReactDOM.unstable_batchedUpdates(fn);
526 }
527
528 return batchedUpdates;
529 }()
530 };
531 }
532
533 return createShallowRenderer;
534 }()
535 }, {
536 key: 'createStringRenderer',
537 value: function () {
538 function createStringRenderer(options) {
539 return {
540 render: function () {
541 function render(el, context) {
542 if (options.context && (el.type.contextTypes || options.childContextTypes)) {
543 var childContextTypes = (0, _object2['default'])({}, el.type.contextTypes || {}, options.childContextTypes);
544 var ContextWrapper = (0, _enzymeAdapterUtils.createRenderWrapper)(el, context, childContextTypes);
545 return _server2['default'].renderToStaticMarkup(_react2['default'].createElement(ContextWrapper));
546 }
547 return _server2['default'].renderToStaticMarkup(el);
548 }
549
550 return render;
551 }()
552 };
553 }
554
555 return createStringRenderer;
556 }()
557
558 // Provided a bag of options, return an `EnzymeRenderer`. Some options can be implementation
559 // specific, like `attach` etc. for React, but not part of this interface explicitly.
560 // eslint-disable-next-line class-methods-use-this, no-unused-vars
561
562 }, {
563 key: 'createRenderer',
564 value: function () {
565 function createRenderer(options) {
566 switch (options.mode) {
567 case _enzyme.EnzymeAdapter.MODES.MOUNT:
568 return this.createMountRenderer(options);
569 case _enzyme.EnzymeAdapter.MODES.SHALLOW:
570 return this.createShallowRenderer(options);
571 case _enzyme.EnzymeAdapter.MODES.STRING:
572 return this.createStringRenderer(options);
573 default:
574 throw new Error('Enzyme Internal Error: Unrecognized mode: ' + String(options.mode));
575 }
576 }
577
578 return createRenderer;
579 }()
580
581 // converts an RSTNode to the corresponding JSX Pragma Element. This will be needed
582 // in order to implement the `Wrapper.mount()` and `Wrapper.shallow()` methods, but should
583 // be pretty straightforward for people to implement.
584 // eslint-disable-next-line class-methods-use-this, no-unused-vars
585
586 }, {
587 key: 'nodeToElement',
588 value: function () {
589 function nodeToElement(node) {
590 if (!node || (typeof node === 'undefined' ? 'undefined' : _typeof(node)) !== 'object') return null;
591 return _react2['default'].createElement(node.type, (0, _enzymeAdapterUtils.propsWithKeysAndRef)(node));
592 }
593
594 return nodeToElement;
595 }()
596 }, {
597 key: 'elementToNode',
598 value: function () {
599 function elementToNode(element) {
600 return elementToTree(element);
601 }
602
603 return elementToNode;
604 }()
605 }, {
606 key: 'nodeToHostNode',
607 value: function () {
608 function nodeToHostNode(node) {
609 return _nodeToHostNode(node);
610 }
611
612 return nodeToHostNode;
613 }()
614 }, {
615 key: 'displayNameOfNode',
616 value: function () {
617 function displayNameOfNode(node) {
618 if (!node) return null;
619
620 var type = node.type,
621 $$typeof = node.$$typeof;
622
623 return displayNamesByType[type || $$typeof] || (0, _enzymeAdapterUtils.displayNameOfNode)(node);
624 }
625
626 return displayNameOfNode;
627 }()
628 }, {
629 key: 'isValidElement',
630 value: function () {
631 function isValidElement(element) {
632 return (0, _reactIs.isElement)(element);
633 }
634
635 return isValidElement;
636 }()
637 }, {
638 key: 'isValidElementType',
639 value: function () {
640 function isValidElementType(object) {
641 return (0, _reactIs.isValidElementType)(object);
642 }
643
644 return isValidElementType;
645 }()
646 }, {
647 key: 'isFragment',
648 value: function () {
649 function isFragment(fragment) {
650 return (0, _Utils.typeOfNode)(fragment) === _reactIs.Fragment;
651 }
652
653 return isFragment;
654 }()
655 }, {
656 key: 'createElement',
657 value: function () {
658 function createElement() {
659 return _react2['default'].createElement.apply(_react2['default'], arguments);
660 }
661
662 return createElement;
663 }()
664 }]);
665
666 return ReactSixteenTwoAdapter;
667}(_enzyme.EnzymeAdapter);
668
669module.exports = ReactSixteenTwoAdapter;
\No newline at end of file