From 9c634b8b19ea164f180745451b5ec5234276d763 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Wed, 9 Nov 2016 11:40:02 -0800 Subject: [PATCH 1/3] [Tests] add failing test cases from #495. --- test/ReactWrapper-spec.jsx | 24 ++++++++++++++++++++++++ test/ShallowWrapper-spec.jsx | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/test/ReactWrapper-spec.jsx b/test/ReactWrapper-spec.jsx index a73ab0c55..9acaa516d 100644 --- a/test/ReactWrapper-spec.jsx +++ b/test/ReactWrapper-spec.jsx @@ -633,6 +633,30 @@ describeWithDOM('mount', () => { expect(wrapper.find('[key]')).to.have.length(0); }); }); + + describe('works with attribute selectors containing #', () => { + let wrapper; + beforeEach(() => { + wrapper = mount( +
+ Hello + World +
+ ); + }); + + 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('.findWhere(predicate)', () => { diff --git a/test/ShallowWrapper-spec.jsx b/test/ShallowWrapper-spec.jsx index 1b713f7b3..7987a5d98 100644 --- a/test/ShallowWrapper-spec.jsx +++ b/test/ShallowWrapper-spec.jsx @@ -661,6 +661,30 @@ describe('shallow', () => { expect(wrapper.find('Foo').type()).to.equal(Foo); }); }); + + describe('works with attribute selectors containing #', () => { + let wrapper; + beforeEach(() => { + wrapper = shallow( +
+ Hello + World +
+ ); + }); + + 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('.findWhere(predicate)', () => { From f979d998660b342412710cb20d76966424a8a5fd Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Wed, 9 Nov 2016 11:44:12 -0800 Subject: [PATCH 2/3] [Fix] Do horrible things with regex to fix ID selectors. Fixes #495. --- package.json | 3 ++- src/Utils.js | 20 +++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9658f5ea2..3c0b32d2b 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,8 @@ "lodash": "^4.16.4", "object-is": "^1.0.1", "object.assign": "^4.0.4", - "object.values": "^1.0.3" + "object.values": "^1.0.3", + "uuid": "^2.0.3" }, "devDependencies": { "babel-cli": "^6.18.0", diff --git a/src/Utils.js b/src/Utils.js index 200e34434..81e0b96d2 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -2,6 +2,7 @@ import isEqual from 'lodash/isEqual'; import React from 'react'; import is from 'object-is'; +import uuid from 'uuid'; import functionName from 'function.prototype.name'; import { isDOMComponent, @@ -171,7 +172,24 @@ export function withSetStateAllowed(fn) { } export function splitSelector(selector) { - return selector.split(/(?=\.|\[.*])|(?=#|\[#.*])/); + // step 1: make a map of all quoted strings with a uuid + const quotedSegments = selector.split(/[^" ]+|("[^"]*")|.*/g) + .filter(Boolean) + .reduce((obj, match) => ({ ...obj, [match]: uuid.v4() }), {}); + + return selector + // step 2: replace all quoted strings with the uuid, so we don't have to properly parse them + .replace(/[^" ]+|("[^"]*")|.*/g, x => quotedSegments[x] || x) + // step 3: split as best we can without a proper parser + .split(/(?=\.|\[.*])|(?=#|\[#.*])/) + // step 4: restore the quoted strings by swapping back the uuid's for the original segments + .map((selectorSegment) => { + let restoredSegment = selectorSegment; + Object.entries(quotedSegments).forEach(([k, v]) => { + restoredSegment = restoredSegment.replace(v, k); + }); + return restoredSegment; + }); } From d3af3dc83d87810c4fa447bb686cae21db44167f Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Wed, 9 Nov 2016 12:14:15 -0800 Subject: [PATCH 3/3] Use object.entries and object.assign for older environments --- package.json | 1 + src/Utils.js | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3c0b32d2b..5ca08cacf 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "lodash": "^4.16.4", "object-is": "^1.0.1", "object.assign": "^4.0.4", + "object.entries": "^1.0.3", "object.values": "^1.0.3", "uuid": "^2.0.3" }, diff --git a/src/Utils.js b/src/Utils.js index 81e0b96d2..a09439268 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -3,6 +3,8 @@ import isEqual from 'lodash/isEqual'; import React from 'react'; import is from 'object-is'; import uuid from 'uuid'; +import entries from 'object.entries'; +import assign from 'object.assign'; import functionName from 'function.prototype.name'; import { isDOMComponent, @@ -175,7 +177,7 @@ export function splitSelector(selector) { // step 1: make a map of all quoted strings with a uuid const quotedSegments = selector.split(/[^" ]+|("[^"]*")|.*/g) .filter(Boolean) - .reduce((obj, match) => ({ ...obj, [match]: uuid.v4() }), {}); + .reduce((obj, match) => assign({}, obj, { [match]: uuid.v4() }), {}); return selector // step 2: replace all quoted strings with the uuid, so we don't have to properly parse them @@ -185,7 +187,7 @@ export function splitSelector(selector) { // step 4: restore the quoted strings by swapping back the uuid's for the original segments .map((selectorSegment) => { let restoredSegment = selectorSegment; - Object.entries(quotedSegments).forEach(([k, v]) => { + entries(quotedSegments).forEach(([k, v]) => { restoredSegment = restoredSegment.replace(v, k); }); return restoredSegment;