@samitouri / QOS-React / commits / c068d31cca

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 });