Skip to content

Commit

Permalink
support multiple literal types for property lookups
Browse files Browse the repository at this point in the history
  • Loading branch information
blainekasten committed Jan 5, 2016
1 parent 5771873 commit 72872fa
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 9 deletions.
21 changes: 19 additions & 2 deletions docs/api/selector.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,32 @@ follows:
- class syntax (`.foo`, `.foo-bar`, etc.)
- tag syntax (`input`, `div`, `span`, etc.)
- id syntax (`#foo`, `#foo-bar`, etc.)
- prop syntax (`[htmlFor="bar"]`, `[htmlFor]`, etc.);
- prop syntax (`[htmlFor="foo"]`, `[bar]`, `[baz=1]`, etc.);

**Note -- Prop selector**
Strings, numeric literals and boolean property values are supported for prop syntax
in combination of the expected string syntax. For example, the following
is supported:

```js
const wrapper = mount(
<div>
<span foo={3} bar={false} title="baz" />
</div>
)

wrapper.find('[foo=3]')
wrapper.find('[bar=false]')
wrapper.find('[title="baz"]')
```

Further, enzyme supports combining any of those supported syntaxes together to uniquely identify a
single node. For instance:

```css
div.foo.bar
input#input-name
label[htmlfor="checkbox"]
label[foo=true]
```

Are all valid selectors in enzyme. At this time, however, any contextual CSS selector syntax that
Expand Down
16 changes: 11 additions & 5 deletions src/MountedTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,24 @@ export function instHasType(inst, type) {
}
}

export function instHasProp(inst, propKey, stringifiedPropValue) {
export function instHasProperty(inst, propKey, stringifiedPropValue) {
if (!isDOMComponent(inst)) return false;
const node = getNode(inst);
const instProps = propsOfNode(node);
const nodeProps = propsOfNode(node);
const nodePropValue = nodeProps[propKey];

const propValue = coercePropValue(stringifiedPropValue);

// intentionally not matching node props that are undefined
if (nodePropValue === undefined) {
return false;
}

if (propValue) {
return instProps[propKey] === propValue;
return nodePropValue === propValue;
}

return instProps.hasOwnProperty(propKey);
return nodeProps.hasOwnProperty(propKey);
}

// called with private inst
Expand Down Expand Up @@ -194,7 +200,7 @@ export function buildInstPredicate(selector) {
const propKey = selector.split(/\[([a-zA-Z\-\:]*?)(=|\])/)[1];
const propValue = selector.split(/=(.*?)]/)[1];

return node => instHasProp(node, propKey, propValue);
return node => instHasProperty(node, propKey, propValue);
default:
// selector is a string. match to DOM tag or constructor displayName
return inst => instHasType(inst, selector);
Expand Down
7 changes: 6 additions & 1 deletion src/ShallowTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,14 @@ export function nodeHasId(node, id) {
export function nodeHasProperty(node, propKey, stringifiedPropValue) {
const nodeProps = propsOfNode(node);
const propValue = coercePropValue(stringifiedPropValue);
const nodePropValue = nodeProps[propKey];

if (nodePropValue === undefined) {
return false;
}

if (propValue) {
return nodeProps[propKey] === propValue;
return nodePropValue === propValue;
}

return nodeProps.hasOwnProperty(propKey);
Expand Down
14 changes: 13 additions & 1 deletion src/__tests__/ReactWrapper-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,17 @@ describeWithDOM('mount', () => {
expect(wrapper.find('span[htmlFor="foo"][preserveAspectRatio="xMaxYMax"]')).to.have.length(1);
});


it('should not find property when undefined', () => {
const wrapper = mount(
<div>
<span data-foo={undefined} />
</div>
);

expect(wrapper.find('[data-foo]')).to.have.length(0);
});

it('should support boolean and numeric values for matching props', () => {
const wrapper = mount(
<div>
Expand Down Expand Up @@ -196,11 +207,12 @@ describeWithDOM('mount', () => {
}
}


const wrapper = mount(<Foo />);

expect(wrapper.find('div[ref="foo"]')).to.have.length(0);
expect(wrapper.find('div[key="1"]')).to.have.length(0);
expect(wrapper.find('[ref]')).to.have.length(0);
expect(wrapper.find('[key]')).to.have.length(0);
});


Expand Down
6 changes: 6 additions & 0 deletions src/__tests__/ShallowTraversal-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ describe('ShallowTraversal', () => {
expect(nodeHasProperty(node, 'for', 'foo')).to.be.false;
});

it('should not find undefined properties', () => {
const node = (<div title={undefined} />);

expect(nodeHasProperty(node, 'title')).to.be.false;
});

});

describe('treeForEach', () => {
Expand Down
2 changes: 2 additions & 0 deletions src/__tests__/ShallowWrapper-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ describe('shallow', () => {

expect(wrapper.find('div[ref="foo"]')).to.have.length(0);
expect(wrapper.find('div[key="1"]')).to.have.length(0);
expect(wrapper.find('[ref]')).to.have.length(0);
expect(wrapper.find('[key]')).to.have.length(0);
});

it('should find multiple elements based on a constructor', () => {
Expand Down

0 comments on commit 72872fa

Please sign in to comment.