@samitouri / QOS-React-2 / commits / ce489262a1

Add react-create-class integration tests

These are mostly copied from the old ReactClass-test module.

Andrew Clark committed Mar 27, 2017 at 16:34 UTC ce489262a1ee34340440e55a0b99ea6918e19e7a
3 files changed +460
scripts/fiber/tests-passing.txt
+18
@@ -90,6 +90,24 @@ src/isomorphic/classic/__tests__/ReactContextValidator-test.js
90 * should warn (but not error) if getChildContext method is missing
91 * should pass parent context if getChildContext method is missing
92
93 +src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js
94 +* should throw when `render` is not specified
95 +* should copy prop types onto the Constructor
96 +* should warn on invalid prop types
97 +* should warn on invalid context types
98 +* should throw on invalid child context types
99 +* should warn when mispelling shouldComponentUpdate
100 +* should warn when mispelling componentWillReceiveProps
101 +* should throw if a reserved property is in statics
102 +* should support statics
103 +* should work with object getInitialState() return values
104 +* renders based on context getInitialState
105 +* should throw with non-object getInitialState() return values
106 +* should work with a null getInitialState() return value
107 +* should throw when using legacy factories
108 +* replaceState and callback works
109 +* isMounted works
110 +
111 src/isomorphic/classic/element/__tests__/ReactElement-test.js
112 * uses the fallback value when in an environment without Symbol
113 * returns a complete element according to spec
src/isomorphic/classic/class/__tests__/react-create-class-integration-test.js new
+436
@@ -0,0 +1,436 @@
1 +/**
2 + * Copyright 2013-present, 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 ReactDOM;
16 +var ReactTestUtils;
17 +var ReactCreateClass;
18 +
19 +describe('react-create-class-integration', () => {
20 + beforeEach(() => {
21 + React = require('React');
22 + ReactDOM = require('ReactDOM');
23 + ReactTestUtils = require('ReactTestUtils');
24 + var ReactCreateClassFactory = require('react-create-class/factory');
25 + ReactCreateClass = ReactCreateClassFactory(
26 + React.Component,
27 + React.isValidElement,
28 + require('ReactNoopUpdateQueue'),
29 + );
30 + });
31 +
32 + it('should throw when `render` is not specified', () => {
33 + expect(function() {
34 + ReactCreateClass({});
35 + }).toThrowError(
36 + 'createClass(...): Class specification must implement a `render` method.',
37 + );
38 + });
39 +
40 + // TODO: Update babel-plugin-transform-react-display-name
41 + xit('should copy `displayName` onto the Constructor', () => {
42 + var TestComponent = ReactCreateClass({
43 + render: function() {
44 + return <div />;
45 + },
46 + });
47 +
48 + expect(TestComponent.displayName).toBe('TestComponent');
49 + });
50 +
51 + it('should copy prop types onto the Constructor', () => {
52 + var propValidator = jest.fn();
53 + var TestComponent = ReactCreateClass({
54 + propTypes: {
55 + value: propValidator,
56 + },
57 + render: function() {
58 + return <div />;
59 + },
60 + });
61 +
62 + expect(TestComponent.propTypes).toBeDefined();
63 + expect(TestComponent.propTypes.value).toBe(propValidator);
64 + });
65 +
66 + it('should warn on invalid prop types', () => {
67 + spyOn(console, 'error');
68 + ReactCreateClass({
69 + displayName: 'Component',
70 + propTypes: {
71 + prop: null,
72 + },
73 + render: function() {
74 + return <span>{this.props.prop}</span>;
75 + },
76 + });
77 + expect(console.error.calls.count()).toBe(1);
78 + expect(console.error.calls.argsFor(0)[0]).toBe(
79 + 'Warning: Component: prop type `prop` is invalid; ' +
80 + 'it must be a function, usually from React.PropTypes.',
81 + );
82 + });
83 +
84 + it('should warn on invalid context types', () => {
85 + spyOn(console, 'error');
86 + ReactCreateClass({
87 + displayName: 'Component',
88 + contextTypes: {
89 + prop: null,
90 + },
91 + render: function() {
92 + return <span>{this.props.prop}</span>;
93 + },
94 + });
95 + expect(console.error.calls.count()).toBe(1);
96 + expect(console.error.calls.argsFor(0)[0]).toBe(
97 + 'Warning: Component: context type `prop` is invalid; ' +
98 + 'it must be a function, usually from React.PropTypes.',
99 + );
100 + });
101 +
102 + it('should throw on invalid child context types', () => {
103 + spyOn(console, 'error');
104 + ReactCreateClass({
105 + displayName: 'Component',
106 + childContextTypes: {
107 + prop: null,
108 + },
109 + render: function() {
110 + return <span>{this.props.prop}</span>;
111 + },
112 + });
113 + expect(console.error.calls.count()).toBe(1);
114 + expect(console.error.calls.argsFor(0)[0]).toBe(
115 + 'Warning: Component: child context type `prop` is invalid; ' +
116 + 'it must be a function, usually from React.PropTypes.',
117 + );
118 + });
119 +
120 + it('should warn when mispelling shouldComponentUpdate', () => {
121 + spyOn(console, 'error');
122 +
123 + ReactCreateClass({
124 + componentShouldUpdate: function() {
125 + return false;
126 + },
127 + render: function() {
128 + return <div />;
129 + },
130 + });
131 + expect(console.error.calls.count()).toBe(1);
132 + expect(console.error.calls.argsFor(0)[0]).toBe(
133 + 'Warning: A component has a method called componentShouldUpdate(). Did you ' +
134 + 'mean shouldComponentUpdate()? The name is phrased as a question ' +
135 + 'because the function is expected to return a value.',
136 + );
137 +
138 + ReactCreateClass({
139 + displayName: 'NamedComponent',
140 + componentShouldUpdate: function() {
141 + return false;
142 + },
143 + render: function() {
144 + return <div />;
145 + },
146 + });
147 + expect(console.error.calls.count()).toBe(2);
148 + expect(console.error.calls.argsFor(1)[0]).toBe(
149 + 'Warning: NamedComponent has a method called componentShouldUpdate(). Did you ' +
150 + 'mean shouldComponentUpdate()? The name is phrased as a question ' +
151 + 'because the function is expected to return a value.',
152 + );
153 + });
154 +
155 + it('should warn when mispelling componentWillReceiveProps', () => {
156 + spyOn(console, 'error');
157 + ReactCreateClass({
158 + componentWillRecieveProps: function() {
159 + return false;
160 + },
161 + render: function() {
162 + return <div />;
163 + },
164 + });
165 + expect(console.error.calls.count()).toBe(1);
166 + expect(console.error.calls.argsFor(0)[0]).toBe(
167 + 'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
168 + 'mean componentWillReceiveProps()?',
169 + );
170 + });
171 +
172 + it('should throw if a reserved property is in statics', () => {
173 + expect(function() {
174 + ReactCreateClass({
175 + statics: {
176 + getDefaultProps: function() {
177 + return {
178 + foo: 0,
179 + };
180 + },
181 + },
182 +
183 + render: function() {
184 + return <span />;
185 + },
186 + });
187 + }).toThrowError(
188 + 'ReactClass: You are attempting to define a reserved property, ' +
189 + '`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' +
190 + 'it as an instance property instead; it will still be accessible on ' +
191 + 'the constructor.',
192 + );
193 + });
194 +
195 + // TODO: Consider actually moving these to statics or drop this unit test.
196 +
197 + xit('should warn when using deprecated non-static spec keys', () => {
198 + spyOn(console, 'error');
199 + ReactCreateClass({
200 + mixins: [{}],
201 + propTypes: {
202 + foo: React.PropTypes.string,
203 + },
204 + contextTypes: {
205 + foo: React.PropTypes.string,
206 + },
207 + childContextTypes: {
208 + foo: React.PropTypes.string,
209 + },
210 + render: function() {
211 + return <div />;
212 + },
213 + });
214 + expect(console.error.calls.count()).toBe(4);
215 + expect(console.error.calls.argsFor(0)[0]).toBe(
216 + 'createClass(...): `mixins` is now a static property and should ' +
217 + 'be defined inside "statics".',
218 + );
219 + expect(console.error.calls.argsFor(1)[0]).toBe(
220 + 'createClass(...): `propTypes` is now a static property and should ' +
221 + 'be defined inside "statics".',
222 + );
223 + expect(console.error.calls.argsFor(2)[0]).toBe(
224 + 'createClass(...): `contextTypes` is now a static property and ' +
225 + 'should be defined inside "statics".',
226 + );
227 + expect(console.error.calls.argsFor(3)[0]).toBe(
228 + 'createClass(...): `childContextTypes` is now a static property and ' +
229 + 'should be defined inside "statics".',
230 + );
231 + });
232 +
233 + it('should support statics', () => {
234 + var Component = ReactCreateClass({
235 + statics: {
236 + abc: 'def',
237 + def: 0,
238 + ghi: null,
239 + jkl: 'mno',
240 + pqr: function() {
241 + return this;
242 + },
243 + },
244 +
245 + render: function() {
246 + return <span />;
247 + },
248 + });
249 + var instance = <Component />;
250 + instance = ReactTestUtils.renderIntoDocument(instance);
251 + expect(instance.constructor.abc).toBe('def');
252 + expect(Component.abc).toBe('def');
253 + expect(instance.constructor.def).toBe(0);
254 + expect(Component.def).toBe(0);
255 + expect(instance.constructor.ghi).toBe(null);
256 + expect(Component.ghi).toBe(null);
257 + expect(instance.constructor.jkl).toBe('mno');
258 + expect(Component.jkl).toBe('mno');
259 + expect(instance.constructor.pqr()).toBe(Component);
260 + expect(Component.pqr()).toBe(Component);
261 + });
262 +
263 + it('should work with object getInitialState() return values', () => {
264 + var Component = ReactCreateClass({
265 + getInitialState: function() {
266 + return {
267 + occupation: 'clown',
268 + };
269 + },
270 + render: function() {
271 + return <span />;
272 + },
273 + });
274 + var instance = <Component />;
275 + instance = ReactTestUtils.renderIntoDocument(instance);
276 + expect(instance.state.occupation).toEqual('clown');
277 + });
278 +
279 + it('renders based on context getInitialState', () => {
280 + var Foo = ReactCreateClass({
281 + contextTypes: {
282 + className: React.PropTypes.string,
283 + },
284 + getInitialState() {
285 + return {className: this.context.className};
286 + },
287 + render() {
288 + return <span className={this.state.className} />;
289 + },
290 + });
291 +
292 + var Outer = ReactCreateClass({
293 + childContextTypes: {
294 + className: React.PropTypes.string,
295 + },
296 + getChildContext() {
297 + return {className: 'foo'};
298 + },
299 + render() {
300 + return <Foo />;
301 + },
302 + });
303 +
304 + var container = document.createElement('div');
305 + ReactDOM.render(<Outer />, container);
306 + expect(container.firstChild.className).toBe('foo');
307 + });
308 +
309 + it('should throw with non-object getInitialState() return values', () => {
310 + [['an array'], 'a string', 1234].forEach(function(state) {
311 + var Component = ReactCreateClass({
312 + getInitialState: function() {
313 + return state;
314 + },
315 + render: function() {
316 + return <span />;
317 + },
318 + });
319 + var instance = <Component />;
320 + expect(function() {
321 + instance = ReactTestUtils.renderIntoDocument(instance);
322 + }).toThrowError(
323 + 'Component.getInitialState(): must return an object or null',
324 + );
325 + });
326 + });
327 +
328 + it('should work with a null getInitialState() return value', () => {
329 + var Component = ReactCreateClass({
330 + getInitialState: function() {
331 + return null;
332 + },
333 + render: function() {
334 + return <span />;
335 + },
336 + });
337 + expect(() =>
338 + ReactTestUtils.renderIntoDocument(<Component />)).not.toThrow();
339 + });
340 +
341 + it('should throw when using legacy factories', () => {
342 + spyOn(console, 'error');
343 + var Component = ReactCreateClass({
344 + render() {
345 + return <div />;
346 + },
347 + });
348 +
349 + expect(() => Component()).toThrow();
350 + expect(console.error.calls.count()).toBe(1);
351 + expect(console.error.calls.argsFor(0)[0]).toBe(
352 + 'Warning: Something is calling a React component directly. Use a ' +
353 + 'factory or JSX instead. See: https://fb.me/react-legacyfactory',
354 + );
355 + });
356 +
357 + it('replaceState and callback works', () => {
358 + var ops = [];
359 + var Component = ReactCreateClass({
360 + getInitialState() {
361 + return {step: 0};
362 + },
363 + render() {
364 + ops.push('Render: ' + this.state.step);
365 + return <div />;
366 + },
367 + });
368 +
369 + var instance = ReactTestUtils.renderIntoDocument(<Component />);
370 + instance.replaceState({step: 1}, () => {
371 + ops.push('Callback: ' + instance.state.step);
372 + });
373 + expect(ops).toEqual(['Render: 0', 'Render: 1', 'Callback: 1']);
374 + });
375 +
376 + it('isMounted works', () => {
377 + spyOn(console, 'error');
378 +
379 + var ops = [];
380 + var instance;
381 + var Component = ReactCreateClass({
382 + displayName: 'MyComponent',
383 + log(name) {
384 + ops.push(`${name}: ${this.isMounted()}`);
385 + },
386 + getInitialState() {
387 + this.log('getInitialState');
388 + return {};
389 + },
390 + componentWillMount() {
391 + this.log('componentWillMount');
392 + },
393 + componentDidMount() {
394 + this.log('componentDidMount');
395 + },
396 + componentWillUpdate() {
397 + this.log('componentWillUpdate');
398 + },
399 + componentDidUpdate() {
400 + this.log('componentDidUpdate');
401 + },
402 + componentWillUnmount() {
403 + this.log('componentWillUnmount');
404 + },
405 + render() {
406 + instance = this;
407 + this.log('render');
408 + return <div />;
409 + },
410 + });
411 +
412 + var container = document.createElement('div');
413 + ReactDOM.render(<Component />, container);
414 + ReactDOM.render(<Component />, container);
415 + ReactDOM.unmountComponentAtNode(container);
416 + instance.log('after unmount');
417 + expect(ops).toEqual([
418 + 'getInitialState: false',
419 + 'componentWillMount: false',
420 + 'render: false',
421 + 'componentDidMount: true',
422 + 'componentWillUpdate: true',
423 + 'render: true',
424 + 'componentDidUpdate: true',
425 + 'componentWillUnmount: false',
426 + 'after unmount: false',
427 + ]);
428 +
429 + expect(console.error.calls.count()).toBe(1);
430 + expect(console.error.calls.argsFor(0)[0]).toEqual(
431 + 'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
432 + 'clean up subscriptions and pending requests in componentWillUnmount ' +
433 + 'to prevent memory leaks.',
434 + );
435 + });
436 +});
yarn.lock
+6
@@ -4004,6 +4004,12 @@ rc@^1.1.7:
4004 minimist "^1.2.0"
4005 strip-json-comments "~2.0.1"
4006
4007 +react-create-class@15.5.0-alpha.7:
4008 + version "15.5.0-alpha.7"
4009 + resolved "https://registry.yarnpkg.com/react-create-class/-/react-create-class-15.5.0-alpha.7.tgz#a2bf8846ab0f0e86799e8a2c2346d7a87941a350"
4010 + dependencies:
4011 + fbjs "^0.8.9"
4012 +
4013 read-only-stream@^2.0.0:
4014 version "2.0.0"
4015 resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0"