diff --git a/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx b/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
index 51760b9de..d902bd494 100644
--- a/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
+++ b/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
@@ -436,508 +436,528 @@ describeWithDOM('mount', () => {
});
});
- describe('.find(selector)', () => {
- it('should find an element based on a class name', () => {
- const wrapper = mount((
-
-
-
- ));
- expect(wrapper.find('.foo').type()).to.equal('input');
- });
-
- it('should find an SVG element based on a class name', () => {
- const wrapper = mount((
-
-
-
- ));
- expect(wrapper.find('.foo').type()).to.equal('svg');
- });
-
- it('should find an element based on a tag name', () => {
- const wrapper = mount((
-
-
-
- ));
- expect(wrapper.find('input').props().className).to.equal('foo');
- });
-
- it('should find an element based on a tag name and class name', () => {
- const wrapper = mount((
-
+ wrap()
+ .withOverride(() => getAdapter(), 'isValidElementType', () => undefined)
+ .describe('.find(selector)', () => {
+ it('should find an element based on a class name', () => {
+ const wrapper = mount((
+
+
-
- ));
- expect(wrapper.find('.a')).to.have.lengthOf(1);
- expect(wrapper.find('.b')).to.have.lengthOf(2);
- expect(wrapper.find('.b').find('.c')).to.have.lengthOf(6);
- });
+ ));
+ expect(wrapper.find('.foo').type()).to.equal('input');
+ });
+ it('should find an SVG element based on a class name', () => {
+ const wrapper = mount((
+
+
+
+ ));
+ expect(wrapper.find('.foo').type()).to.equal('svg');
+ });
- it('should find an element based on a tag name and id', () => {
- const wrapper = mount((
-
-
-
- ));
- expect(wrapper.find('input#foo')).to.have.lengthOf(1);
- });
+ it('should find an element based on a tag name', () => {
+ const wrapper = mount((
+
+
+
+ ));
+ expect(wrapper.find('input').props().className).to.equal('foo');
+ });
- it('should find an element based on a tag name, id, and class name', () => {
- const wrapper = mount((
-
-
-
- ));
- expect(wrapper.find('input#foo.bar')).to.have.lengthOf(1);
- });
+ it('should find an element based on a tag name and class name', () => {
+ const wrapper = mount((
+
+
+
+
+ ));
+ expect(wrapper.find('input.foo')).to.have.lengthOf(1);
+ });
- it('should find a component based on a constructor', () => {
- class Foo extends React.Component {
- render() { return ; }
- }
- const wrapper = mount((
-
+ ));
+ expect(wrapper.find('.a')).to.have.lengthOf(1);
+ expect(wrapper.find('.b')).to.have.lengthOf(2);
+ expect(wrapper.find('.b').find('.c')).to.have.lengthOf(6);
+ });
- it('should find a component based on a component displayName', () => {
- class Foo extends React.Component {
- render() { return ; }
- }
- const wrapper = mount((
-
-
-
- ));
- expect(wrapper.find('Foo').type()).to.equal(Foo);
- });
- describeIf(is('> 0.13'), 'stateless components', () => {
- it('should find a stateless component based on a component displayName', () => {
- const Foo = () => ;
+ it('should find an element based on a tag name and id', () => {
const wrapper = mount((
-
+
));
- expect(wrapper.find('Foo').type()).to.equal(Foo);
+ expect(wrapper.find('input#foo')).to.have.lengthOf(1);
});
- it('should find a stateless component based on a component displayName if rendered by function', () => {
- const Foo = () => ;
- const renderStatelessComponent = () => ;
+ it('should find an element based on a tag name, id, and class name', () => {
const wrapper = mount((
- {renderStatelessComponent()}
+
));
- expect(wrapper.find('Foo').type()).to.equal(Foo);
+ expect(wrapper.find('input#foo.bar')).to.have.lengthOf(1);
});
- });
-
- it('should find component based on a react prop', () => {
- const wrapper = mount((
-
-
-
-
- ));
- expect(wrapper.find('[htmlFor="foo"]')).to.have.lengthOf(1);
- expect(wrapper.find('[htmlFor]')).to.have.lengthOf(2);
- });
-
- it('should error sensibly if any of the search props are undefined', () => {
- const wrapper = mount((
-
-
-
- ));
-
- expect(() => wrapper.find({ type: undefined })).to.throw(
- TypeError,
- 'Enzyme::Props can’t have `undefined` values. Try using ‘findWhere()’ instead.',
- );
- });
+ it('should find a component based on a constructor', () => {
+ class Foo extends React.Component {
+ render() { return ; }
+ }
+ const wrapper = mount((
+
- ));
- expect(() => wrapper.find({})).to.throw(
- TypeError,
- 'Enzyme::Selector does not support an array, null, or empty object as a selector',
- );
- expect(() => wrapper.find([])).to.throw(
- TypeError,
- 'Enzyme::Selector does not support an array, null, or empty object as a selector',
- );
- expect(() => wrapper.find(null)).to.throw(
- TypeError,
- 'Enzyme::Selector does not support an array, null, or empty object as a selector',
- );
- });
+ it('should support boolean and numeric values for matching props', () => {
+ const wrapper = mount((
+
+
+
+
+
+
+
+
+ ));
- it('Should query attributes with spaces in their values', () => {
- const wrapper = mount((
-
);
- expect(wrapper.find('h1')).to.have.lengthOf(1);
- expect(containerDiv.querySelectorAll('h1')).to.have.lengthOf(1);
- });
+ const wrapper = mount();
- describeIf(is('> 0.13'), 'stateless function components', () => {
- it('should find a component based on a constructor', () => {
- const Foo = () => ;
+ expect(wrapper.find('div[ref="foo"]')).to.have.lengthOf(0);
+ expect(wrapper.find('div[key="1"]')).to.have.lengthOf(0);
+ expect(wrapper.find('[ref]')).to.have.lengthOf(0);
+ expect(wrapper.find('[key]')).to.have.lengthOf(0);
+ });
+
+ it('should find multiple elements based on a class name', () => {
const wrapper = mount((
-
+
+
));
- expect(wrapper.find(Foo).type()).to.equal(Foo);
+ expect(wrapper.find('.foo')).to.have.lengthOf(2);
});
- it('should find a component based on a component displayName', () => {
- const Foo = () => ;
+ it('should find multiple elements based on a tag name', () => {
const wrapper = mount((
));
+ expect(() => wrapper.find({})).to.throw(
+ TypeError,
+ 'Enzyme::Selector does not support an array, null, or empty object as a selector',
+ );
+ expect(() => wrapper.find([])).to.throw(
+ TypeError,
+ 'Enzyme::Selector does not support an array, null, or empty object as a selector',
+ );
+ expect(() => wrapper.find(null)).to.throw(
+ TypeError,
+ 'Enzyme::Selector does not support an array, null, or empty object as a selector',
+ );
});
- it('works with an ID', () => {
- expect(wrapper.find('a#test')).to.have.lengthOf(1);
+ it('Should query attributes with spaces in their values', () => {
+ const wrapper = mount((
+
- );
+ ));
+ });
+
+ it('works with an ID', () => {
+ expect(wrapper.find('a#test')).to.have.lengthOf(1);
+ });
+
+ it('works with a normal attribute', () => {
+ expect(wrapper.find('a[href="/page"]')).to.have.lengthOf(1);
+ });
+
+ it('works with an attribute with a #', () => {
+ expect(wrapper.find('a[href="/page#anchor"]')).to.have.lengthOf(1);
+ });
+ });
+
+ describe('works with data- attributes', () => {
+ class Foo extends React.Component {
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ }
}
- }
- it('finds elements by data attribute', () => {
- const wrapper = mount();
- expect(wrapper.html()).to.contain('data-custom-tag="bookIcon"'); // sanity check
- const elements = wrapper.find('[data-custom-tag="bookIcon"]');
- expect(elements).to.have.lengthOf(2);
- expect(elements.filter('i')).to.have.lengthOf(2);
+ it('finds elements by data attribute', () => {
+ const wrapper = mount();
+ expect(wrapper.html()).to.contain('data-custom-tag="bookIcon"'); // sanity check
+ const elements = wrapper.find('[data-custom-tag="bookIcon"]');
+ expect(elements).to.have.lengthOf(2);
+ expect(elements.filter('i')).to.have.lengthOf(2);
+ });
});
});
- });
describe('.findWhere(predicate)', () => {
it('should return all elements for a truthy test', () => {
diff --git a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
index ce19067d9..1894b18ce 100644
--- a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
+++ b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
@@ -500,469 +500,489 @@ describe('shallow', () => {
});
});
- describe('.find(selector)', () => {
- it('should be able to match the root DOM element', () => {
- const wrapper = shallow(
hello
);
- expect(wrapper.find('#ttt')).to.have.lengthOf(1);
- expect(wrapper.find('.ttt')).to.have.lengthOf(1);
- });
-
- it('should find an element based on a class name', () => {
- const wrapper = shallow((
-
-
-
- ));
- expect(wrapper.find('.foo').type()).to.equal('input');
- });
+ wrap()
+ .withOverride(() => getAdapter(), 'isValidElementType', () => undefined)
+ .describe('.find(selector)', () => {
+ it('should be able to match the root DOM element', () => {
+ const wrapper = shallow(
hello
);
+ expect(wrapper.find('#ttt')).to.have.lengthOf(1);
+ expect(wrapper.find('.ttt')).to.have.lengthOf(1);
+ });
- it('should find an element that has dot in attribute', () => {
- const wrapper = shallow((
-
-
-
- ));
+ it('should find an element based on a class name', () => {
+ const wrapper = shallow((
+
+
+
+ ));
+ expect(wrapper.find('.foo').type()).to.equal('input');
+ });
- const elements = wrapper.find('[data-baz="foo.bar"]');
- expect(elements).to.have.lengthOf(1);
- });
+ it('should find an element that has dot in attribute', () => {
+ const wrapper = shallow((
+
+
+
+ ));
- it('should find an element that with class and attribute', () => {
- const wrapper = shallow((
-
-
-
- ));
+ const elements = wrapper.find('[data-baz="foo.bar"]');
+ expect(elements).to.have.lengthOf(1);
+ });
- const elements = wrapper.find('.classBar[data-baz="bar"]');
- expect(elements).to.have.lengthOf(1);
- });
+ it('should find an element that with class and attribute', () => {
+ const wrapper = shallow((
+
+
+
+ ));
- it('should find an element that with multiple classes and one attribute', () => {
- const wrapper = shallow((
-
-
-
- ));
+ const elements = wrapper.find('.classBar[data-baz="bar"]');
+ expect(elements).to.have.lengthOf(1);
+ });
- const elements = wrapper.find('.classBar.classFoo[data-baz="bar"]');
- expect(elements).to.have.lengthOf(1);
- });
+ it('should find an element that with multiple classes and one attribute', () => {
+ const wrapper = shallow((
+
+
+
+ ));
- it('should find an element that with class and class with hyphen', () => {
- const wrapper = shallow((
-
-
-
- ));
+ const elements = wrapper.find('.classBar.classFoo[data-baz="bar"]');
+ expect(elements).to.have.lengthOf(1);
+ });
- const elements = wrapper.find('.classBar.class-Foo');
- expect(elements).to.have.lengthOf(1);
- });
+ it('should find an element that with class and class with hyphen', () => {
+ const wrapper = shallow((
+
+
+
+ ));
- it('should find an element based on a tag name and class name', () => {
- const wrapper = shallow((
-
-
-
- ));
- expect(wrapper.find('input.foo')).to.have.lengthOf(1);
- });
+ const elements = wrapper.find('.classBar.class-Foo');
+ expect(elements).to.have.lengthOf(1);
+ });
- it('should find an element based on a tag name and id', () => {
- const wrapper = shallow((
-
-
-
- ));
- expect(wrapper.find('input#foo')).to.have.lengthOf(1);
- });
+ it('should find an element based on a tag name and class name', () => {
+ const wrapper = shallow((
+
+
+
+ ));
+ expect(wrapper.find('input.foo')).to.have.lengthOf(1);
+ });
- it('should find an element based on a tag name, id, and class name', () => {
- const wrapper = shallow((
-
-
-
- ));
- expect(wrapper.find('input#foo.bar')).to.have.lengthOf(1);
- });
+ it('should find an element based on a tag name and id', () => {
+ const wrapper = shallow((
+
+
+
+ ));
+ expect(wrapper.find('input#foo')).to.have.lengthOf(1);
+ });
- it('should find an element based on a tag name', () => {
- const wrapper = shallow((
-
-
-
-
-
-
- ));
- expect(wrapper.find('input').props().className).to.equal('foo');
- expect(wrapper.find('button').props().className).to.equal('bar');
- expect(wrapper.find('textarea').props().className).to.equal('magic');
- expect(wrapper.find('select').props().className).to.equal('reality');
- });
+ it('should find an element based on a tag name, id, and class name', () => {
+ const wrapper = shallow((
+
+
+
+ ));
+ expect(wrapper.find('input#foo.bar')).to.have.lengthOf(1);
+ });
- it('should find a component based on a constructor', () => {
- class Foo extends React.Component {
- render() { return ; }
- }
- const wrapper = shallow((
-
-
-
- ));
- expect(wrapper.find(Foo).type()).to.equal(Foo);
- });
+ it('should find an element based on a tag name', () => {
+ const wrapper = shallow((
+
+
+
+
+
+
+ ));
+ expect(wrapper.find('input').props().className).to.equal('foo');
+ expect(wrapper.find('button').props().className).to.equal('bar');
+ expect(wrapper.find('textarea').props().className).to.equal('magic');
+ expect(wrapper.find('select').props().className).to.equal('reality');
+ });
- it('should find a component based on a display name', () => {
- class Foo extends React.Component {
- render() { return ; }
- }
- const wrapper = shallow((
-
-
-
- ));
- expect(wrapper.find('Foo').type()).to.equal(Foo);
- });
+ it('should find a component based on a constructor', () => {
+ class Foo extends React.Component {
+ render() { return ; }
+ }
+ const wrapper = shallow((
+
+
+
+ ));
+ expect(wrapper.find(Foo).type()).to.equal(Foo);
+ });
- it('should find multiple elements based on a class name', () => {
- const wrapper = shallow((
-
- ));
- expect(() => wrapper.find({})).to.throw(
- TypeError,
- 'Enzyme::Selector does not support an array, null, or empty object as a selector',
- );
- expect(() => wrapper.find([])).to.throw(
- TypeError,
- 'Enzyme::Selector does not support an array, null, or empty object as a selector',
- );
- expect(() => wrapper.find(null)).to.throw(
- TypeError,
- 'Enzyme::Selector does not support an array, null, or empty object as a selector',
- );
- });
+ const wrapper = shallow((
+
+
+ {arrayOfComponents}
+
+ ));
- it('Should query attributes with spaces in their values', () => {
- const wrapper = shallow((
-
-
Hello
-
World
-
- ));
- expect(wrapper.find('[data-foo]')).to.have.lengthOf(2);
- expect(wrapper.find('[data-foo="foo bar"]')).to.have.lengthOf(1);
- expect(wrapper.find('[data-foo="bar baz quz"]')).to.have.lengthOf(1);
- expect(wrapper.find('[data-foo="bar baz"]')).to.have.lengthOf(0);
- expect(wrapper.find('[data-foo="foo bar"]')).to.have.lengthOf(0);
- expect(wrapper.find('[data-foo="bar baz quz"]')).to.have.lengthOf(0);
- });
+ expect(wrapper.find('div[ref="foo"]')).to.have.lengthOf(0);
+ expect(wrapper.find('div[key="1"]')).to.have.lengthOf(0);
+ expect(wrapper.find('[ref]')).to.have.lengthOf(0);
+ expect(wrapper.find('[key]')).to.have.lengthOf(0);
+ });
- describeIf(is('> 0.13'), 'stateless function components', () => {
- it('should find a component based on a constructor', () => {
- const Foo = () => (
-
- );
+ it('should find multiple elements based on a constructor', () => {
const wrapper = shallow((
-
+
+
+
));
- expect(wrapper.find(Foo).type()).to.equal(Foo);
+ expect(wrapper.find('input')).to.have.lengthOf(2);
+ expect(wrapper.find('button')).to.have.lengthOf(1);
});
- it('should find a component based on a display name', () => {
- const Foo = () => (
-
- );
+ it('should support object property selectors', () => {
const wrapper = shallow((
+ ));
+ expect(() => wrapper.find({})).to.throw(
+ TypeError,
+ 'Enzyme::Selector does not support an array, null, or empty object as a selector',
+ );
+ expect(() => wrapper.find([])).to.throw(
+ TypeError,
+ 'Enzyme::Selector does not support an array, null, or empty object as a selector',
+ );
+ expect(() => wrapper.find(null)).to.throw(
+ TypeError,
+ 'Enzyme::Selector does not support an array, null, or empty object as a selector',
+ );
});
- it('works with a normal attribute', () => {
- expect(wrapper.find('a[href="/page"]')).to.have.lengthOf(1);
+ it('Should query attributes with spaces in their values', () => {
+ const wrapper = shallow((
+
+
Hello
+
World
+
+ ));
+ expect(wrapper.find('[data-foo]')).to.have.lengthOf(2);
+ expect(wrapper.find('[data-foo="foo bar"]')).to.have.lengthOf(1);
+ expect(wrapper.find('[data-foo="bar baz quz"]')).to.have.lengthOf(1);
+ expect(wrapper.find('[data-foo="bar baz"]')).to.have.lengthOf(0);
+ expect(wrapper.find('[data-foo="foo bar"]')).to.have.lengthOf(0);
+ expect(wrapper.find('[data-foo="bar baz quz"]')).to.have.lengthOf(0);
});
- it('works with an attribute with a #', () => {
- expect(wrapper.find('a[href="/page#anchor"]')).to.have.lengthOf(1);
+ describeIf(is('> 0.13'), 'stateless function components', () => {
+ it('should find a component based on a constructor', () => {
+ const Foo = () => (
+
+ );
+ const wrapper = shallow((
+
+
+
+ ));
+ expect(wrapper.find(Foo).type()).to.equal(Foo);
+ });
+
+ it('should find a component based on a display name', () => {
+ const Foo = () => (
+
+ );
+ const wrapper = shallow((
+
- );
+ ));
+ });
+
+ it('works with an ID', () => {
+ expect(wrapper.find('a#test')).to.have.lengthOf(1);
+ });
+
+ it('works with a normal attribute', () => {
+ expect(wrapper.find('a[href="/page"]')).to.have.lengthOf(1);
+ });
+
+ it('works with an attribute with a #', () => {
+ expect(wrapper.find('a[href="/page#anchor"]')).to.have.lengthOf(1);
+ });
+ });
+
+ describe('works with data- attributes', () => {
+ class Foo extends React.Component {
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ }
}
- }
- it('finds elements by data attribute', () => {
- const wrapper = shallow();
- expect(wrapper.html()).to.contain('data-custom-tag="bookIcon"'); // sanity check
- const elements = wrapper.find('[data-custom-tag="bookIcon"]');
- expect(elements).to.have.lengthOf(2);
- expect(elements.filter('i')).to.have.lengthOf(2);
+ it('finds elements by data attribute', () => {
+ const wrapper = shallow();
+ expect(wrapper.html()).to.contain('data-custom-tag="bookIcon"'); // sanity check
+ const elements = wrapper.find('[data-custom-tag="bookIcon"]');
+ expect(elements).to.have.lengthOf(2);
+ expect(elements.filter('i')).to.have.lengthOf(2);
+ });
});
});
- });
describe('.findWhere(predicate)', () => {
it('should return all elements for a truthy test', () => {
diff --git a/packages/enzyme/src/selectors.js b/packages/enzyme/src/selectors.js
index 8cb98737f..096a6c69b 100644
--- a/packages/enzyme/src/selectors.js
+++ b/packages/enzyme/src/selectors.js
@@ -13,7 +13,7 @@ import {
childrenOfNode,
hasClassName,
} from './RSTTraversal';
-import { nodeHasType, propsOfNode } from './Utils';
+import { getAdapter, nodeHasType, propsOfNode } from './Utils';
// our CSS selector parser instance
const parser = createParser();
@@ -239,8 +239,22 @@ function isComplexSelector(tokens) {
* @param {Function|Object|String} selector
*/
export function buildPredicate(selector) {
- // If the selector is a function, check if the node's constructor matches
- if (typeof selector === 'function') {
+ // If the selector is a string, parse it as a simple CSS selector
+ if (typeof selector === 'string') {
+ const tokens = safelyGenerateTokens(selector);
+ if (isComplexSelector(tokens)) {
+ throw new TypeError('This method does not support complex CSS selectors');
+ }
+ // Simple selectors only have a single selector token
+ return buildPredicateFromToken(tokens[0]);
+ }
+
+ // If the selector is an element type, check if the node's type matches
+ const adapter = getAdapter();
+ const isElementType = adapter.isValidElementType
+ ? adapter.isValidElementType(selector)
+ : typeof selector === 'function';
+ if (isElementType) {
return node => node && node.type === selector;
}
// If the selector is an non-empty object, treat the keys/values as props
@@ -254,16 +268,8 @@ export function buildPredicate(selector) {
}
throw new TypeError('Enzyme::Selector does not support an array, null, or empty object as a selector');
}
- // If the selector is a string, parse it as a simple CSS selector
- if (typeof selector === 'string') {
- const tokens = safelyGenerateTokens(selector);
- if (isComplexSelector(tokens)) {
- throw new TypeError('This method does not support complex CSS selectors');
- }
- // Simple selectors only have a single selector token
- return buildPredicateFromToken(tokens[0]);
- }
- throw new TypeError('Enzyme::Selector expects a string, object, or Component Constructor');
+
+ throw new TypeError('Enzyme::Selector expects a string, object, or valid element type (Component Constructor)');
}
/**