25
}
26
27
beforeEach(() => {
28
+ jest.resetModuleRegistry();
29
React = require('React');
30
ReactDOM = require('ReactDOM');
31
ReactTestUtils = require('ReactTestUtils');
157
return <div>{props.children}</div>;
158
}
159
159
- class Parent extends React.Component {
160
+ class ParentUsingStringRef extends React.Component {
161
render() {
161
- return <Indirection><StatelessComponent name="A" ref="stateless"/></Indirection>;
162
+ return (
163
+ <Indirection>
164
+ <StatelessComponent name="A" ref="stateless" />
165
+ </Indirection>
166
+ );
167
}
168
}
169
165
- ReactTestUtils.renderIntoDocument(<Parent/>);
166
-
170
+ ReactTestUtils.renderIntoDocument(<ParentUsingStringRef />);
171
expectDev(console.error.calls.count()).toBe(1);
172
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
173
'Warning: Stateless function components cannot be given refs. ' +
174
'Attempts to access this ref will fail. Check the render method ' +
171
- 'of `Parent`.\n' +
175
+ 'of `ParentUsingStringRef`.\n' +
176
' in StatelessComponent (at **)\n' +
177
' in div (at **)\n' +
178
' in Indirection (at **)\n' +
175
- ' in Parent (at **)'
179
+ ' in ParentUsingStringRef (at **)'
180
);
181
+
182
+ ReactTestUtils.renderIntoDocument(<ParentUsingStringRef />);
183
+ expectDev(console.error.calls.count()).toBe(1);
184
});
185
186
it('should warn when given a function ref', () => {
187
spyOn(console, 'error');
181
- var ref = jasmine.createSpy().and.callFake((arg) => {
182
- expect(arg).toBe(null);
183
- });
188
189
function Indirection(props) {
190
return <div>{props.children}</div>;
191
}
192
189
- class Parent extends React.Component {
193
+ class ParentUsingFunctionRef extends React.Component {
194
render() {
191
- return <Indirection><StatelessComponent name="A" ref={ref} /></Indirection>;
195
+ return (
196
+ <Indirection>
197
+ <StatelessComponent name="A" ref={(arg) => {
198
+ expect(arg).toBe(null);
199
+ }} />
200
+ </Indirection>
201
+ );
202
}
203
}
204
195
- ReactTestUtils.renderIntoDocument(<Parent/>);
196
-
205
+ ReactTestUtils.renderIntoDocument(<ParentUsingFunctionRef />);
206
expectDev(console.error.calls.count()).toBe(1);
207
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
208
'Warning: Stateless function components cannot be given refs. ' +
209
'Attempts to access this ref will fail. Check the render method ' +
201
- 'of `Parent`.\n' +
210
+ 'of `ParentUsingFunctionRef`.\n' +
211
' in StatelessComponent (at **)\n' +
212
' in div (at **)\n' +
213
' in Indirection (at **)\n' +
205
- ' in Parent (at **)'
214
+ ' in ParentUsingFunctionRef (at **)'
215
+ );
216
+
217
+ ReactTestUtils.renderIntoDocument(<ParentUsingFunctionRef />);
218
+ expectDev(console.error.calls.count()).toBe(1);
219
+ });
220
+
221
+ it('deduplicates ref warnings based on element or owner', () => {
222
+ spyOn(console, 'error');
223
+
224
+ // Prevent the Babel transform adding a displayName.
225
+ var createClassWithoutDisplayName = React.createClass;
226
+
227
+ // When owner uses JSX, we can use exact line location to dedupe warnings
228
+ var AnonymousParentUsingJSX = createClassWithoutDisplayName({
229
+ render() {
230
+ return <StatelessComponent name="A" ref={() => {}} />;
231
+ },
232
+ });
233
+ const instance1 = ReactTestUtils.renderIntoDocument(<AnonymousParentUsingJSX />);
234
+ expectDev(console.error.calls.count()).toBe(1);
235
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
236
+ 'Warning: Stateless function components cannot be given refs.'
237
);
238
+ // Should be deduped (offending element is on the same line):
239
+ instance1.forceUpdate();
240
+ // Should also be deduped (offending element is on the same line):
241
+ ReactTestUtils.renderIntoDocument(<AnonymousParentUsingJSX />);
242
+ expectDev(console.error.calls.count()).toBe(1);
243
+ console.error.calls.reset();
244
+
245
+ // When owner doesn't use JSX, and is anonymous, we warn once per internal instance.
246
+ var AnonymousParentNotUsingJSX = createClassWithoutDisplayName({
247
+ render() {
248
+ return React.createElement(StatelessComponent, {name: 'A', 'ref': () => {}});
249
+ },
250
+ });
251
+ const instance2 = ReactTestUtils.renderIntoDocument(<AnonymousParentNotUsingJSX />);
252
+ expectDev(console.error.calls.count()).toBe(1);
253
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
254
+ 'Warning: Stateless function components cannot be given refs.'
255
+ );
256
+ // Should be deduped (same internal instance):
257
+ instance2.forceUpdate();
258
+ expectDev(console.error.calls.count()).toBe(1);
259
+ // Could not be deduped (different internal instance):
260
+ ReactTestUtils.renderIntoDocument(<AnonymousParentNotUsingJSX />);
261
+ expectDev(console.error.calls.count()).toBe(2);
262
+ expectDev(console.error.calls.argsFor(1)[0]).toContain(
263
+ 'Warning: Stateless function components cannot be given refs.'
264
+ );
265
+ console.error.calls.reset();
266
+
267
+ // When owner doesn't use JSX, but is named, we warn once per owner name
268
+ class NamedParentNotUsingJSX extends React.Component {
269
+ render() {
270
+ return React.createElement(StatelessComponent, {name: 'A', 'ref': () => {}});
271
+ }
272
+ }
273
+ const instance3 = ReactTestUtils.renderIntoDocument(<NamedParentNotUsingJSX />);
274
+ expectDev(console.error.calls.count()).toBe(1);
275
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
276
+ 'Warning: Stateless function components cannot be given refs.'
277
+ );
278
+ // Should be deduped (same owner name):
279
+ instance3.forceUpdate();
280
+ expectDev(console.error.calls.count()).toBe(1);
281
+ // Should also be deduped (same owner name):
282
+ ReactTestUtils.renderIntoDocument(<NamedParentNotUsingJSX />);
283
+ expectDev(console.error.calls.count()).toBe(1);
284
+ console.error.calls.reset();
285
});
286
287
it('should provide a null ref', () => {