Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not return false positive when passing function (and other non-Rea… #259

Merged
merged 1 commit into from
May 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/ShallowWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
withSetStateAllowed,
propsOfNode,
typeOfNode,
isReactElementAlike,
} from './Utils';
import {
debugNodes,
Expand Down Expand Up @@ -209,6 +210,13 @@ export default class ShallowWrapper {
* @returns {Boolean}
*/
contains(nodeOrNodes) {
if (!isReactElementAlike(nodeOrNodes)) {
throw new Error(
'ShallowWrapper::contains() can only be called with ReactElement (or array of them), ' +
'string or number as argument.'
);
}

const predicate = Array.isArray(nodeOrNodes)
? other => containsChildrenSubArray(nodeEqual, other, nodeOrNodes)
: other => nodeEqual(nodeOrNodes, other);
Expand Down
10 changes: 9 additions & 1 deletion src/Utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint no-use-before-define:0 */
import isEqual from 'lodash/isEqual';
import React from 'react';
import {
isDOMComponent,
findDOMNode,
Expand Down Expand Up @@ -94,7 +95,7 @@ export function nodeEqual(a, b) {
}
}

if (typeof a !== 'string' && typeof a !== 'number') {
if (!isTextualNode(a)) {
return leftKeys.length === Object.keys(right).length;
}

Expand All @@ -117,6 +118,13 @@ function childrenOfNode(node) {
return childrenToArray(children);
}

function isTextualNode(node) {
return typeof node === 'string' || typeof node === 'number';
}

export function isReactElementAlike(arg) {
return React.isValidElement(arg) || isTextualNode(arg) || Array.isArray(arg);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 one thing that's still not great... a very common mistake will be passing in a string selector: ie .contains('.button-class') in such a way that this won't throw, since text is a valid node.

Not sure what we can do about that at this point though...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it is for sure a common issue for people that they assume selectors are allowed here.

Maybe we should allow them and try to merge those 2 different logics of selectors and nodeEquals into one? Although I ain't sure if that's even possible elegantly.

}

// 'click' => 'onClick'
// 'mouseEnter' => 'onMouseEnter'
Expand Down
7 changes: 7 additions & 0 deletions test/ShallowWrapper-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,13 @@ describe('shallow', () => {
expect(wrapper.contains(passes2)).to.equal(true);
});

it('should throw on invalid argument', () => {
const wrapper = shallow(<div></div>);

expect(() => wrapper.contains({})).to.throw();
expect(() => wrapper.contains(() => ({}))).to.throw();
});

describeIf(!REACT013, 'stateless function components', () => {
it('should match composite components', () => {
const Foo = () => (
Expand Down