Add unit tests for concurrent mode event dispatching (#14415)
Sebastian Markbåge committed
Jan 23, 2019 at 07:28 UTC
c068d31cca8126bda00beaef398b4d79152ed085
1 file changed
+186
packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js
+186
@@ -491,5 +491,191 @@ describe('ReactDOMFiberAsync', () => {
491
expect(container.textContent).toEqual('1');
492
expect(returnValue).toBe(undefined);
493
});
494
+
495
+ it('ignores discrete events on a pending removed element', () => {
496
+ const disableButtonRef = React.createRef();
497
+ const submitButtonRef = React.createRef();
498
+
499
+ let formSubmitted = false;
500
+
501
+ class Form extends React.Component {
502
+ state = {active: true};
503
+ disableForm = () => {
504
+ this.setState({active: false});
505
+ };
506
+ submitForm = () => {
507
+ formSubmitted = true; // This should not get invoked
508
+ };
509
+ render() {
510
+ return (
511
+ <div>
512
+ <button onClick={this.disableForm} ref={disableButtonRef}>
513
+ Disable
514
+ </button>
515
+ {this.state.active ? (
516
+ <button onClick={this.submitForm} ref={submitButtonRef}>
517
+ Submit
518
+ </button>
519
+ ) : null}
520
+ </div>
521
+ );
522
+ }
523
+ }
524
+
525
+ const root = ReactDOM.unstable_createRoot(container);
526
+ root.render(<Form />);
527
+ // Flush
528
+ jest.runAllTimers();
529
+
530
+ let disableButton = disableButtonRef.current;
531
+ expect(disableButton.tagName).toBe('BUTTON');
532
+
533
+ // Dispatch a click event on the Disable-button.
534
+ let firstEvent = document.createEvent('Event');
535
+ firstEvent.initEvent('click', true, true);
536
+ disableButton.dispatchEvent(firstEvent);
537
+
538
+ // There should now be a pending update to disable the form.
539
+
540
+ // This should not have flushed yet since it's in concurrent mode.
541
+ let submitButton = submitButtonRef.current;
542
+ expect(submitButton.tagName).toBe('BUTTON');
543
+
544
+ // In the meantime, we can dispatch a new client event on the submit button.
545
+ let secondEvent = document.createEvent('Event');
546
+ secondEvent.initEvent('click', true, true);
547
+ // This should force the pending update to flush which disables the submit button before the event is invoked.
548
+ submitButton.dispatchEvent(secondEvent);
549
+
550
+ // Therefore the form should never have been submitted.
551
+ expect(formSubmitted).toBe(false);
552
+
553
+ expect(submitButtonRef.current).toBe(null);
554
+ });
555
+
556
+ it('ignores discrete events on a pending removed event listener', () => {
557
+ const disableButtonRef = React.createRef();
558
+ const submitButtonRef = React.createRef();
559
+
560
+ let formSubmitted = false;
561
+
562
+ class Form extends React.Component {
563
+ state = {active: true};
564
+ disableForm = () => {
565
+ this.setState({active: false});
566
+ };
567
+ submitForm = () => {
568
+ formSubmitted = true; // This should not get invoked
569
+ };
570
+ disabledSubmitForm = () => {
571
+ // The form is disabled.
572
+ };
573
+ render() {
574
+ return (
575
+ <div>
576
+ <button onClick={this.disableForm} ref={disableButtonRef}>
577
+ Disable
578
+ </button>
579
+ <button
580
+ onClick={
581
+ this.state.active ? this.submitForm : this.disabledSubmitForm
582
+ }
583
+ ref={submitButtonRef}>
584
+ Submit
585
+ </button>{' '}
586
+ : null}
587
+ </div>
588
+ );
589
+ }
590
+ }
591
+
592
+ const root = ReactDOM.unstable_createRoot(container);
593
+ root.render(<Form />);
594
+ // Flush
595
+ jest.runAllTimers();
596
+
597
+ let disableButton = disableButtonRef.current;
598
+ expect(disableButton.tagName).toBe('BUTTON');
599
+
600
+ // Dispatch a click event on the Disable-button.
601
+ let firstEvent = document.createEvent('Event');
602
+ firstEvent.initEvent('click', true, true);
603
+ disableButton.dispatchEvent(firstEvent);
604
+
605
+ // There should now be a pending update to disable the form.
606
+
607
+ // This should not have flushed yet since it's in concurrent mode.
608
+ let submitButton = submitButtonRef.current;
609
+ expect(submitButton.tagName).toBe('BUTTON');
610
+
611
+ // In the meantime, we can dispatch a new client event on the submit button.
612
+ let secondEvent = document.createEvent('Event');
613
+ secondEvent.initEvent('click', true, true);
614
+ // This should force the pending update to flush which disables the submit button before the event is invoked.
615
+ submitButton.dispatchEvent(secondEvent);
616
+
617
+ // Therefore the form should never have been submitted.
618
+ expect(formSubmitted).toBe(false);
619
+ });
620
+
621
+ it('uses the newest discrete events on a pending changed event listener', () => {
622
+ const enableButtonRef = React.createRef();
623
+ const submitButtonRef = React.createRef();
624
+
625
+ let formSubmitted = false;
626
+
627
+ class Form extends React.Component {
628
+ state = {active: false};
629
+ enableForm = () => {
630
+ this.setState({active: true});
631
+ };
632
+ submitForm = () => {
633
+ formSubmitted = true; // This should happen
634
+ };
635
+ render() {
636
+ return (
637
+ <div>
638
+ <button onClick={this.enableForm} ref={enableButtonRef}>
639
+ Enable
640
+ </button>
641
+ <button
642
+ onClick={this.state.active ? this.submitForm : null}
643
+ ref={submitButtonRef}>
644
+ Submit
645
+ </button>{' '}
646
+ : null}
647
+ </div>
648
+ );
649
+ }
650
+ }
651
+
652
+ const root = ReactDOM.unstable_createRoot(container);
653
+ root.render(<Form />);
654
+ // Flush
655
+ jest.runAllTimers();
656
+
657
+ let enableButton = enableButtonRef.current;
658
+ expect(enableButton.tagName).toBe('BUTTON');
659
+
660
+ // Dispatch a click event on the Enable-button.
661
+ let firstEvent = document.createEvent('Event');
662
+ firstEvent.initEvent('click', true, true);
663
+ enableButton.dispatchEvent(firstEvent);
664
+
665
+ // There should now be a pending update to enable the form.
666
+
667
+ // This should not have flushed yet since it's in concurrent mode.
668
+ let submitButton = submitButtonRef.current;
669
+ expect(submitButton.tagName).toBe('BUTTON');
670
+
671
+ // In the meantime, we can dispatch a new client event on the submit button.
672
+ let secondEvent = document.createEvent('Event');
673
+ secondEvent.initEvent('click', true, true);
674
+ // This should force the pending update to flush which enables the submit button before the event is invoked.
675
+ submitButton.dispatchEvent(secondEvent);
676
+
677
+ // Therefore the form should have been submitted.
678
+ expect(formSubmitted).toBe(true);
679
+ });
680
});
681
});