From 4dd2780c083559108cf973c96efad334ad264107 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 20 Aug 2018 20:42:19 -0700 Subject: [PATCH 1/4] [Fix] `shallow`: `.parents`: ensure that one `.find` call does not affect another. Fixes #1780. --- .../test/ReactWrapper-spec.jsx | 49 +++++++++++++++++++ .../test/ShallowWrapper-spec.jsx | 49 +++++++++++++++++++ packages/enzyme/src/RSTTraversal.js | 2 +- packages/enzyme/src/ReactWrapper.js | 6 ++- packages/enzyme/src/ShallowWrapper.js | 6 ++- 5 files changed, 107 insertions(+), 5 deletions(-) diff --git a/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx b/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx index d88bd7bed..e3f7e74aa 100644 --- a/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx +++ b/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx @@ -3893,6 +3893,55 @@ describeWithDOM('mount', () => { const formUp = input.parents('form'); expect(formUp).to.have.lengthOf(1); }); + + it('works when called sequentially on two sibling nodes', () => { + class Test extends React.Component { + render() { + return ( +
+
+
A child
+
+
+
B child
+
+
+ ); + } + } + + const wrapper = mount(); + + const aChild = wrapper.find({ children: 'A child' }); + expect(aChild.debug()).to.equal(`
+ A child +
`); + expect(aChild).to.have.lengthOf(1); + + const bChild = wrapper.find({ children: 'B child' }); + expect(bChild.debug()).to.equal(`
+ B child +
`); + expect(bChild).to.have.lengthOf(1); + + /* + const bChildParents = bChild.parents('.b'); + expect(bChildParents.debug()).to.equal(`
+
+ B child +
+
`); + expect(bChildParents).to.have.lengthOf(1); + */ + + const aChildParents = aChild.parents('.a'); + expect(aChildParents.debug()).to.equal(`
+
+ A child +
+
`); + expect(aChildParents).to.have.lengthOf(1); + }); }); describe('.parent()', () => { diff --git a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx index ab4bf9c29..17359a2f6 100644 --- a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx +++ b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx @@ -3556,6 +3556,55 @@ describe('shallow', () => { expect(parents.at(0).hasClass('foo')).to.equal(true); expect(parents.at(1).hasClass('bax')).to.equal(true); }); + + it('works when called sequentially on two sibling nodes', () => { + class Test extends React.Component { + render() { + return ( +
+
+
A child
+
+
+
B child
+
+
+ ); + } + } + + const wrapper = shallow(); + + const aChild = wrapper.find({ children: 'A child' }); + expect(aChild.debug()).to.equal(`
+ A child +
`); + expect(aChild).to.have.lengthOf(1); + + const bChild = wrapper.find({ children: 'B child' }); + expect(bChild.debug()).to.equal(`
+ B child +
`); + expect(bChild).to.have.lengthOf(1); + + /* + const bChildParents = bChild.parents('.b'); + expect(bChildParents.debug()).to.equal(`
+
+ B child +
+
`); + expect(bChildParents).to.have.lengthOf(1); + */ + + const aChildParents = aChild.parents('.a'); + expect(aChildParents.debug()).to.equal(`
+
+ A child +
+
`); + expect(aChildParents).to.have.lengthOf(1); + }); }); describe('.parent()', () => { diff --git a/packages/enzyme/src/RSTTraversal.js b/packages/enzyme/src/RSTTraversal.js index ad2f7a7ab..f3389902e 100644 --- a/packages/enzyme/src/RSTTraversal.js +++ b/packages/enzyme/src/RSTTraversal.js @@ -106,7 +106,7 @@ export function pathToNode(node, root) { } export function parentsOfNode(node, root) { - return pathToNode(node, root).reverse(); + return (pathToNode(node, root) || []).reverse(); } export function nodeHasId(node, id) { diff --git a/packages/enzyme/src/ReactWrapper.js b/packages/enzyme/src/ReactWrapper.js index 1ba5fa831..72479ef48 100644 --- a/packages/enzyme/src/ReactWrapper.js +++ b/packages/enzyme/src/ReactWrapper.js @@ -737,8 +737,10 @@ class ReactWrapper { * @returns {ReactWrapper} */ parents(selector) { - const allParents = this.wrap(this.single('parents', n => nodeParents(this, n))); - return selector ? allParents.filter(selector) : allParents; + return this.single('parents', (n) => { + const allParents = this.wrap(nodeParents(this, n)); + return selector ? allParents.filter(selector) : allParents; + }); } /** diff --git a/packages/enzyme/src/ShallowWrapper.js b/packages/enzyme/src/ShallowWrapper.js index 18a946cdf..b53171963 100644 --- a/packages/enzyme/src/ShallowWrapper.js +++ b/packages/enzyme/src/ShallowWrapper.js @@ -972,8 +972,10 @@ class ShallowWrapper { * @returns {ShallowWrapper} */ parents(selector) { - const allParents = this.wrap(this.single('parents', n => nodeParents(this, n))); - return selector ? allParents.filter(selector) : allParents; + return this.single('parents', (n) => { + const allParents = this.wrap(nodeParents(this, n)); + return selector ? allParents.filter(selector) : allParents; + }); } /** From 2a4f21619b8d8b55b556a59d12095d46b5a4a920 Mon Sep 17 00:00:00 2001 From: jgzuke Date: Sat, 8 Sep 2018 14:05:19 +0800 Subject: [PATCH 2/4] freeze ROOT_NODES --- packages/enzyme/src/ReactWrapper.js | 14 +++++++++++++- packages/enzyme/src/ShallowWrapper.js | 9 +++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/enzyme/src/ReactWrapper.js b/packages/enzyme/src/ReactWrapper.js index 72479ef48..c6953502b 100644 --- a/packages/enzyme/src/ReactWrapper.js +++ b/packages/enzyme/src/ReactWrapper.js @@ -31,6 +31,7 @@ const RENDERER = sym('__renderer__'); const UNRENDERED = sym('__unrendered__'); const ROOT = sym('__root__'); const OPTIONS = sym('__options__'); +const ROOT_NODES = sym('__rootNodes__'); /** * Finds all nodes in the current wrapper nodes' render trees that match the provided predicate @@ -57,8 +58,18 @@ function filterWhereUnwrapped(wrapper, predicate) { return wrapper.wrap(wrapper.getNodesInternal().filter(predicate).filter(Boolean)); } +function getRootNodeInternal(wrapper) { + if (wrapper[ROOT].length !== 1) { + throw new Error('getRootNodeInternal(wrapper) can only be called when wrapper wraps one node'); + } + if (wrapper[ROOT] !== wrapper) { + return wrapper[ROOT_NODES][0]; + } + return wrapper[ROOT][NODE]; +} + function nodeParents(wrapper, node) { - return parentsOfNode(node, wrapper[ROOT].getNodeInternal()); + return parentsOfNode(node, getRootNodeInternal(wrapper)); } function privateSetNodes(wrapper, nodes) { @@ -102,6 +113,7 @@ class ReactWrapper { privateSet(this, RENDERER, root[RENDERER]); privateSet(this, ROOT, root); privateSetNodes(this, nodes); + privateSet(this, ROOT_NODES, root[NODES]); } privateSet(this, OPTIONS, root ? root[OPTIONS] : options); } diff --git a/packages/enzyme/src/ShallowWrapper.js b/packages/enzyme/src/ShallowWrapper.js index b53171963..0b3dad11f 100644 --- a/packages/enzyme/src/ShallowWrapper.js +++ b/packages/enzyme/src/ShallowWrapper.js @@ -37,6 +37,8 @@ const UNRENDERED = sym('__unrendered__'); const ROOT = sym('__root__'); const OPTIONS = sym('__options__'); const SET_STATE = sym('__setState__'); +const ROOT_NODES = sym('__rootNodes__'); + /** * Finds all nodes in the current wrapper nodes' render trees that match the provided predicate * function. @@ -144,6 +146,12 @@ function getRootNode(node) { } function getRootNodeInternal(wrapper) { + if (wrapper[ROOT].length !== 1) { + throw new Error('getRootNodeInternal(wrapper) can only be called when wrapper wraps one node'); + } + if (wrapper[ROOT] !== wrapper) { + return wrapper[ROOT_NODES][0]; + } return wrapper[ROOT][NODE]; } @@ -219,6 +227,7 @@ class ShallowWrapper { privateSet(this, RENDERER, root[RENDERER]); privateSetNodes(this, nodes); privateSet(this, OPTIONS, root[OPTIONS]); + privateSet(this, ROOT_NODES, root[NODES]); } } From a39f9c7274e44fa059ec3f52e2e541b81be09c5f Mon Sep 17 00:00:00 2001 From: jgzuke Date: Sat, 8 Sep 2018 14:34:14 +0800 Subject: [PATCH 3/4] add parent tests --- packages/enzyme-test-suite/test/ReactWrapper-spec.jsx | 2 -- packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx | 2 -- 2 files changed, 4 deletions(-) diff --git a/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx b/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx index e3f7e74aa..29955d4b0 100644 --- a/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx +++ b/packages/enzyme-test-suite/test/ReactWrapper-spec.jsx @@ -3924,7 +3924,6 @@ describeWithDOM('mount', () => { `); expect(bChild).to.have.lengthOf(1); - /* const bChildParents = bChild.parents('.b'); expect(bChildParents.debug()).to.equal(`
@@ -3932,7 +3931,6 @@ describeWithDOM('mount', () => {
`); expect(bChildParents).to.have.lengthOf(1); - */ const aChildParents = aChild.parents('.a'); expect(aChildParents.debug()).to.equal(`
diff --git a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx index 17359a2f6..3a41fb2c0 100644 --- a/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx +++ b/packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx @@ -3587,7 +3587,6 @@ describe('shallow', () => {
`); expect(bChild).to.have.lengthOf(1); - /* const bChildParents = bChild.parents('.b'); expect(bChildParents.debug()).to.equal(`
@@ -3595,7 +3594,6 @@ describe('shallow', () => {
`); expect(bChildParents).to.have.lengthOf(1); - */ const aChildParents = aChild.parents('.a'); expect(aChildParents.debug()).to.equal(`
From 53be3e802dbf2d8a18f34c18576fec4a5f02149f Mon Sep 17 00:00:00 2001 From: jgzuke Date: Wed, 12 Sep 2018 11:22:55 +0800 Subject: [PATCH 4/4] use getRootNodeInternal in ReactWrapper simulateError --- packages/enzyme/src/ReactWrapper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/enzyme/src/ReactWrapper.js b/packages/enzyme/src/ReactWrapper.js index c6953502b..1fe7aa5e0 100644 --- a/packages/enzyme/src/ReactWrapper.js +++ b/packages/enzyme/src/ReactWrapper.js @@ -651,7 +651,7 @@ class ReactWrapper { throw new TypeError('your adapter does not support `simulateError`. Try upgrading it!'); } - const rootNode = this[ROOT].getNodeInternal(); + const rootNode = getRootNodeInternal(this); const nodeHierarchy = [thisNode].concat(nodeParents(this, thisNode)); renderer.simulateError(nodeHierarchy, rootNode, error);