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