diff --git a/docs/api/ReactWrapper/find.md b/docs/api/ReactWrapper/find.md
index 223bfa2e7..0417b5e7a 100644
--- a/docs/api/ReactWrapper/find.md
+++ b/docs/api/ReactWrapper/find.md
@@ -47,7 +47,11 @@ const wrapper = mount();
expect(wrapper.find('Foo')).to.have.length(1);
```
-
+Object Property Selector:
+```jsx
+const wrapper = mount();
+expect(wrapper.find({prop: 'value'})).to.have.length(1);
+```
#### Related Methods
diff --git a/docs/api/ShallowWrapper/find.md b/docs/api/ShallowWrapper/find.md
index 635602de1..85dd30579 100644
--- a/docs/api/ShallowWrapper/find.md
+++ b/docs/api/ShallowWrapper/find.md
@@ -44,6 +44,11 @@ const wrapper = shallow();
expect(wrapper.find('Foo')).to.have.length(1);
```
+Object Property Selector:
+```jsx
+const wrapper = shallow();
+expect(wrapper.find({prop: 'value'})).to.have.length(1);
+```
#### Related Methods
diff --git a/docs/api/selector.md b/docs/api/selector.md
index 1eb357396..5d11ae734 100644
--- a/docs/api/selector.md
+++ b/docs/api/selector.md
@@ -6,7 +6,7 @@ one of the following three categories:
### 1. A Valid CSS Selector
-Enzyme supports a subset of valid CSS selectors to find nodes inside a render tree. Support is as
+Enzyme supports a subset of valid CSS selectors to find nodes inside a render tree. Support is as
follows:
- class syntax (`.foo`, `.foo-bar`, etc.)
@@ -92,6 +92,25 @@ MyComponent.displayName = 'MyComponent';
const myComponents = wrapper.find('MyComponent');
```
-NOTE: This will *only* work if the selector (and thus the component's `displayName`) is a string
+NOTE: This will *only* work if the selector (and thus the component's `displayName`) is a string
starting with a capital letter. Strings starting with lower case letters will assume it is a CSS
selector using the tag syntax.
+
+
+
+### 4. Object Property Selector
+
+Enzyme allows you to find components and nodes based on a subset of their properties:
+
+
+```jsx
+const wrapper = mount(
+
+
+
+)
+
+wrapper.find({ foo: 3 })
+wrapper.find({ bar: false })
+wrapper.find({ title: 'baz'})
+```
diff --git a/src/MountedTraversal.js b/src/MountedTraversal.js
index 54bea0128..28e0a278f 100644
--- a/src/MountedTraversal.js
+++ b/src/MountedTraversal.js
@@ -1,3 +1,4 @@
+import { isArray, isNull, isMatch, isEmpty } from 'underscore';
import {
coercePropValue,
nodeEqual,
@@ -177,6 +178,12 @@ export function parentsOfInst(inst, root) {
return pathToNode(inst, root).reverse();
}
+export function instHasProps(inst, props) {
+ if (!isDOMComponent(inst)) return false;
+ const node = getNode(inst);
+ return !isEmpty(props) && isMatch(propsOfNode(node), props);
+}
+
export function buildInstPredicate(selector) {
switch (typeof selector) {
case 'function':
@@ -207,8 +214,14 @@ export function buildInstPredicate(selector) {
}
break;
+ case 'object':
+ if (!isArray(selector) && !isNull(selector)) {
+ return node => instHasProps(node, selector);
+ }
+ throw new TypeError('An array or null is not supported as a selector');
+
default:
- throw new TypeError('Expecting a string or Component Constructor');
+ throw new TypeError('Expecting a string, object, or Component Constructor');
}
}
diff --git a/src/ShallowTraversal.js b/src/ShallowTraversal.js
index e634c2d2e..ed8dc1855 100644
--- a/src/ShallowTraversal.js
+++ b/src/ShallowTraversal.js
@@ -1,4 +1,5 @@
import React from 'react';
+import { isArray, isNull, isMatch, isEmpty } from 'underscore';
import {
coercePropValue,
propsOfNode,
@@ -95,6 +96,10 @@ export function nodeHasType(node, type) {
return node.type.name === type || node.type.displayName === type;
}
+export function nodeHasProps(node, props) {
+ return !isEmpty(props) && isMatch(propsOfNode(node), props);
+}
+
export function buildPredicate(selector) {
switch (typeof selector) {
case 'function':
@@ -127,9 +132,14 @@ export function buildPredicate(selector) {
}
break;
+ case 'object':
+ if (!isArray(selector) && !isNull(selector)) {
+ return node => nodeHasProps(node, selector);
+ }
+ throw new TypeError('An array or null is not supported as a selector');
default:
- throw new TypeError('Expecting a string or Component Constructor');
+ throw new TypeError('Expecting a string, object, or Component Constructor');
}
}
diff --git a/src/__tests__/ReactWrapper-spec.js b/src/__tests__/ReactWrapper-spec.js
index 39a216318..4d550d407 100644
--- a/src/__tests__/ReactWrapper-spec.js
+++ b/src/__tests__/ReactWrapper-spec.js
@@ -261,6 +261,61 @@ describeWithDOM('mount', () => {
expect(() => wrapper.find('.foo .foo')).to.throw(Error);
});
+ it('should support object property selectors', () => {
+ const wrapper = mount(
+