diff --git a/src/MountedTraversal.js b/src/MountedTraversal.js index 54bea0128..9a12d9027 100644 --- a/src/MountedTraversal.js +++ b/src/MountedTraversal.js @@ -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) { diff --git a/src/ShallowTraversal.js b/src/ShallowTraversal.js index e634c2d2e..51634530c 100644 --- a/src/ShallowTraversal.js +++ b/src/ShallowTraversal.js @@ -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) { diff --git a/src/Utils.js b/src/Utils.js index 727e5d177..7f34cac70 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -149,19 +149,21 @@ 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)) { @@ -169,7 +171,14 @@ export function coercePropValue(propValue) { } // 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) { diff --git a/src/__tests__/ShallowTraversal-spec.js b/src/__tests__/ShallowTraversal-spec.js index 2c8eb88db..03f9036c3 100644 --- a/src/__tests__/ShallowTraversal-spec.js +++ b/src/__tests__/ShallowTraversal-spec.js @@ -64,13 +64,13 @@ describe('ShallowTraversal', () => { const node = (
); 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 = (); - expect(nodeHasProperty(node, 'for', 'foo')).to.equal(false); + expect(nodeHasProperty(node, 'for', '"foo"')).to.equal(false); }); it('should not find undefined properties', () => { @@ -79,6 +79,35 @@ describe('ShallowTraversal', () => { expect(nodeHasProperty(node, 'title')).to.equal(false); }); + it('should parse false as a literal', () => { + const node = (); + + expect(nodeHasProperty(node, 'foo', 'false')).to.equal(true); + }); + + it('should parse false as a literal', () => { + const node = (); + + expect(nodeHasProperty(node, 'foo', 'true')).to.equal(true); + }); + + it('should parse numbers as numeric literals', () => { + expect(nodeHasProperty(, 'foo', '2.3')).to.equal(true); + expect(nodeHasProperty(, 'foo', '2')).to.equal(true); + expect(() => nodeHasProperty(, 'foo', '2abc')).to.throw(); + expect(() => nodeHasProperty(, 'foo', 'abc2')).to.throw(); + expect(nodeHasProperty(, 'foo', '-2')).to.equal(true); + expect(nodeHasProperty(, 'foo', '2e8')).to.equal(true); + expect(nodeHasProperty(, 'foo', 'Infinity')).to.equal(true); + expect(nodeHasProperty(, 'foo', '-Infinity')).to.equal(true); + }); + + it('should throw when un unquoted string is passed in', () => { + const node = (); + + expect(() => nodeHasProperty(node, 'title', 'foo')).to.throw(); + }); + }); describe('treeForEach', () => { diff --git a/src/__tests__/ShallowWrapper-spec.js b/src/__tests__/ShallowWrapper-spec.js index dcb50f3d8..372be8b2b 100644 --- a/src/__tests__/ShallowWrapper-spec.js +++ b/src/__tests__/ShallowWrapper-spec.js @@ -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( +