@samitouri / QOS-React / commits / 5ac6209599

Fix shallow renderer callbacks (#10106)

* Add failing test to show that shallow test renderer doesn't call setState's callback arg * Record tests * Fix shallow renderer's setState/replaceState/forceUpdate to execute any callbacks passed. (#10089) * Ensure shallow renderer callbacks are called with the correct binding.

Dheeraj Kumar committed Jul 11, 2017 at 03:11 UTC 5ac62095996cce7b5441d9fad73fbcda1e3d2fca
3 files changed +117
scripts/fiber/tests-passing.txt
+3
@@ -1955,6 +1955,9 @@ src/renderers/dom/test/__tests__/ReactTestUtils-test.js
1955 * can setState in componentWillMount when shallow rendering
1956 * can setState in componentWillReceiveProps when shallow rendering
1957 * can setState with an updater function
1958 +* can setState with a callback
1959 +* can replaceState with a callback
1960 +* can forceUpdate with a callback
1961 * can pass context when shallowly rendering
1962 * should track context across updates
1963 * can fail context when shallowly rendering
src/renderers/dom/test/__tests__/ReactTestUtils-test.js
+102
@@ -405,6 +405,108 @@ describe('ReactTestUtils', () => {
405 expect(result.props.children).toEqual(2);
406 });
407
408 + it('can setState with a callback', () => {
409 + let instance;
410 +
411 + class SimpleComponent extends React.Component {
412 + state = {
413 + counter: 0,
414 + };
415 + render() {
416 + instance = this;
417 + return (
418 + <p>
419 + {this.state.counter}
420 + </p>
421 + );
422 + }
423 + }
424 +
425 + const shallowRenderer = createRenderer();
426 + const result = shallowRenderer.render(<SimpleComponent />);
427 + expect(result.props.children).toBe(0);
428 +
429 + const callback = jest.fn(function() {
430 + expect(this).toBe(instance);
431 + });
432 +
433 + instance.setState({counter: 1}, callback);
434 +
435 + const updated = shallowRenderer.getRenderOutput();
436 + expect(updated.props.children).toBe(1);
437 + expect(callback).toHaveBeenCalled();
438 + });
439 +
440 + it('can replaceState with a callback', () => {
441 + let instance;
442 +
443 + class SimpleComponent extends React.Component {
444 + state = {
445 + counter: 0,
446 + };
447 + render() {
448 + instance = this;
449 + return (
450 + <p>
451 + {this.state.counter}
452 + </p>
453 + );
454 + }
455 + }
456 +
457 + const shallowRenderer = createRenderer();
458 + const result = shallowRenderer.render(<SimpleComponent />);
459 + expect(result.props.children).toBe(0);
460 +
461 + const callback = jest.fn(function() {
462 + expect(this).toBe(instance);
463 + });
464 +
465 + // No longer a public API, but we can test that it works internally by
466 + // reaching into the updater.
467 + shallowRenderer._updater.enqueueReplaceState(
468 + instance,
469 + {counter: 1},
470 + callback,
471 + );
472 +
473 + const updated = shallowRenderer.getRenderOutput();
474 + expect(updated.props.children).toBe(1);
475 + expect(callback).toHaveBeenCalled();
476 + });
477 +
478 + it('can forceUpdate with a callback', () => {
479 + let instance;
480 +
481 + class SimpleComponent extends React.Component {
482 + state = {
483 + counter: 0,
484 + };
485 + render() {
486 + instance = this;
487 + return (
488 + <p>
489 + {this.state.counter}
490 + </p>
491 + );
492 + }
493 + }
494 +
495 + const shallowRenderer = createRenderer();
496 + const result = shallowRenderer.render(<SimpleComponent />);
497 + expect(result.props.children).toBe(0);
498 +
499 + const callback = jest.fn(function() {
500 + expect(this).toBe(instance);
501 + });
502 +
503 + instance.forceUpdate(callback);
504 +
505 + const updated = shallowRenderer.getRenderOutput();
506 + expect(updated.props.children).toBe(0);
507 + expect(callback).toHaveBeenCalled();
508 + });
509 +
510 it('can pass context when shallowly rendering', () => {
511 class SimpleComponent extends React.Component {
512 static contextTypes = {
src/renderers/testing/ReactShallowRendererEntry.js
+12
@@ -201,11 +201,19 @@ class Updater {
201
202 enqueueForceUpdate(publicInstance, callback, callerName) {
203 this._renderer.render(this._renderer._element, this._renderer._context);
204 +
205 + if (typeof callback === 'function') {
206 + callback.call(publicInstance);
207 + }
208 }
209
210 enqueueReplaceState(publicInstance, completeState, callback, callerName) {
211 this._renderer._newState = completeState;
212 this._renderer.render(this._renderer._element, this._renderer._context);
213 +
214 + if (typeof callback === 'function') {
215 + callback.call(publicInstance);
216 + }
217 }
218
219 enqueueSetState(publicInstance, partialState, callback, callerName) {
@@ -219,6 +227,10 @@ class Updater {
227 };
228
229 this._renderer.render(this._renderer._element, this._renderer._context);
230 +
231 + if (typeof callback === 'function') {
232 + callback.call(publicInstance);
233 + }
234 }
235 }
236