diff --git a/package.json b/package.json
index 12bae69..ace4c61 100644
--- a/package.json
+++ b/package.json
@@ -46,5 +46,8 @@
"react": "^0.14.0",
"react-addons-test-utils": "^0.14.0"
},
- "dependencies": {}
+ "dependencies": {
+ "lodash.get": "^3.7.0",
+ "lodash.isequal": "^3.0.4"
+ }
}
diff --git a/specs/find-all-spec.js b/specs/find-all-spec.js
index d3bf66a..ebe356f 100644
--- a/specs/find-all-spec.js
+++ b/specs/find-all-spec.js
@@ -2,40 +2,36 @@ import {findAll} from '../src';
import {createRenderer} from 'react-addons-test-utils';
import React from 'react';
-class OtherComponent extends React.Component {
- render() {
- return (
-
- );
- }
+function OtherComponent() {
+ return (
+
+ );
}
-class TestWithForm extends React.Component {
- render() {
- return (
-
-
-
-
-
-
-
-
Some content
-
- );
- }
+function TestWithForm() {
+ return (
+
+
+
+
+
+
+
+
Some content
+
+ );
}
describe('`findAll`', function() {
diff --git a/specs/find-all-with-class-spec.js b/specs/find-all-with-class-spec.js
index 38a5431..7d617e1 100644
--- a/specs/find-all-with-class-spec.js
+++ b/specs/find-all-with-class-spec.js
@@ -4,19 +4,17 @@ import React from 'react';
describe('`findAllWithClass`', function() {
beforeEach(function() {
- class TestWithClasses extends React.Component {
- render() {
- return (
-
-
-
-
-
-
-
Some content
-
- );
- }
+ function TestWithClasses() {
+ return (
+
+
+
+
+
+
+
Some content
+
+ );
}
this.renderer = createRenderer();
diff --git a/specs/find-all-with-prop-spec.js b/specs/find-all-with-prop-spec.js
new file mode 100644
index 0000000..3700a16
--- /dev/null
+++ b/specs/find-all-with-prop-spec.js
@@ -0,0 +1,70 @@
+import {findAllWithProp} from '../src';
+import {createRenderer} from 'react-addons-test-utils';
+import React from 'react';
+
+describe('`findAllWithProp`', function() {
+ beforeEach(function() {
+ function TestComponent() {
+ const deepObject = {
+ top: {
+ deep: true
+ }
+ };
+
+ return (
+
+ );
+ }
+
+ this.renderer = createRenderer();
+ this.renderer.render();
+ this.tree = this.renderer.getRenderOutput();
+ });
+
+ it('should find one component with `testProp1` equal to `1`', function() {
+ const found = findAllWithProp(this.tree, 'testProp1', 1);
+
+ expect(found.length).toBe(1);
+ });
+
+ it('should find no component with `testProp1` equal to `2`', function() {
+ const found = findAllWithProp(this.tree, 'testProp1', 2);
+
+ expect(found.length).toBe(0);
+ });
+
+ it('should find two components with `testProp3.top` equal to `{deep:true}`', function() {
+ const found = findAllWithProp(this.tree, 'testProp3.top', {deep:true});
+
+ expect(found.length).toBe(2);
+ });
+
+ it('should find no components with `testProp3.top` equal to `{deep:false}`', function() {
+ const found = findAllWithProp(this.tree, 'testProp3.top', {deep:false});
+
+ expect(found.length).toBe(0);
+ });
+
+ it('should find four components with `sameProp` equal to `same`', function() {
+ const found = findAllWithProp(this.tree, 'sameProp', 'same');
+
+ expect(found.length).toBe(4);
+ });
+
+ it('should find no components with `sameProp` equal to `not-same`', function() {
+ const found = findAllWithProp(this.tree, 'sameProp', 'not-same');
+
+ expect(found.length).toBe(0);
+ });
+
+ it('should find no components with non-existant prop', function() {
+ const found = findAllWithProp(this.tree, 'blahblahblah', 1);
+
+ expect(found.length).toBe(0);
+ });
+});
diff --git a/specs/find-all-with-type-spec.js b/specs/find-all-with-type-spec.js
index bcc1861..8623eaf 100644
--- a/specs/find-all-with-type-spec.js
+++ b/specs/find-all-with-type-spec.js
@@ -2,39 +2,33 @@ import {findAllWithType} from '../src';
import {createRenderer} from 'react-addons-test-utils';
import React from 'react';
-class OtherComponent extends React.Component {
- render() {
- return (
-
- );
- }
+function OtherComponent() {
+ return (
+
+ );
}
-class YetAnotherComponent extends React.Component {
- render() {
- return (
-
- );
- }
+function YetAnotherComponent() {
+ return (
+
+ );
}
-class TestWithTypes extends React.Component {
- render() {
- return (
-
- );
- }
+function TestWithTypes() {
+ return (
+
+ );
}
describe('`findAllWithType`', function() {
diff --git a/specs/find-with-class-spec.js b/specs/find-with-class-spec.js
index 6cba63e..e45b850 100644
--- a/specs/find-with-class-spec.js
+++ b/specs/find-with-class-spec.js
@@ -4,18 +4,16 @@ import React from 'react';
describe('`findWithClass`', function() {
beforeEach(function() {
- class TestWithClasses extends React.Component {
- render() {
- return (
-
- );
- }
+ function TestWithClasses() {
+ return (
+
+ );
}
this.renderer = createRenderer();
diff --git a/specs/find-with-prop-spec.js b/specs/find-with-prop-spec.js
new file mode 100644
index 0000000..9f266e8
--- /dev/null
+++ b/specs/find-with-prop-spec.js
@@ -0,0 +1,76 @@
+import {findWithProp} from '../src';
+import {createRenderer} from 'react-addons-test-utils';
+import React from 'react';
+
+describe('`findWithProp`', function() {
+ beforeEach(function() {
+ function TestComponent() {
+ const deepObject = {
+ top: {
+ deep: true
+ }
+ };
+
+ const deepArray = [{
+ name: 'Dave'
+ }, {
+ name: 'Sarah'
+ }, {
+ name: 'John'
+ }];
+
+ return (
+
+ );
+ }
+
+ this.renderer = createRenderer();
+ this.renderer.render();
+ this.tree = this.renderer.getRenderOutput();
+ });
+
+ it('should find component with `testProp1` equal to `1`', function() {
+ expect(() => findWithProp(this.tree, 'testProp1', 1)).not.toThrow();
+ });
+
+ it('should not find component with `testProp1` equal to `2`', function() {
+ expect(() => findWithProp(this.tree, 'testProp1', 2)).toThrow();
+ });
+
+ it('should find component with `testProp2` equal to `testProp2Value`', function() {
+ expect(() => findWithProp(this.tree, 'testProp2', 'testProp2Value')).not.toThrow();
+ });
+
+ it('should not find component with `testProp2` equal to `NOTtestProp2Value`', function() {
+ expect(() => findWithProp(this.tree, 'testProp2', 'NOTtestProp2Value')).toThrow();
+ });
+
+ it('should find component with `testProp3.top` equal to `{deep:true}`', function() {
+ expect(() => findWithProp(this.tree, 'testProp3.top', {deep:true})).not.toThrow();
+ });
+
+ it('should not find component with `testProp3.top` equal to `{deep:false}`', function() {
+ expect(() => findWithProp(this.tree, 'testProp3.top', {deep:false})).toThrow();
+ });
+
+ it('should find component with `testProp4[1].name` equal to `{name: Sarah}`', function() {
+ expect(() => findWithProp(this.tree, 'testProp4[1]', {name: 'Sarah'})).not.toThrow();
+ });
+
+ it('should find component with `testProp4[1].name` equal to `{name: Chris}`', function() {
+ expect(() => findWithProp(this.tree, 'testProp4[1]', {name: 'Chris'})).toThrow();
+ });
+
+ it('should not find exactly one component with `sameProp` equal to `same`', function() {
+ expect(() => findWithProp(this.tree, 'sameProp', 'same')).toThrow();
+ });
+
+ it('should find no components with non-existant prop', function() {
+ expect(() => findWithProp(this.tree, 'blahblahblah', 1)).toThrow();
+ });
+});
diff --git a/specs/find-with-ref-spec.js b/specs/find-with-ref-spec.js
index 81c5f04..37f848a 100644
--- a/specs/find-with-ref-spec.js
+++ b/specs/find-with-ref-spec.js
@@ -2,25 +2,21 @@ import {findWithRef} from '../src';
import {createRenderer} from 'react-addons-test-utils';
import React from 'react';
-class OtherComponent extends React.Component {
- render() {
- return (
-
- );
- }
+function OtherComponent() {
+ return (
+
+ );
}
-class TestWithRefs extends React.Component {
- render() {
- return (
-
- );
- }
+function TestWithRefs() {
+ return (
+
+ );
}
describe('`findWithRef`', function() {
diff --git a/specs/find-with-type-spec.js b/specs/find-with-type-spec.js
index 5418511..120a257 100644
--- a/specs/find-with-type-spec.js
+++ b/specs/find-with-type-spec.js
@@ -2,27 +2,23 @@ import {findWithType} from '../src';
import {createRenderer} from 'react-addons-test-utils';
import React from 'react';
-class OtherComponent extends React.Component {
- render() {
- return (
-
- );
- }
+function OtherComponent() {
+ return (
+
+ );
}
-class TestWithTypes extends React.Component {
- render() {
- return (
-
-
-
-
-
-
Some content
-
-
- );
- }
+function TestWithTypes() {
+ return (
+
+
+
+
+
+
Some content
+
+
+ );
}
describe('`findWithType`', function() {
diff --git a/specs/is-component-of-type-spec.js b/specs/is-component-of-type-spec.js
index 74c8949..d7adf90 100644
--- a/specs/is-component-of-type-spec.js
+++ b/specs/is-component-of-type-spec.js
@@ -2,30 +2,24 @@ import {isComponentOfType} from '../src';
import React from 'react';
import {createRenderer} from 'react-addons-test-utils';
-class OtherComponent extends React.Component {
- render() {
- return (
-
- );
- }
+function OtherComponent() {
+ return (
+
+ );
}
-class WrongComponent extends React.Component {
- render() {
- return (
-
- );
- }
+function WrongComponent() {
+ return (
+
+ );
}
-class Test extends React.Component {
- render() {
- return (
-
-
-
- );
- }
+function Test() {
+ return (
+
+
+
+ );
}
describe('`isComponentOfType`', function() {
diff --git a/specs/is-dom-component-spec.js b/specs/is-dom-component-spec.js
index 16a670c..c38d03a 100644
--- a/specs/is-dom-component-spec.js
+++ b/specs/is-dom-component-spec.js
@@ -2,22 +2,18 @@ import {isDOMComponent} from '../src';
import {createRenderer} from 'react-addons-test-utils';
import React from 'react';
-class OtherComponent extends React.Component {
- render() {
- return (
-
- );
- }
+function OtherComponent() {
+ return (
+
+ );
}
-class Test extends React.Component {
- render() {
- return (
-
-
-
- );
- }
+function Test() {
+ return (
+
+
+
+ );
}
describe('`isDOMComponent`', function() {
diff --git a/src/find-all-with-prop.js b/src/find-all-with-prop.js
new file mode 100644
index 0000000..6045f62
--- /dev/null
+++ b/src/find-all-with-prop.js
@@ -0,0 +1,25 @@
+import isEqual from 'lodash.isequal';
+import findAll from './find-all';
+import get from 'lodash.get';
+import React from 'react';
+
+/**
+ * Finds all instances of components in the tree with a prop found at the
+ * `propPath` that matches `propValue`.
+ *
+ * @param {ReactComponent} tree the rendered tree to traverse
+ * @param {String} propPath the prop path to find
+ * @param {*} propValue the prop value to find
+ * @return {Array} all matching components
+ */
+export default function findAllWithProp(tree, propPath, propValue) {
+ return findAll(tree, component => {
+ if (React.isValidElement(component)) {
+ const value = get(component.props, propPath);
+
+ return isEqual(value, propValue);
+ }
+
+ return false;
+ });
+}
diff --git a/src/find-with-class.js b/src/find-with-class.js
index 23f4080..fe267a2 100644
--- a/src/find-with-class.js
+++ b/src/find-with-class.js
@@ -7,6 +7,7 @@ import findAllWithClass from './find-all-with-class';
* This is different to React's `findRenderedDOMComponentWithClass` in that
* it will check *all* components and not just DOM components.
*
+ * @throws Will throw an error if none or more than one component is found.
* @param {ReactComponent} tree the rendered tree to traverse
* @param {String} className the class to find
* @return {ReactComponent} the matching component
diff --git a/src/find-with-prop.js b/src/find-with-prop.js
new file mode 100644
index 0000000..343b5d5
--- /dev/null
+++ b/src/find-with-prop.js
@@ -0,0 +1,21 @@
+import findAllWithProp from './find-all-with-prop';
+
+/**
+ * Find only one instance of a component in the tree with a prop found at the
+ * `propPath` that matches `propValue`.
+ *
+ * @throws Will throw an error if none or more than one component is found.
+ * @param {ReactComponent} tree the rendered tree to traverse
+ * @param {String} propPath the prop path to find
+ * @param {*} propValue the prop value to find
+ * @return {ReactComponent} the matching component
+ */
+export default function findWithProp(root, propPath, propValue) {
+ const found = findAllWithProp(root, propPath, propValue);
+
+ if (found.length !== 1) {
+ throw new Error(`Did not find exactly once match for prop: ${propPath}, with value: ${propValue}`);
+ }
+
+ return found[0];
+}
diff --git a/src/find-with-ref.js b/src/find-with-ref.js
index e03cf12..3e444e1 100644
--- a/src/find-with-ref.js
+++ b/src/find-with-ref.js
@@ -5,6 +5,7 @@ import findAll from './find-all';
* Finds component in the tree with a ref that matches
* `ref`.
*
+ * @throws Will throw an error if none or more than one component is found.
* @param {ReactComponent} tree the rendered tree to traverse
* @param {String} ref to find
* @return {ReactComponent} found component
diff --git a/src/find-with-type.js b/src/find-with-type.js
index bfea626..8642e85 100644
--- a/src/find-with-type.js
+++ b/src/find-with-type.js
@@ -8,6 +8,7 @@ import findAllWithType from './find-all-with-type';
* `findRenderedComponentWithType` as you can supply a component class or a
* DOM tag.
*
+ * @throws Will throw an error if none or more than one component is found.
* @param {ReactComponent} tree the rendered tree to traverse
* @param {Function|String} type the component type or tag to find
* @return {ReactComponent} the matching component
diff --git a/src/index.js b/src/index.js
index bdddcd0..88deaa7 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,7 +1,9 @@
export findAll from './find-all';
export findAllWithClass from './find-all-with-class';
+export findAllWithProp from './find-all-with-prop';
export findAllWithType from './find-all-with-type';
export findWithClass from './find-with-class';
+export findWithProp from './find-with-prop';
export findWithRef from './find-with-ref';
export findWithType from './find-with-type';
export getMountedInstance from './get-mounted-instance';