Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Fixed confusing prop selector behavior. Added helpful warning
  • Loading branch information
lelandrichardson committed Jan 20, 2016
commit 0033fbf50f4e36b0c0acdb74496a906f27e87dc9
2 changes: 1 addition & 1 deletion src/MountedTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export function instHasProperty(inst, propKey, stringifiedPropValue) {
const nodeProps = propsOfNode(node);
const nodePropValue = nodeProps[propKey];

const propValue = coercePropValue(stringifiedPropValue);
const propValue = coercePropValue(propKey, stringifiedPropValue);

// intentionally not matching node props that are undefined
if (nodePropValue === undefined) {
Expand Down
2 changes: 1 addition & 1 deletion src/ShallowTraversal.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function nodeHasId(node, id) {

export function nodeHasProperty(node, propKey, stringifiedPropValue) {
const nodeProps = propsOfNode(node);
const propValue = coercePropValue(stringifiedPropValue);
const propValue = coercePropValue(propKey, stringifiedPropValue);
const nodePropValue = nodeProps[propKey];

if (nodePropValue === undefined) {
Expand Down
19 changes: 14 additions & 5 deletions src/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,27 +149,36 @@ export function AND(fns) {
};
}

export function coercePropValue(propValue) {
export function coercePropValue(propName, propValue) {
// can be undefined
if (propValue === undefined) {
return propValue;
}

const trimmedValue = propValue.trim();

// if propValue includes quotes, it should be
// treated as a string
if (propValue.search(/"/) !== -1) {
return propValue.replace(/"/g, '');
if (/^(['"]).*\1$/.test(trimmedValue)) {
return trimmedValue.slice(1, -1);
}

const numericPropValue = parseInt(propValue, 10);
const numericPropValue = +trimmedValue;

// if parseInt is not NaN, then we've wanted a number
if (!isNaN(numericPropValue)) {
return numericPropValue;
}

// coerce to boolean
return propValue === 'true' ? true : false;
if (trimmedValue === 'true') return true;
if (trimmedValue === 'false') return false;

// user provided an unquoted string value
throw new TypeError(
`Enzyme::Unable to parse selector '[${propName}=${propValue}]'. ` +
`Perhaps you forgot to escape a string? Try '[${propName}="${trimmedValue}"]' instead.`
);
}

export function mapNativeEventNames(event) {
Expand Down
33 changes: 31 additions & 2 deletions src/__tests__/ShallowTraversal-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ describe('ShallowTraversal', () => {
const node = (<div onChange={noop} title="foo" />);

expect(nodeHasProperty(node, 'onChange')).to.equal(true);
expect(nodeHasProperty(node, 'title', 'foo')).to.equal(true);
expect(nodeHasProperty(node, 'title', '"foo"')).to.equal(true);
});

it('should not match on html attributes', () => {
const node = (<div htmlFor="foo" />);

expect(nodeHasProperty(node, 'for', 'foo')).to.equal(false);
expect(nodeHasProperty(node, 'for', '"foo"')).to.equal(false);
});

it('should not find undefined properties', () => {
Expand All @@ -79,6 +79,35 @@ describe('ShallowTraversal', () => {
expect(nodeHasProperty(node, 'title')).to.equal(false);
});

it('should parse false as a literal', () => {
const node = (<div foo={false} />);

expect(nodeHasProperty(node, 'foo', 'false')).to.equal(true);
});

it('should parse false as a literal', () => {
const node = (<div foo />);

expect(nodeHasProperty(node, 'foo', 'true')).to.equal(true);
});

it('should parse numbers as numeric literals', () => {
expect(nodeHasProperty(<div foo={2.3} />, 'foo', '2.3')).to.equal(true);
expect(nodeHasProperty(<div foo={2} />, 'foo', '2')).to.equal(true);
expect(() => nodeHasProperty(<div foo={2} />, 'foo', '2abc')).to.throw();
expect(() => nodeHasProperty(<div foo={2} />, 'foo', 'abc2')).to.throw();
expect(nodeHasProperty(<div foo={-2} />, 'foo', '-2')).to.equal(true);
expect(nodeHasProperty(<div foo={2e8} />, 'foo', '2e8')).to.equal(true);
expect(nodeHasProperty(<div foo={Infinity} />, 'foo', 'Infinity')).to.equal(true);
expect(nodeHasProperty(<div foo={-Infinity} />, 'foo', '-Infinity')).to.equal(true);
});

it('should throw when un unquoted string is passed in', () => {
const node = (<div title="foo" />);

expect(() => nodeHasProperty(node, 'title', 'foo')).to.throw();
});

});

describe('treeForEach', () => {
Expand Down
11 changes: 11 additions & 0 deletions src/__tests__/ShallowWrapper-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,17 @@ describe('shallow', () => {
expect(wrapper.find('[title]')).to.have.length(1);
});

it('should error sensibly if prop selector without quotes', () => {
const wrapper = shallow(
<div>
<input type="text" />
<input type="hidden" />
</div>
);

expect(() => wrapper.find('[type=text]')).to.throw();
});

it('should compound tag and prop selector', () => {
const wrapper = shallow(
<div>
Expand Down
12 changes: 6 additions & 6 deletions src/__tests__/Utils-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,19 +227,19 @@ describe('Utils', () => {
});

describe('coercePropValue', () => {

const key = 'foo';
it('returns undefined if passed undefined', () => {
expect(coercePropValue(undefined)).to.equal(undefined);
expect(coercePropValue(key, undefined)).to.equal(undefined);
});

it('returns number if passed a stringified number', () => {
expect(coercePropValue('1')).to.be.equal(1);
expect(coercePropValue('0')).to.be.equal(0);
expect(coercePropValue(key, '1')).to.be.equal(1);
expect(coercePropValue(key, '0')).to.be.equal(0);
});

it('returns a boolean if passed a stringified bool', () => {
expect(coercePropValue('true')).to.equal(true);
expect(coercePropValue('false')).to.equal(false);
expect(coercePropValue(key, 'true')).to.equal(true);
expect(coercePropValue(key, 'false')).to.equal(false);
});
});

Expand Down