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 = require('React');
15
var ReactTestUtils = require('ReactTestUtils');
16
17
var reactComponentExpect= require('reactComponentExpect');
18
19
20
/**
21
* Counts clicks and has a renders an item for each click. Each item rendered
22
* has a ref of the form "clickLogN".
23
*/
24
var ClickCounter = React.createClass({
25
getInitialState: function() {
26
return {count: this.props.initialCount};
27
},
28
triggerReset: function() {
29
this.setState({count: this.props.initialCount});
30
},
31
handleClick: function() {
32
this.setState({count: this.state.count + 1});
33
},
34
render: function() {
35
var children = [];
36
var i;
37
for (i=0; i < this.state.count; i++) {
38
children.push(
39
<div
40
className="clickLogDiv"
41
key={"clickLog" + i}
42
ref={"clickLog" + i}
43
/>
44
);
45
}
46
return (
47
<span className="clickIncrementer" onClick={this.handleClick}>
48
{children}
49
</span>
50
);
51
}
52
});
53
54
/**
55
* Only purpose is to test that refs are tracked even when applied to a
56
* component that is injected down several layers. Ref systems are difficult to
57
* build in such a way that ownership is maintained in an airtight manner.
58
*/
59
var GeneralContainerComponent = React.createClass({
60
render: function() {
61
return <div>{this.props.children}</div>;
62
}
63
});
64
65
/**
66
* Notice how refs ownership is maintained even when injecting a component
67
* into a different parent.
68
*/
69
var TestRefsComponent = React.createClass({
70
doReset: function() {
71
this.refs.myCounter.triggerReset();
72
},
73
render: function() {
74
return (
75
<div>
76
<div ref="resetDiv" onClick={this.doReset}>
77
Reset Me By Clicking This.
78
</div>
79
<GeneralContainerComponent ref="myContainer">
80
<ClickCounter ref="myCounter" initialCount={1}/>
81
</GeneralContainerComponent>
82
</div>
83
);
84
}
85
});
86
87
/**
88
* Render a TestRefsComponent and ensure that the main refs are wired up.
89
*/
90
var renderTestRefsComponent = function() {
91
var testRefsComponent =
92
ReactTestUtils.renderIntoDocument(<TestRefsComponent />);
93
94
reactComponentExpect(testRefsComponent)
95
.toBeCompositeComponentWithType(TestRefsComponent);
96
97
var generalContainer = testRefsComponent.refs.myContainer;
98
var counter = testRefsComponent.refs.myCounter;
99
100
reactComponentExpect(generalContainer)
101
.toBeCompositeComponentWithType(GeneralContainerComponent);
102
reactComponentExpect(counter)
103
.toBeCompositeComponentWithType(ClickCounter);
104
105
return testRefsComponent;
106
};
107
108
109
var expectClickLogsLengthToBe = function(instance, length) {
110
var clickLogs =
111
ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, 'clickLogDiv');
112
expect(clickLogs.length).toBe(length);
113
expect(Object.keys(instance.refs.myCounter.refs).length).toBe(length);
114
};
115
116
describe('reactiverefs', function() {
117
beforeEach(function() {
118
require('mock-modules').dumpCache();
119
});
120
121
/**
122
* Ensure that for every click log there is a corresponding ref (from the
123
* perspective of the injected ClickCounter component.
124
*/
125
it("Should increase refs with an increase in divs", function() {
126
var testRefsComponent = renderTestRefsComponent();
127
var clickIncrementer =
128
ReactTestUtils.findRenderedDOMComponentWithClass(
129
testRefsComponent,
130
'clickIncrementer'
131
);
132
133
expectClickLogsLengthToBe(testRefsComponent, 1);
134
135
// After clicking the reset, there should still only be one click log ref.
136
ReactTestUtils.Simulate.click(testRefsComponent.refs.resetDiv);
137
expectClickLogsLengthToBe(testRefsComponent, 1);
138
139
// Begin incrementing clicks (and therefore refs).
140
ReactTestUtils.Simulate.click(clickIncrementer);
141
expectClickLogsLengthToBe(testRefsComponent, 2);
142
143
ReactTestUtils.Simulate.click(clickIncrementer);
144
expectClickLogsLengthToBe(testRefsComponent, 3);
145
146
// Now reset again
147
ReactTestUtils.Simulate.click(testRefsComponent.refs.resetDiv);
148
expectClickLogsLengthToBe(testRefsComponent, 1);
149
150
});
151
152
});
153
154
155
156
/**
157
* Tests that when a ref hops around children, we can track that correctly.
158
*/
159
describe('ref swapping', function() {
160
beforeEach(function() {
161
require('mock-modules').dumpCache();
162
});
163
164
var RefHopsAround = React.createClass({
165
getInitialState: function() {
166
return {count: 0};
167
},
168
moveRef: function() {
169
this.setState({ count: this.state.count + 1 });
170
},
171
render: function() {
172
var count = this.state.count;
173
/**
174
* What we have here, is three divs with refs (div1/2/3), but a single
175
* moving cursor ref `hopRef` that "hops" around the three. We'll call the
176
* `moveRef()` function several times and make sure that the hop ref
177
* points to the correct divs.
178
*/
179
return (
180
<div>
181
<div
182
className="first"
183
ref={count % 3 === 0 ? 'hopRef' : 'divOneRef'}
184
/>
185
<div
186
className="second"
187
ref={count % 3 === 1 ? 'hopRef' : 'divTwoRef'}
188
/>
189
<div
190
className="third"
191
ref={count % 3 === 2 ? 'hopRef' : 'divThreeRef'}
192
/>
193
</div>
194
);
195
}
196
});
197
198
it("Allow refs to hop around children correctly", function() {
199
var refHopsAround = ReactTestUtils.renderIntoDocument(<RefHopsAround />);
200
201
var firstDiv =
202
ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'first');
203
var secondDiv =
204
ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'second');
205
var thirdDiv =
206
ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'third');
207
208
expect(refHopsAround.refs.hopRef).toEqual(firstDiv);
209
expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
210
expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
211
212
refHopsAround.moveRef();
213
expect(refHopsAround.refs.divOneRef).toEqual(firstDiv);
214
expect(refHopsAround.refs.hopRef).toEqual(secondDiv);
215
expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
216
217
refHopsAround.moveRef();
218
expect(refHopsAround.refs.divOneRef).toEqual(firstDiv);
219
expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
220
expect(refHopsAround.refs.hopRef).toEqual(thirdDiv);
221
222
/**
223
* Make sure that after the third, we're back to where we started and the
224
* refs are completely restored.
225
*/
226
refHopsAround.moveRef();
227
expect(refHopsAround.refs.hopRef).toEqual(firstDiv);
228
expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
229
expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
230
});
231
232
233
it('always has a value for this.refs', function() {
234
var Component = React.createClass({
235
render: function() {
236
return <div />;
237
}
238
});
239
240
var instance = ReactTestUtils.renderIntoDocument(<Component />);
241
expect(!!instance.refs).toBe(true);
242
});
243
});
244
245
246