Skip to content

Commit

Permalink
refactor getNode and getNodes
Browse files Browse the repository at this point in the history
  • Loading branch information
lelandrichardson committed Aug 15, 2017
1 parent 12a79c1 commit 568ce89
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 59 deletions.
94 changes: 72 additions & 22 deletions src/ReactWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const noop = () => {};
* @returns {ReactWrapper}
*/
function findWhereUnwrapped(wrapper, predicate, filter = treeFilter) {
return wrapper.flatMap(n => filter(n.getNode(), predicate));
return wrapper.flatMap(n => filter(n.getNodeInternal(), predicate));
}

/**
Expand All @@ -51,7 +51,7 @@ function findWhereUnwrapped(wrapper, predicate, filter = treeFilter) {
* @returns {ReactWrapper}
*/
function filterWhereUnwrapped(wrapper, predicate) {
return wrapper.wrap(compact(wrapper.getNodes().filter(predicate)));
return wrapper.wrap(compact(wrapper.getNodesInternal().filter(predicate)));
}

function getFromRenderer(renderer) {
Expand Down Expand Up @@ -121,7 +121,7 @@ class ReactWrapper {
*
* @return {ReactComponent}
*/
getNode() {
getNodeInternal() {
if (this.length !== 1) {
throw new Error(
'ReactWrapper::getNode() can only be called when wrapping one node',
Expand All @@ -138,10 +138,47 @@ class ReactWrapper {
*
* @return {Array<ReactComponent>}
*/
getNodes() {
getNodesInternal() {
return this.nodes;
}

/**
* Returns the wrapped ReactElement.
*
* @return {ReactElement}
*/
getElement() {
if (this.length !== 1) {
throw new Error(
'ReactWrapper::getElement() can only be called when wrapping one node',
);
}
return getAdapter(this.options).nodeToElement(this.node);
}

/**
* Returns the wrapped ReactElements.
*
* @return {Array<ReactElement>}
*/
getElements() {
return this.nodes.map(getAdapter(this.options).nodeToElement);
}

// eslint-disable-next-line class-methods-use-this
getNode() {
throw new Error(
'ReactWrapper::getNode() is no longer supported. Use ReactWrapper::instance() instead',
);
}

// eslint-disable-next-line class-methods-use-this
getNodes() {
throw new Error(
'ReactWrapper::getNodes() is no longer supported.',
);
}

/**
* Returns the outer most DOMComponent of the current wrapper.
*
Expand Down Expand Up @@ -345,7 +382,7 @@ class ReactWrapper {
* @returns {Boolean}
*/
matchesElement(node) {
return this.single('matchesElement', () => nodeMatches(node, this.getNode(), (a, b) => a <= b));
return this.single('matchesElement', () => nodeMatches(node, this.getNodeInternal(), (a, b) => a <= b));
}

/**
Expand Down Expand Up @@ -624,7 +661,7 @@ class ReactWrapper {
* @returns {ReactWrapper}
*/
children(selector) {
const allChildren = this.flatMap(n => childrenOfNode(n.getNode()).filter(x => typeof x === 'object'));
const allChildren = this.flatMap(n => childrenOfNode(n.getNodeInternal()).filter(x => typeof x === 'object'));
return selector ? allChildren.filter(selector) : allChildren;
}

Expand All @@ -649,7 +686,7 @@ class ReactWrapper {
*/
parents(selector) {
const allParents = this.wrap(
this.single('parents', n => parentsOfNode(n, this.root.getNode())),
this.single('parents', n => parentsOfNode(n, this.root.getNodeInternal())),
);
return selector ? allParents.filter(selector) : allParents;
}
Expand Down Expand Up @@ -739,7 +776,7 @@ class ReactWrapper {
* @returns {ReactWrapper}
*/
forEach(fn) {
this.getNodes().forEach((n, i) => fn.call(this, this.wrap(n), i));
this.getNodesInternal().forEach((n, i) => fn.call(this, this.wrap(n), i));
return this;
}

Expand All @@ -751,7 +788,7 @@ class ReactWrapper {
* @returns {Array}
*/
map(fn) {
return this.getNodes().map((n, i) => fn.call(this, this.wrap(n), i));
return this.getNodesInternal().map((n, i) => fn.call(this, this.wrap(n), i));
}

/**
Expand All @@ -763,7 +800,7 @@ class ReactWrapper {
* @returns {*}
*/
reduce(fn, initialValue) {
return this.getNodes().reduce(
return this.getNodesInternal().reduce(
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
initialValue,
);
Expand All @@ -778,7 +815,7 @@ class ReactWrapper {
* @returns {*}
*/
reduceRight(fn, initialValue) {
return this.getNodes().reduceRight(
return this.getNodesInternal().reduceRight(
(accum, n, i) => fn.call(this, accum, this.wrap(n), i),
initialValue,
);
Expand All @@ -793,7 +830,7 @@ class ReactWrapper {
* @returns {ShallowWrapper}
*/
slice(begin, end) {
return this.wrap(this.getNodes().slice(begin, end));
return this.wrap(this.getNodesInternal().slice(begin, end));
}

/**
Expand All @@ -807,7 +844,7 @@ class ReactWrapper {
throw new Error('ReactWrapper::some() can not be called on the root');
}
const predicate = buildPredicate(selector);
return this.getNodes().some(predicate);
return this.getNodesInternal().some(predicate);
}

/**
Expand All @@ -817,7 +854,7 @@ class ReactWrapper {
* @returns {Boolean}
*/
someWhere(predicate) {
return this.getNodes().some((n, i) => predicate.call(this, this.wrap(n), i));
return this.getNodesInternal().some((n, i) => predicate.call(this, this.wrap(n), i));
}

/**
Expand All @@ -828,7 +865,7 @@ class ReactWrapper {
*/
every(selector) {
const predicate = buildPredicate(selector);
return this.getNodes().every(predicate);
return this.getNodesInternal().every(predicate);
}

/**
Expand All @@ -838,7 +875,7 @@ class ReactWrapper {
* @returns {Boolean}
*/
everyWhere(predicate) {
return this.getNodes().every((n, i) => predicate.call(this, this.wrap(n), i));
return this.getNodesInternal().every((n, i) => predicate.call(this, this.wrap(n), i));
}

/**
Expand All @@ -850,7 +887,7 @@ class ReactWrapper {
* @returns {ReactWrapper}
*/
flatMap(fn) {
const nodes = this.getNodes().map((n, i) => fn.call(this, this.wrap(n), i));
const nodes = this.getNodesInternal().map((n, i) => fn.call(this, this.wrap(n), i));
const flattened = flatten(nodes, true);
const uniques = unique(flattened);
const compacted = compact(uniques);
Expand All @@ -875,7 +912,7 @@ class ReactWrapper {
* @returns {ReactElement}
*/
get(index) {
return this.getNodes()[index];
return this.getElements()[index];
}

/**
Expand All @@ -885,7 +922,7 @@ class ReactWrapper {
* @returns {ReactWrapper}
*/
at(index) {
return this.wrap(this.getNodes()[index]);
return this.wrap(this.getNodesInternal()[index]);
}

/**
Expand Down Expand Up @@ -942,7 +979,7 @@ class ReactWrapper {
`Method “${fnName}” is only meant to be run on a single node. ${this.length} found instead.`,
);
}
return callback.call(this, this.getNode());
return callback.call(this, this.getNodeInternal());
}

/**
Expand All @@ -967,7 +1004,7 @@ class ReactWrapper {
* @returns {String}
*/
debug(options = {}) {
return debugNodes(this.getNodes(), options);
return debugNodes(this.getNodesInternal(), options);
}

/**
Expand Down Expand Up @@ -1009,7 +1046,20 @@ if (ITERATOR_SYMBOL) {
Object.defineProperty(ReactWrapper.prototype, ITERATOR_SYMBOL, {
configurable: true,
value: function iterator() {
return this.nodes[ITERATOR_SYMBOL]();
const iter = this.nodes[ITERATOR_SYMBOL]();
const adapter = getAdapter(this.options);
return {
next() {
const next = iter.next();
if (next.done) {
return { done: true };
}
return {
done: false,
value: adapter.nodeToElement(next.value),
};
},
};
},
});
}
Expand Down
40 changes: 28 additions & 12 deletions src/ShallowWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,28 +153,42 @@ class ShallowWrapper {
*
* @return {ReactElement}
*/
getNode() {
getElement() {
if (this.length !== 1) {
throw new Error(
'ShallowWrapper::getNode() can only be called when wrapping one node',
'ShallowWrapper::getElement() can only be called when wrapping one node',
);
}
return getAdapter(this.options).nodeToElement(this.node);
}

getNodesInternal() {
return this.nodes;
}

/**
* Returns the wrapped ReactElements.
*
* @return {Array<ReactElement>}
*/
getNodes() {
getElements() {
return this.nodes.map(getAdapter(this.options).nodeToElement);
}

// eslint-disable-next-line class-methods-use-this
getNode() {
throw new Error(
'ShallowWrapper::getNode() is no longer supported. Use ShallowWrapper::getElement() instead',
);
}

getNodesInternal() {
return this.nodes;
}

// eslint-disable-next-line class-methods-use-this
getNodes() {
throw new Error(
'ShallowWrapper::getNodes() is no longer supported. Use ShallowWrapper::getElements() instead',
);
}

/**
* Gets the instance of the component being rendered as the root node passed into `shallow()`.
*
Expand Down Expand Up @@ -379,7 +393,8 @@ class ShallowWrapper {
* @returns {Boolean}
*/
contains(nodeOrNodes) {
if (!isReactElementAlike(nodeOrNodes)) {
const adapter = getAdapter(this.options);
if (!isReactElementAlike(nodeOrNodes, adapter)) {
throw new Error(
'ShallowWrapper::contains() can only be called with ReactElement (or array of them), ' +
'string or number as argument.',
Expand All @@ -389,9 +404,9 @@ class ShallowWrapper {
? other => containsChildrenSubArray(
nodeEqual,
other,
nodeOrNodes.map(getAdapter(this.options).elementToNode),
nodeOrNodes.map(adapter.elementToNode),
)
: other => nodeEqual(getAdapter(this.options).elementToNode(nodeOrNodes), other);
: other => nodeEqual(adapter.elementToNode(nodeOrNodes), other);

return findWhereUnwrapped(this, predicate).length > 0;
}
Expand Down Expand Up @@ -1091,13 +1106,14 @@ class ShallowWrapper {
* @returns {ShallowWrapper}
*/
dive(options = {}) {
const adapter = getAdapter(this.options);
const name = 'dive';
return this.single(name, (n) => {
if (n && n.nodeType === 'host') {
throw new TypeError(`ShallowWrapper::${name}() can not be called on Host Components`);
}
const el = getAdapter(this.options).nodeToElement(n);
if (!isCustomComponentElement(el)) {
if (!isCustomComponentElement(el, adapter)) {
throw new TypeError(`ShallowWrapper::${name}() can only be called on components`);
}
return this.wrap(el, null, { ...this.options, ...options });
Expand All @@ -1112,7 +1128,7 @@ if (ITERATOR_SYMBOL) {
const iter = this.nodes[ITERATOR_SYMBOL]();
const adapter = getAdapter(this.options);
return {
next: () => {
next() {
const next = iter.next();
if (next.done) {
return { done: true };
Expand Down
8 changes: 4 additions & 4 deletions src/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export function isFunctionalComponent(inst) {
functionName(inst.constructor) === 'StatelessComponent';
}

export function isCustomComponentElement(inst) {
return !!inst && React.isValidElement(inst) && typeof inst.type === 'function';
export function isCustomComponentElement(inst, adapter) {
return !!inst && adapter.isValidElement(inst) && typeof inst.type === 'function';
}

function propsOfNode(node) {
Expand Down Expand Up @@ -190,8 +190,8 @@ function isTextualNode(node) {
return typeof node === 'string' || typeof node === 'number';
}

export function isReactElementAlike(arg) {
return React.isValidElement(arg) || isTextualNode(arg) || Array.isArray(arg);
export function isReactElementAlike(arg, adapter) {
return adapter.isValidElement(arg) || isTextualNode(arg) || Array.isArray(arg);
}

// TODO(lmr): can we get rid of this outside of the adapter?
Expand Down
8 changes: 8 additions & 0 deletions src/adapters/ReactFifteenFourAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,14 @@ class ReactFifteenFourAdapter extends EnzymeAdapter {
nodeToHostNode(node) {
return ReactDOM.findDOMNode(node.instance);
}

isValidElement(element) {
return React.isValidElement(element);
}

createElement(...args) {
return React.createElement(...args);
}
}

module.exports = ReactFifteenFourAdapter;
8 changes: 8 additions & 0 deletions src/adapters/ReactFourteenAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ class ReactFifteenAdapter extends EnzymeAdapter {
nodeToHostNode(node) {
return ReactDOM.findDOMNode(node.instance);
}

isValidElement(element) {
return React.isValidElement(element);
}

createElement(...args) {
return React.createElement(...args);
}
}

module.exports = ReactFifteenAdapter;

0 comments on commit 568ce89

Please sign in to comment.