UNPKG

enzyme

Version:

JavaScript Testing utilities for React

1,776 lines (1,492 loc) 142 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _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; }; var _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; }; }(); var _object = require('object.assign'); var _object2 = _interopRequireDefault(_object); var _arrayPrototype = require('array.prototype.flat'); var _arrayPrototype2 = _interopRequireDefault(_arrayPrototype); var _has = require('has'); var _has2 = _interopRequireDefault(_has); var _Utils = require('./Utils'); var _getAdapter = require('./getAdapter'); var _getAdapter2 = _interopRequireDefault(_getAdapter); var _Debug = require('./Debug'); var _RSTTraversal = require('./RSTTraversal'); var _selectors = require('./selectors'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _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; } function _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; } function _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; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var NODE = (0, _Utils.sym)('__node__'); var NODES = (0, _Utils.sym)('__nodes__'); var RENDERER = (0, _Utils.sym)('__renderer__'); var UNRENDERED = (0, _Utils.sym)('__unrendered__'); var ROOT = (0, _Utils.sym)('__root__'); var OPTIONS = (0, _Utils.sym)('__options__'); var ROOT_NODES = (0, _Utils.sym)('__rootNodes__'); var WRAPPING_COMPONENT = (0, _Utils.sym)('__wrappingComponent__'); var LINKED_ROOTS = (0, _Utils.sym)('__linkedRoots__'); var UPDATED_BY = (0, _Utils.sym)('__updatedBy__'); /** * Finds all nodes in the current wrapper nodes' render trees that match the provided predicate * function. * * @param {ReactWrapper} wrapper * @param {Function} predicate * @param {Function} filter * @returns {ReactWrapper} */ function findWhereUnwrapped(wrapper, predicate) { var filter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _RSTTraversal.treeFilter; return wrapper.flatMap(function (n) { return filter(n.getNodeInternal(), predicate); }); } /** * Returns a new wrapper instance with only the nodes of the current wrapper instance that match * the provided predicate function. * * @param {ReactWrapper} wrapper * @param {Function} predicate * @returns {ReactWrapper} */ function filterWhereUnwrapped(wrapper, predicate) { return wrapper.wrap(wrapper.getNodesInternal().filter(predicate).filter(Boolean)); } function getRootNodeInternal(wrapper) { if (wrapper[ROOT].length !== 1) { throw new Error('getRootNodeInternal(wrapper) can only be called when wrapper wraps one node'); } if (wrapper[ROOT] !== wrapper) { return wrapper[ROOT_NODES][0]; } return wrapper[ROOT][NODE]; } function nodeParents(wrapper, node) { return (0, _RSTTraversal.parentsOfNode)(node, getRootNodeInternal(wrapper)); } function privateSetNodes(wrapper, nodes) { if (!nodes) { (0, _Utils.privateSet)(wrapper, NODE, null); (0, _Utils.privateSet)(wrapper, NODES, []); } else if (!Array.isArray(nodes)) { (0, _Utils.privateSet)(wrapper, NODE, nodes); (0, _Utils.privateSet)(wrapper, NODES, [nodes]); } else { (0, _Utils.privateSet)(wrapper, NODE, nodes[0]); (0, _Utils.privateSet)(wrapper, NODES, nodes); } (0, _Utils.privateSet)(wrapper, 'length', wrapper[NODES].length); } /** * @class ReactWrapper */ var ReactWrapper = function () { function ReactWrapper(nodes, root) { var passedOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; _classCallCheck(this, ReactWrapper); if (!global.window && !global.document) { throw new Error('It looks like you called `mount()` without a global document being loaded.'); } var options = (0, _Utils.makeOptions)(passedOptions); if (!root) { var adapter = (0, _getAdapter2['default'])(options); if (!adapter.isValidElement(nodes)) { throw new TypeError('ReactWrapper can only wrap valid elements'); } var renderer = adapter.createRenderer((0, _object2['default'])({ mode: 'mount' }, options)); (0, _Utils.privateSet)(this, RENDERER, renderer); renderer.render(nodes, options.context); (0, _Utils.privateSet)(this, ROOT, this); privateSetNodes(this, this[RENDERER].getNode()); (0, _Utils.privateSet)(this, OPTIONS, options); (0, _Utils.privateSet)(this, LINKED_ROOTS, []); if ((0, _Utils.isCustomComponent)(options.wrappingComponent, adapter)) { if (typeof this[RENDERER].getWrappingComponentRenderer !== 'function') { throw new TypeError('your adapter does not support `wrappingComponent`. Try upgrading it!'); } // eslint-disable-next-line no-use-before-define (0, _Utils.privateSet)(this, WRAPPING_COMPONENT, new WrappingComponentWrapper(this, this[RENDERER].getWrappingComponentRenderer())); this[LINKED_ROOTS].push(this[WRAPPING_COMPONENT]); } } else { (0, _Utils.privateSet)(this, RENDERER, root[RENDERER]); (0, _Utils.privateSet)(this, ROOT, root); privateSetNodes(this, nodes); (0, _Utils.privateSet)(this, ROOT_NODES, root[NODES]); (0, _Utils.privateSet)(this, OPTIONS, root[OPTIONS]); (0, _Utils.privateSet)(this, LINKED_ROOTS, []); } (0, _Utils.privateSet)(this, UNRENDERED, nodes); (0, _Utils.privateSet)(this, UPDATED_BY, null); } /** * Returns the root wrapper * * @return {ReactWrapper} */ _createClass(ReactWrapper, [{ key: 'root', value: function () { function root() { return this[ROOT]; } return root; }() /** * Returns the wrapped component. * * @return {ReactComponent} */ }, { key: 'getNodeInternal', value: function () { function getNodeInternal() { if (this.length !== 1) { throw new Error('ReactWrapper::getNode() can only be called when wrapping one node'); } return this[NODES][0]; } return getNodeInternal; }() /** * Returns the the wrapped components. * * @return {Array<ReactComponent>} */ }, { key: 'getNodesInternal', value: function () { function getNodesInternal() { return this[NODES]; } return getNodesInternal; }() /** * Returns the wrapped ReactElement. * * @return {ReactElement} */ }, { key: 'getElement', value: function () { function getElement() { var _this = this; return this.single('getElement', function () { return (0, _getAdapter2['default'])(_this[OPTIONS]).nodeToElement(_this[NODE]); }); } return getElement; }() /** * Returns the wrapped ReactElements. * * @return {Array<ReactElement>} */ }, { key: 'getElements', value: function () { function getElements() { var _this2 = this; return this[NODES].map(function (n) { return (0, _getAdapter2['default'])(_this2[OPTIONS]).nodeToElement(n); }); } return getElements; }() // eslint-disable-next-line class-methods-use-this }, { key: 'getNode', value: function () { function getNode() { throw new Error('ReactWrapper::getNode() is no longer supported. Use ReactWrapper::instance() instead'); } return getNode; }() // eslint-disable-next-line class-methods-use-this }, { key: 'getNodes', value: function () { function getNodes() { throw new Error('ReactWrapper::getNodes() is no longer supported.'); } return getNodes; }() /** * Returns the outer most DOMComponent of the current wrapper. * * NOTE: can only be called on a wrapper of a single node. * * @returns {DOMComponent} */ }, { key: 'getDOMNode', value: function () { function getDOMNode() { var adapter = (0, _getAdapter2['default'])(this[OPTIONS]); return this.single('getDOMNode', function (n) { return adapter.nodeToHostNode(n, true); }); } return getDOMNode; }() /** * If the root component contained a ref, you can access it here and get the relevant * react component instance or HTML element instance. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {String} refname * @returns {ReactComponent | HTMLElement} */ }, { key: 'ref', value: function () { function ref(refname) { if (this[ROOT] !== this) { throw new Error('ReactWrapper::ref(refname) can only be called on the root'); } return this.instance().refs[refname]; } return ref; }() /** * Returns the wrapper's underlying instance. * * Example: * ``` * const wrapper = mount(<MyComponent />); * const inst = wrapper.instance(); * expect(inst).to.be.instanceOf(MyComponent); * ``` * @returns {ReactComponent|DOMComponent} */ }, { key: 'instance', value: function () { function instance() { var _this3 = this; return this.single('instance', function () { return _this3[NODE].instance; }); } return instance; }() /** * If a `wrappingComponent` was passed in `options`, this methods returns a `ReactWrapper` around * the rendered `wrappingComponent`. This `ReactWrapper` can be used to update the * `wrappingComponent`'s props, state, etc. * * @returns ReactWrapper */ }, { key: 'getWrappingComponent', value: function () { function getWrappingComponent() { if (this[ROOT] !== this) { throw new Error('ReactWrapper::getWrappingComponent() can only be called on the root'); } if (!this[OPTIONS].wrappingComponent) { throw new Error('ReactWrapper::getWrappingComponent() can only be called on a wrapper that was originally passed a `wrappingComponent` option'); } return this[WRAPPING_COMPONENT]; } return getWrappingComponent; }() /** * Forces a re-render. Useful to run before checking the render output if something external * may be updating the state of the component somewhere. * * NOTE: no matter what instance this is called on, it will always update the root. * * @returns {ReactWrapper} */ }, { key: 'update', value: function () { function update() { var _this4 = this; var root = this[ROOT]; if (this !== root) { return root.update(); } privateSetNodes(this, this[RENDERER].getNode()); this[LINKED_ROOTS].forEach(function (linkedRoot) { if (linkedRoot !== _this4[UPDATED_BY]) { /* eslint-disable no-param-reassign */ // Only update a linked it root if it is not the originator of our update(). // This is needed to prevent infinite recursion when there is a bi-directional // link between two roots. linkedRoot[UPDATED_BY] = _this4; try { linkedRoot.update(); } finally { linkedRoot[UPDATED_BY] = null; } } }); return this; } return update; }() /** * A method that unmounts the component. This can be used to simulate a component going through * and unmount/mount lifecycle. * * @returns {ReactWrapper} */ }, { key: 'unmount', value: function () { function unmount() { var _this5 = this; if (this[ROOT] !== this) { throw new Error('ReactWrapper::unmount() can only be called on the root'); } this.single('unmount', function () { _this5[RENDERER].unmount(); _this5.update(); }); return this; } return unmount; }() /** * A method that re-mounts the component, if it is not currently mounted. * This can be used to simulate a component going through * an unmount/mount lifecycle. * * @returns {ReactWrapper} */ }, { key: 'mount', value: function () { function mount() { var _this6 = this; if (this[ROOT] !== this) { throw new Error('ReactWrapper::mount() can only be called on the root'); } this[RENDERER].render(this[UNRENDERED], this[OPTIONS].context, function () { return _this6.update(); }); return this; } return mount; }() /** * A method that sets the props of the root component, and re-renders. Useful for when you are * wanting to test how the component behaves over time with changing props. Calling this, for * instance, will call the `componentWillReceiveProps` lifecycle method. * * Similar to `setState`, this method accepts a props object and will merge it in with the already * existing props. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {Object} props object * @param {Function} cb - callback function * @returns {ReactWrapper} */ }, { key: 'setProps', value: function () { function setProps(props) { var _this7 = this; var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; if (this[ROOT] !== this) { throw new Error('ReactWrapper::setProps() can only be called on the root'); } if (arguments.length > 1 && typeof callback !== 'function') { throw new TypeError('ReactWrapper::setProps() expects a function as its second argument'); } var adapter = (0, _getAdapter2['default'])(this[OPTIONS]); this[UNRENDERED] = (0, _Utils.cloneElement)(adapter, this[UNRENDERED], props); this[RENDERER].render(this[UNRENDERED], null, function () { _this7.update(); if (callback) { callback(); } }); return this; } return setProps; }() /** * A method to invoke `setState` on the root component instance similar to how you might in the * definition of the component, and re-renders. This method is useful for testing your component * in hard to achieve states, however should be used sparingly. If possible, you should utilize * your component's external API in order to get it into whatever state you want to test, in order * to be as accurate of a test as possible. This is not always practical, however. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {Object} state to merge * @param {Function} cb - callback function * @returns {ReactWrapper} */ }, { key: 'setState', value: function () { function setState(state) { var _this8 = this; var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; if (this.instance() === null || this.getNodeInternal().nodeType !== 'class') { throw new Error('ReactWrapper::setState() can only be called on class components'); } if (arguments.length > 1 && typeof callback !== 'function') { throw new TypeError('ReactWrapper::setState() expects a function as its second argument'); } this.instance().setState(state, function () { _this8.update(); if (callback) { var adapter = (0, _getAdapter2['default'])(_this8[OPTIONS]); var instance = _this8.instance(); if (adapter.invokeSetStateCallback) { adapter.invokeSetStateCallback(instance, callback); } else { callback.call(instance); } } }); return this; } return setState; }() /** * A method that sets the context of the root component, and re-renders. Useful for when you are * wanting to test how the component behaves over time with changing contexts. * * NOTE: can only be called on a wrapper instance that is also the root instance. * * @param {Object} context object * @returns {ReactWrapper} */ }, { key: 'setContext', value: function () { function setContext(context) { var _this9 = this; if (this[ROOT] !== this) { throw new Error('ReactWrapper::setContext() can only be called on the root'); } if (!this[OPTIONS].context) { throw new Error('ReactWrapper::setContext() can only be called on a wrapper that was originally passed a context option'); } this[RENDERER].render(this[UNRENDERED], context, function () { return _this9.update(); }); return this; } return setContext; }() /** * Whether or not a given react element exists in the mount render tree. * * Example: * ``` * const wrapper = mount(<MyComponent />); * expect(wrapper.contains(<div className="foo bar" />)).to.equal(true); * ``` * * @param {ReactElement|Array<ReactElement>} nodeOrNodes * @returns {Boolean} */ }, { key: 'contains', value: function () { function contains(nodeOrNodes) { var adapter = (0, _getAdapter2['default'])(this[OPTIONS]); var predicate = Array.isArray(nodeOrNodes) ? function (other) { return (0, _Utils.containsChildrenSubArray)(_Utils.nodeEqual, other, nodeOrNodes.map(function (node) { return adapter.elementToNode(node); })); } : function (other) { return (0, _Utils.nodeEqual)(adapter.elementToNode(nodeOrNodes), other); }; return findWhereUnwrapped(this, predicate).length > 0; } return contains; }() /** * Whether or not a given react element exists in the current render tree. * It will determine if one of the wrappers element "looks like" the expected * element by checking if all props of the expected element are present * on the wrappers element and equals to each other. * * Example: * ``` * // MyComponent outputs <div><div class="foo">Hello</div></div> * const wrapper = mount(<MyComponent />); * expect(wrapper.containsMatchingElement(<div>Hello</div>)).to.equal(true); * ``` * * @param {ReactElement} node * @returns {Boolean} */ }, { key: 'containsMatchingElement', value: function () { function containsMatchingElement(node) { var rstNode = (0, _getAdapter2['default'])(this[OPTIONS]).elementToNode(node); var predicate = function () { function predicate(other) { return (0, _Utils.nodeMatches)(rstNode, other, function (a, b) { return a <= b; }); } return predicate; }(); return findWhereUnwrapped(this, predicate).length > 0; } return containsMatchingElement; }() /** * Whether or not all the given react elements exist in the current render tree. * It will determine if one of the wrappers element "looks like" the expected * element by checking if all props of the expected element are present * on the wrappers element and equals to each other. * * Example: * ``` * const wrapper = mount(<MyComponent />); * expect(wrapper.containsAllMatchingElements([ * <div>Hello</div>, * <div>Goodbye</div>, * ])).to.equal(true); * ``` * * @param {Array<ReactElement>} nodes * @returns {Boolean} */ }, { key: 'containsAllMatchingElements', value: function () { function containsAllMatchingElements(nodes) { var _this10 = this; if (!Array.isArray(nodes)) { throw new TypeError('nodes should be an Array'); } return nodes.every(function (node) { return _this10.containsMatchingElement(node); }); } return containsAllMatchingElements; }() /** * Whether or not one of the given react elements exists in the current render tree. * It will determine if one of the wrappers element "looks like" the expected * element by checking if all props of the expected element are present * on the wrappers element and equals to each other. * * Example: * ``` * const wrapper = mount(<MyComponent />); * expect(wrapper.containsAnyMatchingElements([ * <div>Hello</div>, * <div>Goodbye</div>, * ])).to.equal(true); * ``` * * @param {Array<ReactElement>} nodes * @returns {Boolean} */ }, { key: 'containsAnyMatchingElements', value: function () { function containsAnyMatchingElements(nodes) { var _this11 = this; return Array.isArray(nodes) && nodes.some(function (node) { return _this11.containsMatchingElement(node); }); } return containsAnyMatchingElements; }() /** * Whether or not a given react element exists in the render tree. * * Example: * ``` * const wrapper = mount(<MyComponent />); * expect(wrapper.contains(<div className="foo bar" />)).to.equal(true); * ``` * * @param {ReactElement} node * @returns {Boolean} */ }, { key: 'equals', value: function () { function equals(node) { var _this12 = this; return this.single('equals', function () { return (0, _Utils.nodeEqual)(_this12.getNodeInternal(), node); }); } return equals; }() /** * Whether or not a given react element matches the render tree. * Match is based on the expected element and not on wrapper root node. * It will determine if the wrapper root node "looks like" the expected * element by checking if all props of the expected element are present * on the wrapper root node and equals to each other. * * Example: * ``` * // MyComponent outputs <div class="foo">Hello</div> * const wrapper = mount(<MyComponent />); * expect(wrapper.matchesElement(<div>Hello</div>)).to.equal(true); * ``` * * @param {ReactElement} node * @returns {Boolean} */ }, { key: 'matchesElement', value: function () { function matchesElement(node) { var _this13 = this; return this.single('matchesElement', function () { var adapter = (0, _getAdapter2['default'])(_this13[OPTIONS]); var rstNode = adapter.elementToNode(node); return (0, _Utils.nodeMatches)(rstNode, _this13.getNodeInternal(), function (a, b) { return a <= b; }); }); } return matchesElement; }() /** * Finds every node in the render tree of the current wrapper that matches the provided selector. * * @param {EnzymeSelector} selector * @returns {ReactWrapper} */ }, { key: 'find', value: function () { function find(selector) { return this.wrap((0, _selectors.reduceTreesBySelector)(selector, this.getNodesInternal())); } return find; }() /** * Returns whether or not current node matches a provided selector. * * NOTE: can only be called on a wrapper of a single node. * * @param {EnzymeSelector} selector * @returns {boolean} */ }, { key: 'is', value: function () { function is(selector) { var predicate = (0, _selectors.buildPredicate)(selector); return this.single('is', function (n) { return predicate(n); }); } return is; }() /** * Returns true if the component rendered nothing, i.e., null or false. * * @returns {boolean} */ }, { key: 'isEmptyRender', value: function () { function isEmptyRender() { var nodes = this.getNodeInternal(); return (0, _Utils.renderedDive)(nodes); } return isEmptyRender; }() /** * Returns a new wrapper instance with only the nodes of the current wrapper instance that match * the provided predicate function. * * @param {Function} predicate * @returns {ReactWrapper} */ }, { key: 'filterWhere', value: function () { function filterWhere(predicate) { var _this14 = this; return filterWhereUnwrapped(this, function (n) { return predicate(_this14.wrap(n)); }); } return filterWhere; }() /** * Returns a new wrapper instance with only the nodes of the current wrapper instance that match * the provided selector. * * @param {EnzymeSelector} selector * @returns {ReactWrapper} */ }, { key: 'filter', value: function () { function filter(selector) { var predicate = (0, _selectors.buildPredicate)(selector); return filterWhereUnwrapped(this, predicate); } return filter; }() /** * Returns a new wrapper instance with only the nodes of the current wrapper that did not match * the provided selector. Essentially the inverse of `filter`. * * @param {EnzymeSelector} selector * @returns {ReactWrapper} */ }, { key: 'not', value: function () { function not(selector) { var predicate = (0, _selectors.buildPredicate)(selector); return filterWhereUnwrapped(this, function (n) { return !predicate(n); }); } return not; }() /** * Returns a string of the rendered text of the current render tree. This function should be * looked at with skepticism if being used to test what the actual HTML output of the component * will be. If that is what you would like to test, use enzyme's `render` function instead. * * NOTE: can only be called on a wrapper of a single node. * * @returns {String} */ }, { key: 'text', value: function () { function text() { var adapter = (0, _getAdapter2['default'])(this[OPTIONS]); return this.single('text', function (n) { return (0, _RSTTraversal.getTextFromHostNodes)(n, adapter); }); } return text; }() /** * Returns the HTML of the node. * * NOTE: can only be called on a wrapper of a single node. * * @returns {String} */ }, { key: 'html', value: function () { function html() { var adapter = (0, _getAdapter2['default'])(this[OPTIONS]); return this.single('html', function (n) { return (0, _RSTTraversal.getHTMLFromHostNodes)(n, adapter); }); } return html; }() /** * Returns the current node rendered to HTML and wrapped in a CheerioWrapper. * * NOTE: can only be called on a wrapper of a single node. * * @returns {CheerioWrapper} */ }, { key: 'render', value: function () { function render() { var html = this.html(); return (0, _Utils.loadCheerioRoot)(html); } return render; }() /** * Used to simulate events. Pass an eventname and (optionally) event arguments. This method of * testing events should be met with some skepticism. * * @param {String} event * @param {Object} mock (optional) * @returns {ReactWrapper} */ }, { key: 'simulate', value: function () { function simulate(event) { var _this15 = this; var mock = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return this.single('simulate', function (n) { _this15[RENDERER].simulateEvent(n, event, mock); _this15[ROOT].update(); return _this15; }); } return simulate; }() /** * Used to simulate throwing a rendering error. Pass an error to throw. * * @param {String} error * @returns {ReactWrapper} */ }, { key: 'simulateError', value: function () { function simulateError(error) { var _this16 = this; if (this[ROOT] === this) { throw new Error('ReactWrapper::simulateError() may not be called on the root'); } return this.single('simulateError', function (thisNode) { if (thisNode.nodeType === 'host') { throw new Error('ReactWrapper::simulateError() can only be called on custom components'); } var renderer = _this16[RENDERER]; if (typeof renderer.simulateError !== 'function') { throw new TypeError('your adapter does not support `simulateError`. Try upgrading it!'); } var rootNode = getRootNodeInternal(_this16); var nodeHierarchy = [thisNode].concat(nodeParents(_this16, thisNode)); renderer.simulateError(nodeHierarchy, rootNode, error); _this16[ROOT].update(); return _this16; }); } return simulateError; }() /** * Returns the props hash for the root node of the wrapper. * * NOTE: can only be called on a wrapper of a single node. * * @returns {Object} */ }, { key: 'props', value: function () { function props() { return this.single('props', _RSTTraversal.propsOfNode); } return props; }() /** * Returns the state hash for the root node of the wrapper. Optionally pass in a prop name and it * will return just that value. * * NOTE: can only be called on a wrapper of a single node. * * @param {String} name (optional) * @returns {*} */ }, { key: 'state', value: function () { function state(name) { var _this17 = this; var thisNode = this[ROOT] === this ? this[RENDERER].getNode() : this.getNodeInternal(); if (this.instance() === null || thisNode.nodeType !== 'class') { throw new Error('ReactWrapper::state() can only be called on class components'); } var _state = this.single('state', function () { return _this17.instance().state; }); if (typeof name !== 'undefined') { if (_state == null) { throw new TypeError('ReactWrapper::state("' + String(name) + '") requires that `state` not be `null` or `undefined`'); } return _state[name]; } return _state; } return state; }() /** * Returns the context hash for the root node of the wrapper. * Optionally pass in a prop name and it will return just that value. * * NOTE: can only be called on a wrapper of a single node. * * @param {String} name (optional) * @returns {*} */ }, { key: 'context', value: function () { function context(name) { var _this18 = this; if (this[ROOT] !== this) { throw new Error('ReactWrapper::context() can only be called on the root'); } var instance = this.single('context', function () { return _this18.instance(); }); if (instance === null) { throw new Error('ReactWrapper::context() can only be called on components with instances'); } var _context = instance.context; if (typeof name !== 'undefined') { return _context[name]; } return _context; } return context; }() /** * Returns a new wrapper with all of the children of the current wrapper. * * @param {EnzymeSelector} [selector] * @returns {ReactWrapper} */ }, { key: 'children', value: function () { function children(selector) { var allChildren = this.flatMap(function (n) { return (0, _RSTTraversal.childrenOfNode)(n.getNodeInternal()); }); return selector ? allChildren.filter(selector) : allChildren; } return children; }() /** * Returns a new wrapper with a specific child * * @param {Number} [index] * @returns {ReactWrapper} */ }, { key: 'childAt', value: function () { function childAt(index) { var _this19 = this; return this.single('childAt', function () { return _this19.children().at(index); }); } return childAt; }() /** * Returns a wrapper around all of the parents/ancestors of the wrapper. Does not include the node * in the current wrapper. * * NOTE: can only be called on a wrapper of a single node. * * @param {EnzymeSelector} [selector] * @returns {ReactWrapper} */ }, { key: 'parents', value: function () { function parents(selector) { var _this20 = this; return this.single('parents', function (n) { var allParents = _this20.wrap(nodeParents(_this20, n)); return selector ? allParents.filter(selector) : allParents; }); } return parents; }() /** * Returns a wrapper around the immediate parent of the current node. * * @returns {ReactWrapper} */ }, { key: 'parent', value: function () { function parent() { return this.flatMap(function (n) { return [n.parents().get(0)]; }); } return parent; }() /** * * @param {EnzymeSelector} selector * @returns {ReactWrapper} */ }, { key: 'closest', value: function () { function closest(selector) { if (this.is(selector)) { return this; } var matchingAncestors = this.parents().filter(selector); return matchingAncestors.length > 0 ? matchingAncestors.first() : this.findWhere(function () { return false; }); } return closest; }() /** * Returns the value of prop with the given name of the root node. * * @param {String} propName * @returns {*} */ }, { key: 'prop', value: function () { function prop(propName) { return this.props()[propName]; } return prop; }() /** * Used to invoke a function prop. * Will invoke an function prop and return its value. * * @param {String} propName * @returns {Any} */ }, { key: 'invoke', value: function () { function invoke(propName) { var _this21 = this; return this.single('invoke', function () { var handler = _this21.prop(propName); if (typeof handler !== 'function') { throw new TypeError('ReactWrapper::invoke() requires the name of a prop whose value is a function'); } return function () { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } var response = typeof _this21[RENDERER].wrapInvoke === 'function' ? _this21[RENDERER].wrapInvoke(function () { return handler.apply(undefined, args); }) : handler.apply(undefined, args); _this21[ROOT].update(); return response; }; }); } return invoke; }() /** * Returns a wrapper of the node rendered by the provided render prop. * * @param {String} propName * @returns {Function} */ }, { key: 'renderProp', value: function () { function renderProp(propName) { var _this22 = this; var adapter = (0, _getAdapter2['default'])(this[OPTIONS]); if (typeof adapter.wrap !== 'function') { throw new RangeError('your adapter does not support `wrap`. Try upgrading it!'); } return this.single('renderProp', function (n) { if (n.nodeType === 'host') { throw new TypeError('ReactWrapper::renderProp() can only be called on custom components'); } if (typeof propName !== 'string') { throw new TypeError('ReactWrapper::renderProp(): `propName` must be a string'); } var props = _this22.props(); if (!(0, _has2['default'])(props, propName)) { throw new Error('ReactWrapper::renderProp(): no prop called \u201C' + String(propName) + '\u201C found'); } var propValue = props[propName]; if (typeof propValue !== 'function') { throw new TypeError('ReactWrapper::renderProp(): expected prop \u201C' + String(propName) + '\u201C to contain a function, but it holds \u201C' + (typeof propValue === 'undefined' ? 'undefined' : _typeof(propValue)) + '\u201C'); } return function () { var element = propValue.apply(undefined, arguments); var wrapped = adapter.wrap(element); return _this22.wrap(wrapped, null, _this22[OPTIONS]); }; }); } return renderProp; }() /** * Returns the key assigned to the current node. * * @returns {String} */ }, { key: 'key', value: function () { function key() { return this.single('key', function (n) { return n.key === undefined ? null : n.key; }); } return key; }() /** * Returns the type of the root node of this wrapper. If it's a composite component, this will be * the component constructor. If it's native DOM node, it will be a string. * * @returns {String|Function} */ }, { key: 'type', value: function () { function type() { return this.single('type', function (n) { return (0, _Utils.typeOfNode)(n); }); } return type; }() /** * Returns the name of the root node of this wrapper. * * In order of precedence => type.displayName -> type.name -> type. * * @returns {String} */ }, { key: 'name', value: function () { function name() { var adapter = (0, _getAdapter2['default'])(this[OPTIONS]); return this.single('name', function (n) { return adapter.displayNameOfNode ? adapter.displayNameOfNode(n) : (0, _Utils.displayNameOfNode)(n); }); } return name; }() /** * Returns whether or not the current root node has the given class name or not. * * NOTE: can only be called on a wrapper of a single node. * * @param {String} className * @returns {Boolean} */ }, { key: 'hasClass', value: function () { function hasClass(className) { if (typeof className === 'string' && className.indexOf('.') !== -1) { // eslint-disable-next-line no-console console.warn('It looks like you\'re calling `ReactWrapper::hasClass()` with a CSS selector. hasClass() expects a class name, not a CSS selector.'); } return this.single('hasClass', function (n) { return (0, _RSTTraversal.hasClassName)(n, className); }); } return hasClass; }() /** * Iterates through each node of the current wrapper and executes the provided function with a * wrapper around the corresponding node passed in as the first argument. * * @param {Function} fn * @returns {ReactWrapper} */ }, { key: 'forEach', value: function () { function forEach(fn) { var _this23 = this; this.getNodesInternal().forEach(function (n, i) { return fn.call(_this23, _this23.wrap(n), i); }); return this; } return forEach; }() /** * Maps the current array of nodes to another array. Each node is passed in as a `ReactWrapper` * to the map function. * * @param {Function} fn * @returns {Array} */ }, { key: 'map', value: function () { function map(fn) { var _this24 = this; return this.getNodesInternal().map(function (n, i) { return fn.call(_this24, _this24.wrap(n), i); }); } return map; }() /** * Reduces the current array of nodes to another array. * Each node is passed in as a `ShallowWrapper` to the reducer function. * * @param {Function} fn - the reducer function * @param {*} initialValue - the initial value * @returns {*} */ }, { key: 'reduce', value: function () { function reduce(fn) { var _this25 = this; var initialValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; if (arguments.length > 1) { return this.getNodesInternal().reduce(function (accum, n, i) { return fn.call(_this25, accum, _this25.wrap(n), i); }, initialValue); } return this.getNodesInternal().reduce(function (accum, n, i) { return fn.call(_this25, i === 1 ? _this25.wrap(accum) : accum, _this25.wrap(n), i); }); } return reduce; }() /** * Reduces the current array of nodes to another array, from right to left. Each node is passed * in as a `ShallowWrapper` to the reducer function. * * @param {Function} fn - the reducer function * @param {*} initialValue - the initial value * @returns {*} */ }, { key: 'reduceRight', value: function () { function reduceRight(fn) { var _this26 = this; var initialValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; if (arguments.length > 1) { return this.getNodesInternal().reduceRight(function (accum, n, i) { return fn.call(_this26, accum, _this26.wrap(n), i); }, initialValue); } return this.getNodesInternal().reduceRight(function (accum, n, i) { return fn.call(_this26, i === 1 ? _this26.wrap(accum) : accum, _this26.wrap(n), i); }); } return reduceRight; }() /** * Returns a new wrapper with a subset of the nodes of the original wrapper, according to the * rules of `Array#slice`. * * @param {Number} begin * @param {Number} end * @returns {ShallowWrapper} */ }, { key: 'slice', value: function () { function slice(begin, end) { return this.wrap(this.getNodesInternal().slice(begin, end)); } return slice; }() /** * Returns whether or not any of the nodes in the wrapper match the provided selector. * * @param {EnzymeSelector} selector * @returns {Boolean} */ }, { key: 'some', value: function () { function some(selector) { if (this[ROOT] === this) { throw new Error('ReactWrapper::some() can not be called on the root'); } var predicate = (0, _selectors.buildPredicate)(selector); return this.getNodesInternal().some(predicate); } return some; }() /** * Returns whether or not any of the nodes in the wrapper pass the provided predicate function. * * @param {Function} predicate * @returns {Boolean} */ }, { key: 'someWhere', value: function () { function someWhere(predicate) { var _this27 = this; return this.getNodesInternal().some(function (n, i) { return predicate.call(_this27, _this27.wrap(n), i); }); } return someWhere; }() /** * Returns whether or not all of the nodes in the wrapper match the provided selector. * * @param {EnzymeSelector} selector * @returns {Boolean} */ }, { key: 'every', value: function () { function every(selector) { var predicate = (0, _selectors.buildPredicate)(selector); return this.getNodesInternal().every(predicate); } return every; }() /** * Returns whether or not any of the nodes in the wrapper pass the provided predicate function. * * @param {Function} predicate * @returns {Boolean} */ }, { key: 'everyWhere', value: function () { function everyWhere(predicate) { var _this28 = this; return this.getNodesInternal().every(function (n, i) { return predicate.call(_this28, _this28.wrap(n), i); }); } return everyWhere; }() /** * Utility method used to create new wrappers with a mapping function that returns an array of * nodes in response to a single node wrapper. The returned wrapper is a single wrapper around * all of the mapped nodes flattened (and de-duplicated). * * @param {Function} fn * @returns {ReactWrapper} */ }, { key: 'flatMap', value: function () { function flatMap(fn) { var _this29 = this; var nodes = this.getNodesInternal().map(function (n, i) { return fn.call(_this29, _this29.wrap(n), i); }); var flattened = (0, _arrayPrototype2['default'])(nodes, 1); return this.wrap(flattened.filter(Boolean)); } return flatMap; }() /** * Finds all nodes in the current wrapper nodes' render trees that match the provided predicate * function. * * @param {Function} predicate * @returns {ReactWrapper} */ }, { key: 'findWhere', value: function () { function findWhere(predicate) { var _this30 = this; return findWhereUnwrapped(this, function (n) { var node = _this30.wrap(n); return node.length > 0 && predicate(node); }); } return findWhere; }() /** * Returns the node at a given index of the current wrapper. * * @param {Number} index * @returns {ReactElement} */ }, { key: 'get', value: function () { function get(index) { return this.getElements()[index]; } return get; }() /** * Returns a wrapper around the node at a given index of the current wrapper. * * @param {Number} index * @returns {ReactWrapper} */ }, { key: 'at', value: function () { function at(index) { var nodes = this.getNodesInternal(); if (index < nodes.length) { return this.wrap(nodes[index]); } return this.wrap([]); } return at; }() /** * Returns a wrapper around the first node of the current wrapper. * * @returns {ReactWrapper} */ }, { key: 'first', value: function () { function first() { return this.at(0); } return first; }() /** * Returns a wrapper around the last node of the current wrapper. * * @returns {ReactWrapper} */ }, { key: 'last', value: function () { function last() { return this.at(this.length - 1); } return last; }() /** * Delegates to exists() * * @returns {boolean} */ }, { key: 'isEmpty', value: function () { function isEmpty() { // eslint-disable-next-line no-console console.warn('Enzyme::Deprecated method isEmpty() called, use exists() instead.'); return !this.exists(); } return isEmpty; }() /** * Returns true if the current wrapper has nodes. False otherwise. * If called with a selector it returns `.find(selector).exists()` instead. * * @param {EnzymeSelector} selector (optional) * @returns {boolean} */ }, { key: 'exists', value: function () { function exists() { var selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; return arguments.length > 0 ? this.find(selector).exists() : this.length > 0; } return exists; }() /** * Utility method that throws an error if the current instance has a length other than one. * This is primarily used to enforce that certain methods are only run on a wrapper when it is * wrapping a single node.