enzyme
Version:
JavaScript Testing utilities for React
1,776 lines (1,492 loc) • 142 kB
JavaScript
'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.