Skip to content

Commit

Permalink
✨ add attribute selector for react
Browse files Browse the repository at this point in the history
  • Loading branch information
FBerthelot committed Dec 12, 2019
1 parent 938f486 commit 8d58694
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,38 @@ describe('shallow - querySelector', () => {
expect(cmp.querySelector('.img').exists()).toBe(true);
});

it('should find element with attributs', () => {
const Component = () => (
<div className="container">
<header>header content</header>
<main>
main content
<svg id="image" className="hello img other-class"/>
</main>
</div>
);

const cmp = shallow(<Component/>);

expect(cmp.querySelector('[id]').exists()).toBe(true);
});

it('should find element with attributs value', () => {
const Component = () => (
<div className="container">
<header>header content</header>
<main>
main content
<svg id="image" className="hello img other-class"/>
</main>
</div>
);

const cmp = shallow(<Component/>);

expect(cmp.querySelector('[id=image]').exists()).toBe(true);
});

it('should find element with a nested selector', () => {
const Component = () => (
<div className="container">
Expand Down
44 changes: 35 additions & 9 deletions packages/component-test-utils-react/src/methods/querySelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const {getTagName} = require('./getTagName');
const {EmptyShallowedComponent} = require('../emptyShallow');
const isIDselectorRegex = /^#(.*)/;
const isClassSelectorRegex = /^\.(.*)/;
const isAttributeSelectorRegex = /^\[([^\]=]+)=?"?([^"]*)"?\]/;

const isSelectedObject = (elem, selectorTree) => {
if (typeof elem !== 'object') {
Expand All @@ -22,12 +23,30 @@ const isSelectedObject = (elem, selectorTree) => {
return selector;
}

const isMatchCurrentSelector =
selector.isIdSelector ?
elem.props && elem.props.id === selector.value :
selector.isClassSelector ?
elem.props && elem.props.className && new RegExp(` ${selector.value} `).test(` ${elem.props.className} `) :
getTagName(elem) === selector.value;
let isMatchCurrentSelector;
// eslint-disable-next-line default-case
switch (selector.type) {
case 'id':
isMatchCurrentSelector = elem.props && elem.props.id === selector.value;
break;
case 'class':
isMatchCurrentSelector = elem.props &&
elem.props.className &&
new RegExp(` ${selector.value} `).test(` ${elem.props.className} `);
break;
case 'attribute': {
const attrNameMatch = Object.keys(elem.props).find(attrName => attrName === selector.value.attrName);
const attrValueMatch = selector.value.attrValue ?
elem.props[selector.value.attrName] === selector.value.attrValue :
true;
isMatchCurrentSelector = attrNameMatch && attrValueMatch;
break;
}

case 'element':
isMatchCurrentSelector = getTagName(elem) === selector.value;
break;
}

const isLastSelector = selectorTree.length === index + 1;
lastValueMatch = isLastSelector && isMatchCurrentSelector;
Expand Down Expand Up @@ -89,19 +108,26 @@ const extractSelectorTree = selector => {
.map(selector => {
const matchId = selector.match(isIDselectorRegex);
const matchClass = selector.match(isClassSelectorRegex);
const matchAttribute = selector.match(isAttributeSelectorRegex);

const isClassSelector = Boolean(matchClass);
const isIdSelector = Boolean(matchId);
const isAttributeSelector = Boolean(matchAttribute);

return {
isIdSelector,
isClassSelector,
type:
isClassSelector ? 'class' :
isAttributeSelector ? 'attribute' :
isIdSelector ? 'id' :
'element',
value:
isIdSelector ?
matchId[1] :
isClassSelector ?
matchClass[1] :
selector
matchAttribute ?
{attrName: matchAttribute[1], attrValue: matchAttribute[2]} :
selector
};
});
};
Expand Down

0 comments on commit 8d58694

Please sign in to comment.