Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81155 views
1
/**
2
* Copyright 2013-2014, Facebook, Inc.
3
* All rights reserved.
4
*
5
* This source code is licensed under the BSD-style license found in the
6
* LICENSE file in the root directory of this source tree. An additional grant
7
* of patent rights can be found in the PATENTS file in the same directory.
8
*
9
* @emails react-core
10
*/
11
12
"use strict";
13
14
var React;
15
var ReactTestUtils;
16
var reactComponentExpect;
17
var ReactMount;
18
19
describe('ReactIdentity', function() {
20
21
beforeEach(function() {
22
require('mock-modules').dumpCache();
23
React = require('React');
24
ReactTestUtils = require('ReactTestUtils');
25
reactComponentExpect = require('reactComponentExpect');
26
ReactMount = require('ReactMount');
27
});
28
29
var idExp = /^\.[^.]+(.*)$/;
30
function checkId(child, expectedId) {
31
var actual = idExp.exec(ReactMount.getID(child));
32
var expected = idExp.exec(expectedId);
33
expect(actual).toBeTruthy();
34
expect(expected).toBeTruthy();
35
expect(actual[1]).toEqual(expected[1]);
36
}
37
38
it('should allow keyed objects to express identity', function() {
39
var instance =
40
<div>
41
{{
42
first: <div />,
43
second: <div />
44
}}
45
</div>;
46
47
instance = React.render(instance, document.createElement('div'));
48
var node = instance.getDOMNode();
49
reactComponentExpect(instance).toBeDOMComponentWithChildCount(2);
50
checkId(node.childNodes[0], '.0.$first:0');
51
checkId(node.childNodes[1], '.0.$second:0');
52
});
53
54
it('should allow key property to express identity', function() {
55
var instance =
56
<div>
57
<div key="apple" />
58
<div key="banana" />
59
<div key={0} />
60
<div key={123} />
61
</div>;
62
63
instance = React.render(instance, document.createElement('div'));
64
var node = instance.getDOMNode();
65
reactComponentExpect(instance).toBeDOMComponentWithChildCount(4);
66
checkId(node.childNodes[0], '.0.$apple');
67
checkId(node.childNodes[1], '.0.$banana');
68
checkId(node.childNodes[2], '.0.$0');
69
checkId(node.childNodes[3], '.0.$123');
70
});
71
72
it('should use instance identity', function() {
73
74
var Wrapper = React.createClass({
75
render: function() {
76
return <a key="i_get_overwritten">{this.props.children}</a>;
77
}
78
});
79
80
var instance =
81
<div>
82
<Wrapper key="wrap1"><span key="squirrel" /></Wrapper>
83
<Wrapper key="wrap2"><span key="bunny" /></Wrapper>
84
<Wrapper><span key="chipmunk" /></Wrapper>
85
</div>;
86
87
instance = React.render(instance, document.createElement('div'));
88
var node = instance.getDOMNode();
89
reactComponentExpect(instance).toBeDOMComponentWithChildCount(3);
90
91
checkId(node.childNodes[0], '.0.$wrap1');
92
checkId(node.childNodes[0].firstChild, '.0.$wrap1.$squirrel');
93
checkId(node.childNodes[1], '.0.$wrap2');
94
checkId(node.childNodes[1].firstChild, '.0.$wrap2.$bunny');
95
checkId(node.childNodes[2], '.0.2');
96
checkId(node.childNodes[2].firstChild, '.0.2.$chipmunk');
97
});
98
99
function renderAComponentWithKeyIntoContainer(key, container) {
100
101
var Wrapper = React.createClass({
102
103
render: function() {
104
var span1 = <span ref="span1" key={key} />;
105
var span2 = <span ref="span2" />;
106
107
var map = {};
108
map[key] = span2;
109
return <div>{[span1, map]}</div>;
110
}
111
112
});
113
114
var instance = React.render(<Wrapper />, container);
115
var span1 = instance.refs.span1;
116
var span2 = instance.refs.span2;
117
118
expect(span1.getDOMNode()).not.toBe(null);
119
expect(span2.getDOMNode()).not.toBe(null);
120
121
key = key.replace(/=/g, '=0');
122
123
checkId(span1.getDOMNode(), '.0.$' + key);
124
checkId(span2.getDOMNode(), '.0.1:$' + key + ':0');
125
}
126
127
it('should allow any character as a key, in a detached parent', function() {
128
var detachedContainer = document.createElement('div');
129
renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", detachedContainer);
130
});
131
132
it('should allow any character as a key, in an attached parent', function() {
133
// This test exists to protect against implementation details that
134
// incorrectly query escaped IDs using DOM tools like getElementById.
135
var attachedContainer = document.createElement('div');
136
document.body.appendChild(attachedContainer);
137
138
renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", attachedContainer);
139
140
document.body.removeChild(attachedContainer);
141
});
142
143
it('should not allow scripts in keys to execute', function() {
144
var h4x0rKey =
145
'"><script>window[\'YOUVEBEENH4X0RED\']=true;</script><div id="';
146
147
var attachedContainer = document.createElement('div');
148
document.body.appendChild(attachedContainer);
149
150
renderAComponentWithKeyIntoContainer(h4x0rKey, attachedContainer);
151
152
document.body.removeChild(attachedContainer);
153
154
// If we get this far, make sure we haven't executed the code
155
expect(window.YOUVEBEENH4X0RED).toBe(undefined);
156
});
157
158
it('should let restructured components retain their uniqueness', function() {
159
var instance0 = <span />;
160
var instance1 = <span />;
161
var instance2 = <span />;
162
163
var TestComponent = React.createClass({
164
render: function() {
165
return (
166
<div>
167
{instance2}
168
{this.props.children[0]}
169
{this.props.children[1]}
170
</div>
171
);
172
}
173
});
174
175
var TestContainer = React.createClass({
176
177
render: function() {
178
return <TestComponent>{instance0}{instance1}</TestComponent>;
179
}
180
181
});
182
183
expect(function() {
184
185
React.render(<TestContainer />, document.createElement('div'));
186
187
}).not.toThrow();
188
});
189
190
it('should let nested restructures retain their uniqueness', function() {
191
var instance0 = <span />;
192
var instance1 = <span />;
193
var instance2 = <span />;
194
195
var TestComponent = React.createClass({
196
render: function() {
197
return (
198
<div>
199
{instance2}
200
{this.props.children[0]}
201
{this.props.children[1]}
202
</div>
203
);
204
}
205
});
206
207
var TestContainer = React.createClass({
208
209
render: function() {
210
return (
211
<div>
212
<TestComponent>{instance0}{instance1}</TestComponent>
213
</div>
214
);
215
}
216
217
});
218
219
expect(function() {
220
221
React.render(<TestContainer />, document.createElement('div'));
222
223
}).not.toThrow();
224
});
225
226
it('should let text nodes retain their uniqueness', function() {
227
var TestComponent = React.createClass({
228
render: function() {
229
return <div>{this.props.children}<span /></div>;
230
}
231
});
232
233
var TestContainer = React.createClass({
234
235
render: function() {
236
return (
237
<TestComponent>
238
<div />
239
{'second'}
240
</TestComponent>
241
);
242
}
243
244
});
245
246
expect(function() {
247
248
React.render(<TestContainer />, document.createElement('div'));
249
250
}).not.toThrow();
251
});
252
253
it('should retain key during updates in composite components', function() {
254
255
var TestComponent = React.createClass({
256
render: function() {
257
return <div>{this.props.children}</div>;
258
}
259
});
260
261
var TestContainer = React.createClass({
262
263
getInitialState: function() {
264
return { swapped: false };
265
},
266
267
swap: function() {
268
this.setState({ swapped: true });
269
},
270
271
render: function() {
272
return (
273
<TestComponent>
274
{this.state.swapped ? this.props.second : this.props.first}
275
{this.state.swapped ? this.props.first : this.props.second}
276
</TestComponent>
277
);
278
}
279
280
});
281
282
var instance0 = <span key="A" />;
283
var instance1 = <span key="B" />;
284
285
var wrapped = <TestContainer first={instance0} second={instance1} />;
286
287
wrapped = React.render(wrapped, document.createElement('div'));
288
289
var beforeID = ReactMount.getID(wrapped.getDOMNode().firstChild);
290
291
wrapped.swap();
292
293
var afterID = ReactMount.getID(wrapped.getDOMNode().firstChild);
294
295
expect(beforeID).not.toEqual(afterID);
296
297
});
298
299
it('should not allow implicit and explicit keys to collide', function() {
300
var component =
301
<div>
302
<span />
303
<span key="0" />
304
</div>;
305
306
expect(function() {
307
React.render(component, document.createElement('div'));
308
}).not.toThrow();
309
});
310
311
312
});
313
314