The library for web and native user interfaces.
Reduce `ReactInstanceHandles` API Surface Area
Change `ReactInstanceHandles` so that `getFirstCommonAncestorID` and `nextDescendantID` are now private (and documented to be only exposed for unit testing). Also: - Renamed `nextDescendantID` to `getNextDescendantID`. - Renamed `parentID` to `getParentID`. I also organized `ReactInstanceHandles-test` by method names. Functionally, this diff should not change anything.
CommitSyncScript committed
Jun 10, 2013 at 16:16 UTC
ca3f87164634b40678f67d24076ee8f39dddeaa2
2 files changed
+340
-316
src/core/ReactInstanceHandles.js
+94
-85
@@ -82,10 +82,87 @@ function isValidID(id) {
82
* @return {string} ID of the parent, or an empty string.
83
* @private
84
*/
85
-function parentID(id) {
85
+function getParentID(id) {
86
return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : '';
87
}
88
89
+/**
90
+ * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the
91
+ * supplied `destinationID`. If they are equal, the ID is returned.
92
+ *
93
+ * @param {string} ancestorID ID of an ancestor node of `destinationID`.
94
+ * @param {string} destinationID ID of the destination node.
95
+ * @return {string} Next ID on the path from `ancestorID` to `destinationID`.
96
+ * @private
97
+ */
98
+function getNextDescendantID(ancestorID, destinationID) {
99
+ invariant(
100
+ isValidID(ancestorID) && isValidID(destinationID),
101
+ 'getNextDescendantID(%s, %s): Received an invalid React DOM ID.',
102
+ ancestorID,
103
+ destinationID
104
+ );
105
+ var longestCommonID = getFirstCommonAncestorID(
106
+ ancestorID,
107
+ destinationID
108
+ );
109
+ invariant(
110
+ longestCommonID === ancestorID,
111
+ 'getNextDescendantID(...): React has made an invalid assumption about ' +
112
+ 'the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.',
113
+ ancestorID,
114
+ destinationID
115
+ );
116
+ if (ancestorID === destinationID) {
117
+ return ancestorID;
118
+ }
119
+ // Skip over the ancestor and the immediate separator. Traverse until we hit
120
+ // another separator or we reach the end of `destinationID`.
121
+ var start = ancestorID.length + SEPARATOR_LENGTH;
122
+ for (var i = start; i < destinationID.length; i++) {
123
+ if (isMarker(destinationID, i)) {
124
+ break;
125
+ }
126
+ }
127
+ return destinationID.substr(0, i);
128
+}
129
+
130
+/**
131
+ * Gets the nearest common ancestor ID of two IDs.
132
+ *
133
+ * Using this ID scheme, the nearest common ancestor ID is the longest common
134
+ * prefix of the two IDs that immediately preceded a "marker" in both strings.
135
+ *
136
+ * @param {string} oneID
137
+ * @param {string} twoID
138
+ * @return {string} Nearest common ancestor ID, or the empty string if none.
139
+ * @private
140
+ */
141
+function getFirstCommonAncestorID(oneID, twoID) {
142
+ var minLength = Math.min(oneID.length, twoID.length);
143
+ if (minLength === 0) {
144
+ return '';
145
+ }
146
+ var lastCommonMarkerIndex = 0;
147
+ // Use `<=` to traverse until the "EOL" of the shorter string.
148
+ for (var i = 0; i <= minLength; i++) {
149
+ if (isMarker(oneID, i) && isMarker(twoID, i)) {
150
+ lastCommonMarkerIndex = i;
151
+ } else if (oneID.charAt(i) !== twoID.charAt(i)) {
152
+ break;
153
+ }
154
+ }
155
+ var longestCommonID = oneID.substr(0, lastCommonMarkerIndex);
156
+ invariant(
157
+ isValidID(longestCommonID),
158
+ 'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s',
159
+ oneID,
160
+ twoID,
161
+ longestCommonID
162
+ );
163
+ return longestCommonID;
164
+}
165
+
166
/**
167
* Traverses the parent path between two IDs (either up or down). The IDs must
168
* not be the same, and there must exist a parent path between them.
@@ -105,7 +182,7 @@ function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
182
'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.',
183
start
184
);
108
- var ancestorID = ReactInstanceHandles.getFirstCommonAncestorID(start, stop);
185
+ var ancestorID = getFirstCommonAncestorID(start, stop);
186
var traverseUp = ancestorID === stop;
187
invariant(
188
traverseUp || ancestorID === start,
@@ -116,7 +193,7 @@ function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
193
);
194
// Traverse from `start` to `stop` one depth at a time.
195
var depth = 0;
119
- var traverse = traverseUp ? parentID : ReactInstanceHandles.nextDescendantID;
196
+ var traverse = traverseUp ? getParentID : getNextDescendantID;
197
for (var id = start; /* until break */; id = traverse(id, stop)) {
198
if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
199
cb(id, traverseUp, arg);
@@ -208,42 +285,6 @@ var ReactInstanceHandles = {
285
// Effectively: return null;
286
},
287
211
- /**
212
- * Gets the nearest common ancestor ID of two IDs.
213
- *
214
- * Using this ID scheme, the nearest common ancestor ID is the longest common
215
- * prefix of the two IDs that immediately preceded a "marker" in both strings.
216
- *
217
- * @param {string} oneID
218
- * @param {string} twoID
219
- * @return {string} Nearest common ancestor ID, or the empty string if none.
220
- * @internal
221
- */
222
- getFirstCommonAncestorID: function(oneID, twoID) {
223
- var minLength = Math.min(oneID.length, twoID.length);
224
- if (minLength === 0) {
225
- return '';
226
- }
227
- var lastCommonMarkerIndex = 0;
228
- // Use `<=` to traverse until the "EOL" of the shorter string.
229
- for (var i = 0; i <= minLength; i++) {
230
- if (isMarker(oneID, i) && isMarker(twoID, i)) {
231
- lastCommonMarkerIndex = i;
232
- } else if (oneID.charAt(i) !== twoID.charAt(i)) {
233
- break;
234
- }
235
- }
236
- var longestCommonID = oneID.substr(0, lastCommonMarkerIndex);
237
- invariant(
238
- isValidID(longestCommonID),
239
- 'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s',
240
- oneID,
241
- twoID,
242
- longestCommonID
243
- );
244
- return longestCommonID;
245
- },
246
-
288
/**
289
* Gets the DOM ID of the React component that is the root of the tree that
290
* contains the React component with the supplied DOM ID.
@@ -272,15 +313,12 @@ var ReactInstanceHandles = {
313
* @internal
314
*/
315
traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) {
275
- var longestCommonID = ReactInstanceHandles.getFirstCommonAncestorID(
276
- leaveID,
277
- enterID
278
- );
279
- if (longestCommonID !== leaveID) {
280
- traverseParentPath(leaveID, longestCommonID, cb, upArg, false, true);
316
+ var ancestorID = getFirstCommonAncestorID(leaveID, enterID);
317
+ if (ancestorID !== leaveID) {
318
+ traverseParentPath(leaveID, ancestorID, cb, upArg, false, true);
319
}
282
- if (longestCommonID !== enterID) {
283
- traverseParentPath(longestCommonID, enterID, cb, downArg, true, false);
320
+ if (ancestorID !== enterID) {
321
+ traverseParentPath(ancestorID, enterID, cb, downArg, true, false);
322
}
323
},
324
@@ -302,45 +340,16 @@ var ReactInstanceHandles = {
340
},
341
342
/**
305
- * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the
306
- * supplied `destinationID`. If they are equal, the ID is returned.
307
- *
308
- * @param {string} ancestorID ID of an ancestor node of `destinationID`.
309
- * @param {string} destinationID ID of the destination node.
310
- * @return {string} Next ID on the path from `ancestorID` to `destinationID`.
311
- * @internal
343
+ * Exposed for unit testing.
344
+ * @private
345
*/
313
- nextDescendantID: function(ancestorID, destinationID) {
314
- invariant(
315
- isValidID(ancestorID) && isValidID(destinationID),
316
- 'nextDescendantID(%s, %s): Received an invalid React DOM ID.',
317
- ancestorID,
318
- destinationID
319
- );
320
- var longestCommonID = ReactInstanceHandles.getFirstCommonAncestorID(
321
- ancestorID,
322
- destinationID
323
- );
324
- invariant(
325
- longestCommonID === ancestorID,
326
- 'nextDescendantID(...): React has made an invalid assumption about the ' +
327
- 'DOM hierarchy. Expected `%s` to be an ancestor of `%s`.',
328
- ancestorID,
329
- destinationID
330
- );
331
- if (ancestorID === destinationID) {
332
- return ancestorID;
333
- }
334
- // Skip over the ancestor and the immediate separator. Traverse until we hit
335
- // another separator or we reach the end of `destinationID`.
336
- var start = ancestorID.length + SEPARATOR_LENGTH;
337
- for (var i = start; i < destinationID.length; i++) {
338
- if (isMarker(destinationID, i)) {
339
- break;
340
- }
341
- }
342
- return destinationID.substr(0, i);
343
- }
346
+ _getFirstCommonAncestorID: getFirstCommonAncestorID,
347
+
348
+ /**
349
+ * Exposed for unit testing.
350
+ * @private
351
+ */
352
+ _getNextDescendantID: getNextDescendantID
353
354
};
355
src/core/__tests__/ReactInstanceHandles-test.js
+246
-231
@@ -19,12 +19,7 @@
19
20
"use strict";
21
22
-require('mock-modules')
23
- .dontMock('ReactInstanceHandles');
24
-
22
var React = require('React');
26
-var ReactComponent = require('ReactComponent');
27
-var ReactInstanceHandles = require('ReactInstanceHandles');
23
var ReactTestUtils = require('ReactTestUtils');
24
25
var reactComponentExpect= require('reactComponentExpect');
@@ -64,259 +59,279 @@ function renderParentIntoDocument() {
59
return ReactTestUtils.renderIntoDocument(<ParentComponent />);
60
}
61
67
-var aggregatedArgs = [];
68
-function argAggregator(id, isUp, arg) {
69
- aggregatedArgs.push({
70
- id: id,
71
- isUp: isUp,
72
- arg: arg
73
- });
74
-}
62
+describe('ReactInstanceHandles', function() {
63
+ var ReactInstanceHandles;
64
76
-var nextDescendantID;
77
-var traverseTwoPhase;
78
-var traverseEnterLeave;
79
-var getFirstCommonAncestorID;
65
+ var aggregatedArgs;
66
+ function argAggregator(id, isUp, arg) {
67
+ aggregatedArgs.push({
68
+ id: id,
69
+ isUp: isUp,
70
+ arg: arg
71
+ });
72
+ }
73
81
-describe('ReactInstanceHandles traversal', function() {
74
beforeEach(function() {
83
- require('mock-modules').dumpCache();
84
- aggregatedArgs = [];
75
ReactInstanceHandles = require('ReactInstanceHandles');
86
- nextDescendantID = ReactInstanceHandles.nextDescendantID;
87
- getFirstCommonAncestorID = ReactInstanceHandles.getFirstCommonAncestorID;
88
- traverseTwoPhase = ReactInstanceHandles.traverseTwoPhase;
89
- traverseEnterLeave = ReactInstanceHandles.traverseEnterLeave;
76
+ aggregatedArgs = [];
77
});
78
92
- it("should return next descendent from window", function() {
93
- var parent = renderParentIntoDocument();
94
- expect(nextDescendantID('', parent.refs.P_P1._rootNodeID)).toBe(
95
- parent.refs.P._rootNodeID
96
- );
79
+ describe('isRenderedByReact', function() {
80
+ it('should not crash on text nodes', function() {
81
+ expect(function() {
82
+ ReactInstanceHandles.isRenderedByReact(document.createTextNode('yolo'));
83
+ }).not.toThrow();
84
+ });
85
});
86
99
- it("should return window for next descendent towards window", function() {
100
- expect(nextDescendantID('', '')).toBe('');
87
+ describe('getReactRootIDFromNodeID', function() {
88
+ it('should support strings', function() {
89
+ var test = '.reactRoot[s_0_1][0]..[1]';
90
+ var expected = '.reactRoot[s_0_1]';
91
+ var actual = ReactInstanceHandles.getReactRootIDFromNodeID(test);
92
+ expect(actual).toEqual(expected);
93
+ });
94
});
95
103
- it("should return self for next descendent towards self", function() {
104
- var parent = renderParentIntoDocument();
105
- expect(
106
- nextDescendantID(
107
- parent.refs.P_P1._rootNodeID,
108
- parent.refs.P_P1._rootNodeID
109
- )
110
- ).toBe(parent.refs.P_P1._rootNodeID);
111
- });
96
+ describe('traverseTwoPhase', function() {
97
+ it("should not traverse when traversing outside DOM", function() {
98
+ var targetID = '';
99
+ var expectedAggregation = [];
100
+ ReactInstanceHandles.traverseTwoPhase(targetID, argAggregator, ARG);
101
+ expect(aggregatedArgs).toEqual(expectedAggregation);
102
+ });
103
113
- it("should not traverse when traversing outside DOM", function() {
114
- var targetID = '';
115
- var expectedAggregation = [];
116
- traverseTwoPhase(targetID, argAggregator, ARG);
117
- expect(aggregatedArgs).toEqual(expectedAggregation);
118
- });
104
+ it("should traverse two phase across component boundary", function() {
105
+ var parent = renderParentIntoDocument();
106
+ var targetID = parent.refs.P_P1_C1.refs.DIV_1._rootNodeID;
107
+ var expectedAggregation = [
108
+ {id: parent.refs.P._rootNodeID, isUp: false, arg: ARG},
109
+ {id: parent.refs.P_P1._rootNodeID, isUp: false, arg: ARG},
110
+ {id: parent.refs.P_P1_C1.refs.DIV._rootNodeID, isUp: false, arg: ARG},
111
+ {id: parent.refs.P_P1_C1.refs.DIV_1._rootNodeID, isUp: false, arg: ARG},
112
120
- it("should not traverse when enter/leaving outside DOM", function() {
121
- var targetID = '';
122
- var expectedAggregation = [];
123
- traverseEnterLeave(targetID, targetID, argAggregator, ARG, ARG2);
124
- expect(aggregatedArgs).toEqual(expectedAggregation);
125
- });
113
+ {id: parent.refs.P_P1_C1.refs.DIV_1._rootNodeID, isUp: true, arg: ARG},
114
+ {id: parent.refs.P_P1_C1.refs.DIV._rootNodeID, isUp: true, arg: ARG},
115
+ {id: parent.refs.P_P1._rootNodeID, isUp: true, arg: ARG},
116
+ {id: parent.refs.P._rootNodeID, isUp: true, arg: ARG}
117
+ ];
118
+ ReactInstanceHandles.traverseTwoPhase(targetID, argAggregator, ARG);
119
+ expect(aggregatedArgs).toEqual(expectedAggregation);
120
+ });
121
127
- it("should not traverse if enter/leave the same node", function() {
128
- var parent = renderParentIntoDocument();
129
- var leaveID = parent.refs.P_P1_C1.refs.DIV_1._rootNodeID;
130
- var enterID = parent.refs.P_P1_C1.refs.DIV_1._rootNodeID;
131
- var expectedAggregation = [];
132
- traverseEnterLeave(leaveID, enterID, argAggregator, ARG, ARG2);
133
- expect(aggregatedArgs).toEqual(expectedAggregation);
122
+ it("should traverse two phase at shallowest node", function() {
123
+ var parent = renderParentIntoDocument();
124
+ var targetID = parent.refs.P._rootNodeID;
125
+ var expectedAggregation = [
126
+ {id: parent.refs.P._rootNodeID, isUp: false, arg: ARG},
127
+ {id: parent.refs.P._rootNodeID, isUp: true, arg: ARG}
128
+ ];
129
+ ReactInstanceHandles.traverseTwoPhase(targetID, argAggregator, ARG);
130
+ expect(aggregatedArgs).toEqual(expectedAggregation);
131
+ });
132
});
133
136
- it("should traverse two phase across component boundary", function() {
137
- var parent = renderParentIntoDocument();
138
- var targetID = parent.refs.P_P1_C1.refs.DIV_1._rootNodeID;
139
- var expectedAggregation = [
140
- {id: parent.refs.P._rootNodeID, isUp: false, arg: ARG},
141
- {id: parent.refs.P_P1._rootNodeID, isUp: false, arg: ARG},
142
- {id: parent.refs.P_P1_C1.refs.DIV._rootNodeID, isUp: false, arg: ARG},
143
- {id: parent.refs.P_P1_C1.refs.DIV_1._rootNodeID, isUp: false, arg: ARG},
134
+ describe('traverseEnterLeave', function() {
135
+ it("should not traverse when enter/leaving outside DOM", function() {
136
+ var targetID = '';
137
+ var expectedAggregation = [];
138
+ ReactInstanceHandles.traverseEnterLeave(
139
+ targetID, targetID, argAggregator, ARG, ARG2
140
+ );
141
+ expect(aggregatedArgs).toEqual(expectedAggregation);
142
+ });
143
145
- {id: parent.refs.P_P1_C1.refs.DIV_1._rootNodeID, isUp: true, arg: ARG},
146
- {id: parent.refs.P_P1_C1.refs.DIV._rootNodeID, isUp: true, arg: ARG},
147
- {id: parent.refs.P_P1._rootNodeID, isUp: true, arg: ARG},
148
- {id: parent.refs.P._rootNodeID, isUp: true, arg: ARG}
149
- ];
150
- traverseTwoPhase(targetID, argAggregator, ARG);
151
- expect(aggregatedArgs).toEqual(expectedAggregation);
152
- });
144
+ it("should not traverse if enter/leave the same node", function() {
145
+ var parent = renderParentIntoDocument();
146
+ var leaveID = parent.refs.P_P1_C1.refs.DIV_1._rootNodeID;
147
+ var enterID = parent.refs.P_P1_C1.refs.DIV_1._rootNodeID;
148
+ var expectedAggregation = [];
149
+ ReactInstanceHandles.traverseEnterLeave(
150
+ leaveID, enterID, argAggregator, ARG, ARG2
151
+ );
152
+ expect(aggregatedArgs).toEqual(expectedAggregation);
153
+ });
154
154
- it("should traverse two phase at shallowest node", function() {
155
- var parent = renderParentIntoDocument();
156
- var targetID = parent.refs.P._rootNodeID;
157
- var expectedAggregation = [
158
- {id: parent.refs.P._rootNodeID, isUp: false, arg: ARG},
159
- {id: parent.refs.P._rootNodeID, isUp: true, arg: ARG}
160
- ];
161
- traverseTwoPhase(targetID, argAggregator, ARG);
162
- expect(aggregatedArgs).toEqual(expectedAggregation);
163
- });
155
+ it("should traverse enter/leave to sibling - avoids parent", function() {
156
+ var parent = renderParentIntoDocument();
157
+ var leaveID = parent.refs.P_P1_C1.refs.DIV_1._rootNodeID;
158
+ var enterID = parent.refs.P_P1_C1.refs.DIV_2._rootNodeID;
159
+ var expectedAggregation = [
160
+ {id: parent.refs.P_P1_C1.refs.DIV_1._rootNodeID, isUp: true, arg: ARG},
161
+ // enter/leave shouldn't fire antyhing on the parent
162
+ {id: parent.refs.P_P1_C1.refs.DIV_2._rootNodeID, isUp: false, arg: ARG2}
163
+ ];
164
+ ReactInstanceHandles.traverseEnterLeave(
165
+ leaveID, enterID, argAggregator, ARG, ARG2
166
+ );
167
+ expect(aggregatedArgs).toEqual(expectedAggregation);
168
+ });
169
165
- it("should traverse enter/leave to sibling - avoids parent", function() {
166
- var parent = renderParentIntoDocument();
167
- var leaveID = parent.refs.P_P1_C1.refs.DIV_1._rootNodeID;
168
- var enterID = parent.refs.P_P1_C1.refs.DIV_2._rootNodeID;
169
- var expectedAggregation = [
170
- {id: parent.refs.P_P1_C1.refs.DIV_1._rootNodeID, isUp: true, arg: ARG},
171
- // enter/leave shouldn't fire antyhing on the parent
172
- {id: parent.refs.P_P1_C1.refs.DIV_2._rootNodeID, isUp: false, arg: ARG2}
173
- ];
174
- traverseEnterLeave(leaveID, enterID, argAggregator, ARG, ARG2);
175
- expect(aggregatedArgs).toEqual(expectedAggregation);
176
- });
170
+ it("should traverse enter/leave to parent - avoids parent", function() {
171
+ var parent = renderParentIntoDocument();
172
+ var leaveID = parent.refs.P_P1_C1.refs.DIV_1._rootNodeID;
173
+ var enterID = parent.refs.P_P1_C1.refs.DIV._rootNodeID;
174
+ var expectedAggregation = [
175
+ {id: parent.refs.P_P1_C1.refs.DIV_1._rootNodeID, isUp: true, arg: ARG}
176
+ ];
177
+ ReactInstanceHandles.traverseEnterLeave(
178
+ leaveID, enterID, argAggregator, ARG, ARG2
179
+ );
180
+ expect(aggregatedArgs).toEqual(expectedAggregation);
181
+ });
182
178
- it("should traverse enter/leave to parent - avoids parent", function() {
179
- var parent = renderParentIntoDocument();
180
- var leaveID = parent.refs.P_P1_C1.refs.DIV_1._rootNodeID;
181
- var enterID = parent.refs.P_P1_C1.refs.DIV._rootNodeID;
182
- var expectedAggregation = [
183
- {id: parent.refs.P_P1_C1.refs.DIV_1._rootNodeID, isUp: true, arg: ARG}
184
- ];
185
- traverseEnterLeave(leaveID, enterID, argAggregator, ARG, ARG2);
186
- expect(aggregatedArgs).toEqual(expectedAggregation);
187
- });
183
+ it("should enter from the window", function() {
184
+ var parent = renderParentIntoDocument();
185
+ var leaveID = ''; // From the window or outside of the React sandbox.
186
+ var enterID = parent.refs.P_P1_C1.refs.DIV._rootNodeID;
187
+ var expectedAggregation = [
188
+ {id: parent.refs.P._rootNodeID, isUp: false, arg: ARG2},
189
+ {id: parent.refs.P_P1._rootNodeID, isUp: false, arg: ARG2},
190
+ {id: parent.refs.P_P1_C1.refs.DIV._rootNodeID, isUp: false, arg: ARG2}
191
+ ];
192
+ ReactInstanceHandles.traverseEnterLeave(
193
+ leaveID, enterID, argAggregator, ARG, ARG2
194
+ );
195
+ expect(aggregatedArgs).toEqual(expectedAggregation);
196
+ });
197
189
- it("should enter from the window", function() {
190
- var parent = renderParentIntoDocument();
191
- var leaveID = ''; // From the window or outside of the React sandbox.
192
- var enterID = parent.refs.P_P1_C1.refs.DIV._rootNodeID;
193
- var expectedAggregation = [
194
- {id: parent.refs.P._rootNodeID, isUp: false, arg: ARG2},
195
- {id: parent.refs.P_P1._rootNodeID, isUp: false, arg: ARG2},
196
- {id: parent.refs.P_P1_C1.refs.DIV._rootNodeID, isUp: false, arg: ARG2}
197
- ];
198
- traverseEnterLeave(leaveID, enterID, argAggregator, ARG, ARG2);
199
- expect(aggregatedArgs).toEqual(expectedAggregation);
200
- });
198
+ it("should enter from the window to the shallowest", function() {
199
+ var parent = renderParentIntoDocument();
200
+ var leaveID = ''; // From the window or outside of the React sandbox.
201
+ var enterID = parent.refs.P._rootNodeID;
202
+ var expectedAggregation = [
203
+ {id: parent.refs.P._rootNodeID, isUp: false, arg: ARG2}
204
+ ];
205
+ ReactInstanceHandles.traverseEnterLeave(
206
+ leaveID, enterID, argAggregator, ARG, ARG2
207
+ );
208
+ expect(aggregatedArgs).toEqual(expectedAggregation);
209
+ });
210
202
- it("should enter from the window to the shallowest", function() {
203
- var parent = renderParentIntoDocument();
204
- var leaveID = ''; // From the window or outside of the React sandbox.
205
- var enterID = parent.refs.P._rootNodeID;
206
- var expectedAggregation = [
207
- {id: parent.refs.P._rootNodeID, isUp: false, arg: ARG2}
208
- ];
209
- traverseEnterLeave(leaveID, enterID, argAggregator, ARG, ARG2);
210
- expect(aggregatedArgs).toEqual(expectedAggregation);
211
- });
211
+ it("should leave to the window", function() {
212
+ var parent = renderParentIntoDocument();
213
+ var enterID = ''; // From the window or outside of the React sandbox.
214
+ var leaveID = parent.refs.P_P1_C1.refs.DIV._rootNodeID;
215
+ var expectedAggregation = [
216
+ {id: parent.refs.P_P1_C1.refs.DIV._rootNodeID, isUp: true, arg: ARG},
217
+ {id: parent.refs.P_P1._rootNodeID, isUp: true, arg: ARG},
218
+ {id: parent.refs.P._rootNodeID, isUp: true, arg: ARG}
219
+ ];
220
+ ReactInstanceHandles.traverseEnterLeave(
221
+ leaveID, enterID, argAggregator, ARG, ARG2
222
+ );
223
+ expect(aggregatedArgs).toEqual(expectedAggregation);
224
+ });
225
213
- it("should leave to the window", function() {
214
- var parent = renderParentIntoDocument();
215
- var enterID = ''; // From the window or outside of the React sandbox.
216
- var leaveID = parent.refs.P_P1_C1.refs.DIV._rootNodeID;
217
- var expectedAggregation = [
218
- {id: parent.refs.P_P1_C1.refs.DIV._rootNodeID, isUp: true, arg: ARG},
219
- {id: parent.refs.P_P1._rootNodeID, isUp: true, arg: ARG},
220
- {id: parent.refs.P._rootNodeID, isUp: true, arg: ARG}
221
- ];
222
- traverseEnterLeave(leaveID, enterID, argAggregator, ARG, ARG2);
223
- expect(aggregatedArgs).toEqual(expectedAggregation);
226
+ it("should leave to the window from the shallowest", function() {
227
+ var parent = renderParentIntoDocument();
228
+ var enterID = ''; // From the window or outside of the React sandbox.
229
+ var leaveID = parent.refs.P_P1_C1.refs.DIV._rootNodeID;
230
+ var expectedAggregation = [
231
+ {id: parent.refs.P_P1_C1.refs.DIV._rootNodeID, isUp: true, arg: ARG},
232
+ {id: parent.refs.P_P1._rootNodeID, isUp: true, arg: ARG},
233
+ {id: parent.refs.P._rootNodeID, isUp: true, arg: ARG}
234
+ ];
235
+ ReactInstanceHandles.traverseEnterLeave(
236
+ leaveID, enterID, argAggregator, ARG, ARG2
237
+ );
238
+ expect(aggregatedArgs).toEqual(expectedAggregation);
239
+ });
240
});
241
226
- it("should leave to the window from the shallowest", function() {
227
- var parent = renderParentIntoDocument();
228
- var enterID = ''; // From the window or outside of the React sandbox.
229
- var leaveID = parent.refs.P_P1_C1.refs.DIV._rootNodeID;
230
- var expectedAggregation = [
231
- {id: parent.refs.P_P1_C1.refs.DIV._rootNodeID, isUp: true, arg: ARG},
232
- {id: parent.refs.P_P1._rootNodeID, isUp: true, arg: ARG},
233
- {id: parent.refs.P._rootNodeID, isUp: true, arg: ARG}
234
- ];
235
- traverseEnterLeave(leaveID, enterID, argAggregator, ARG, ARG2);
236
- expect(aggregatedArgs).toEqual(expectedAggregation);
237
- });
242
+ describe('getNextDescendantID', function() {
243
+ it("should return next descendent from window", function() {
244
+ var parent = renderParentIntoDocument();
245
+ expect(
246
+ ReactInstanceHandles._getNextDescendantID(
247
+ '',
248
+ parent.refs.P_P1._rootNodeID
249
+ )
250
+ ).toBe(parent.refs.P._rootNodeID);
251
+ });
252
239
- it("should determine the first common ancestor correctly", function() {
240
- var parent = renderParentIntoDocument();
241
- var ancestors = [
242
- // Common ancestor from window to deep element is ''.
243
- { one: {_rootNodeID: ''},
244
- two: parent.refs.P_P1_C1.refs.DIV_1,
245
- com: {_rootNodeID: ''}
246
- },
247
- // Same as previous - reversed direction.
248
- { one: parent.refs.P_P1_C1.refs.DIV_1,
249
- two: {_rootNodeID: ''},
250
- com: {_rootNodeID: ''}
251
- },
252
- // Common ancestor from window to shallow id is ''.
253
- { one: parent.refs.P,
254
- two: {_rootNodeID: ''},
255
- com: {_rootNodeID: ''}
256
- },
257
- // Common ancestor with self is self.
258
- { one: parent.refs.P_P1_C1.refs.DIV_1,
259
- two: parent.refs.P_P1_C1.refs.DIV_1,
260
- com: parent.refs.P_P1_C1.refs.DIV_1
261
- },
262
- // Common ancestor with self is self - even if topmost DOM.
263
- { one: parent.refs.P, two: parent.refs.P, com: parent.refs.P },
264
- // Siblings
265
- {
266
- one: parent.refs.P_P1_C1.refs.DIV_1,
267
- two: parent.refs.P_P1_C1.refs.DIV_2,
268
- com: parent.refs.P_P1_C1.refs.DIV
269
- },
270
- // Common ancestor with parent is the parent.
271
- {
272
- one: parent.refs.P_P1_C1.refs.DIV_1,
273
- two: parent.refs.P_P1_C1.refs.DIV,
274
- com: parent.refs.P_P1_C1.refs.DIV
275
- },
276
- // Common ancestor with grandparent is the grandparent.
277
- {
278
- one: parent.refs.P_P1_C1.refs.DIV_1,
279
- two: parent.refs.P_P1_C1,
280
- com: parent.refs.P_P1_C1
281
- },
282
- // Grantparent across subcomponent boundaries.
283
- {
284
- one: parent.refs.P_P1_C1.refs.DIV_1,
285
- two: parent.refs.P_P1_C2.refs.DIV_1,
286
- com: parent.refs.P_P1
287
- },
288
- // Something deep with something one-off.
289
- {
290
- one: parent.refs.P_P1_C1.refs.DIV_1,
291
- two: parent.refs.P_OneOff,
292
- com: parent.refs.P
293
- }
294
- ];
295
- var i;
296
- for (i = 0; i < ancestors.length; i++) {
297
- var plan = ancestors[i];
298
- var firstCommon = getFirstCommonAncestorID(
299
- plan.one._rootNodeID,
300
- plan.two._rootNodeID
301
- );
302
- expect(firstCommon).toBe(plan.com._rootNodeID);
303
- }
304
- });
305
-});
253
+ it("should return window for next descendent towards window", function() {
254
+ expect(ReactInstanceHandles._getNextDescendantID('', '')).toBe('');
255
+ });
256
307
-describe('ReactInstanceHandles.getReactRootIDFromNodeID', function() {
308
- it('should support strings', function() {
309
- var test = '.reactRoot[s_0_1][0]..[1]';
310
- var expected = '.reactRoot[s_0_1]';
311
- var actual = ReactInstanceHandles.getReactRootIDFromNodeID(test);
312
- expect(actual).toEqual(expected);
257
+ it("should return self for next descendent towards self", function() {
258
+ var parent = renderParentIntoDocument();
259
+ expect(
260
+ ReactInstanceHandles._getNextDescendantID(
261
+ parent.refs.P_P1._rootNodeID,
262
+ parent.refs.P_P1._rootNodeID
263
+ )
264
+ ).toBe(parent.refs.P_P1._rootNodeID);
265
+ });
266
});
314
-});
267
316
-describe('ReactInstanceHandles.isRenderedByReact', function() {
317
- it('should not crash on text nodes', function() {
318
- expect(function() {
319
- ReactInstanceHandles.isRenderedByReact(document.createTextNode('yolo'))
320
- }).not.toThrow();
268
+ describe('getFirstCommonAncestorID', function() {
269
+ it("should determine the first common ancestor correctly", function() {
270
+ var parent = renderParentIntoDocument();
271
+ var ancestors = [
272
+ // Common ancestor from window to deep element is ''.
273
+ { one: {_rootNodeID: ''},
274
+ two: parent.refs.P_P1_C1.refs.DIV_1,
275
+ com: {_rootNodeID: ''}
276
+ },
277
+ // Same as previous - reversed direction.
278
+ { one: parent.refs.P_P1_C1.refs.DIV_1,
279
+ two: {_rootNodeID: ''},
280
+ com: {_rootNodeID: ''}
281
+ },
282
+ // Common ancestor from window to shallow id is ''.
283
+ { one: parent.refs.P,
284
+ two: {_rootNodeID: ''},
285
+ com: {_rootNodeID: ''}
286
+ },
287
+ // Common ancestor with self is self.
288
+ { one: parent.refs.P_P1_C1.refs.DIV_1,
289
+ two: parent.refs.P_P1_C1.refs.DIV_1,
290
+ com: parent.refs.P_P1_C1.refs.DIV_1
291
+ },
292
+ // Common ancestor with self is self - even if topmost DOM.
293
+ { one: parent.refs.P, two: parent.refs.P, com: parent.refs.P },
294
+ // Siblings
295
+ {
296
+ one: parent.refs.P_P1_C1.refs.DIV_1,
297
+ two: parent.refs.P_P1_C1.refs.DIV_2,
298
+ com: parent.refs.P_P1_C1.refs.DIV
299
+ },
300
+ // Common ancestor with parent is the parent.
301
+ {
302
+ one: parent.refs.P_P1_C1.refs.DIV_1,
303
+ two: parent.refs.P_P1_C1.refs.DIV,
304
+ com: parent.refs.P_P1_C1.refs.DIV
305
+ },
306
+ // Common ancestor with grandparent is the grandparent.
307
+ {
308
+ one: parent.refs.P_P1_C1.refs.DIV_1,
309
+ two: parent.refs.P_P1_C1,
310
+ com: parent.refs.P_P1_C1
311
+ },
312
+ // Grantparent across subcomponent boundaries.
313
+ {
314
+ one: parent.refs.P_P1_C1.refs.DIV_1,
315
+ two: parent.refs.P_P1_C2.refs.DIV_1,
316
+ com: parent.refs.P_P1
317
+ },
318
+ // Something deep with something one-off.
319
+ {
320
+ one: parent.refs.P_P1_C1.refs.DIV_1,
321
+ two: parent.refs.P_OneOff,
322
+ com: parent.refs.P
323
+ }
324
+ ];
325
+ var i;
326
+ for (i = 0; i < ancestors.length; i++) {
327
+ var plan = ancestors[i];
328
+ var firstCommon = ReactInstanceHandles._getFirstCommonAncestorID(
329
+ plan.one._rootNodeID,
330
+ plan.two._rootNodeID
331
+ );
332
+ expect(firstCommon).toBe(plan.com._rootNodeID);
333
+ }
334
+ });
335
});
336
+
337
});