1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @emails react-core
    
  8.  */
    
  9. 
    
  10. 'use strict';
    
  11. 
    
  12. let React;
    
  13. let ReactDOM;
    
  14. 
    
  15. describe('SelectEventPlugin', () => {
    
  16.   let container;
    
  17. 
    
  18.   beforeEach(() => {
    
  19.     React = require('react');
    
  20.     ReactDOM = require('react-dom');
    
  21. 
    
  22.     container = document.createElement('div');
    
  23.     document.body.appendChild(container);
    
  24.   });
    
  25. 
    
  26.   afterEach(() => {
    
  27.     document.body.removeChild(container);
    
  28.     container = null;
    
  29.   });
    
  30. 
    
  31.   // See https://github.com/facebook/react/pull/3639 for details.
    
  32.   it('does not get confused when dependent events are registered independently', () => {
    
  33.     const select = jest.fn();
    
  34.     const onSelect = event => {
    
  35.       expect(typeof event).toBe('object');
    
  36.       expect(event.type).toBe('select');
    
  37.       expect(event.target).toBe(node);
    
  38.       select(event.currentTarget);
    
  39.     };
    
  40. 
    
  41.     // Pass `onMouseDown` so React registers a top-level listener.
    
  42.     const node = ReactDOM.render(
    
  43.       <input type="text" onMouseDown={function () {}} />,
    
  44.       container,
    
  45.     );
    
  46. 
    
  47.     // Trigger `mousedown` and `mouseup`. Note that
    
  48.     // React is not currently listening to `mouseup`.
    
  49.     node.dispatchEvent(
    
  50.       new MouseEvent('mousedown', {
    
  51.         bubbles: true,
    
  52.         cancelable: true,
    
  53.       }),
    
  54.     );
    
  55.     node.dispatchEvent(
    
  56.       new MouseEvent('mouseup', {
    
  57.         bubbles: true,
    
  58.         cancelable: true,
    
  59.       }),
    
  60.     );
    
  61. 
    
  62.     // Now subscribe to `onSelect`.
    
  63.     ReactDOM.render(<input type="text" onSelect={onSelect} />, container);
    
  64.     node.focus();
    
  65. 
    
  66.     // This triggers a `select` event in our polyfill.
    
  67.     node.dispatchEvent(
    
  68.       new KeyboardEvent('keydown', {bubbles: true, cancelable: true}),
    
  69.     );
    
  70. 
    
  71.     // Verify that it doesn't get "stuck" waiting for
    
  72.     // a `mouseup` event that it has "missed" because
    
  73.     // a top-level listener didn't exist yet.
    
  74.     expect(select).toHaveBeenCalledTimes(1);
    
  75.   });
    
  76. 
    
  77.   it('should fire `onSelect` when a listener is present', () => {
    
  78.     const select = jest.fn();
    
  79.     const onSelect = event => {
    
  80.       expect(typeof event).toBe('object');
    
  81.       expect(event.type).toBe('select');
    
  82.       expect(event.target).toBe(node);
    
  83.       select(event.currentTarget);
    
  84.     };
    
  85. 
    
  86.     const node = ReactDOM.render(
    
  87.       <input type="text" onSelect={onSelect} />,
    
  88.       container,
    
  89.     );
    
  90.     node.focus();
    
  91. 
    
  92.     let nativeEvent = new MouseEvent('focus', {
    
  93.       bubbles: true,
    
  94.       cancelable: true,
    
  95.     });
    
  96.     node.dispatchEvent(nativeEvent);
    
  97.     expect(select).toHaveBeenCalledTimes(0);
    
  98. 
    
  99.     nativeEvent = new MouseEvent('mousedown', {
    
  100.       bubbles: true,
    
  101.       cancelable: true,
    
  102.     });
    
  103.     node.dispatchEvent(nativeEvent);
    
  104.     expect(select).toHaveBeenCalledTimes(0);
    
  105. 
    
  106.     nativeEvent = new MouseEvent('mouseup', {bubbles: true, cancelable: true});
    
  107.     node.dispatchEvent(nativeEvent);
    
  108.     expect(select).toHaveBeenCalledTimes(1);
    
  109.   });
    
  110. 
    
  111.   it('should fire `onSelectCapture` when a listener is present', () => {
    
  112.     const select = jest.fn();
    
  113.     const onSelectCapture = event => {
    
  114.       expect(typeof event).toBe('object');
    
  115.       expect(event.type).toBe('select');
    
  116.       expect(event.target).toBe(node);
    
  117.       select(event.currentTarget);
    
  118.     };
    
  119. 
    
  120.     const node = ReactDOM.render(
    
  121.       <input type="text" onSelectCapture={onSelectCapture} />,
    
  122.       container,
    
  123.     );
    
  124.     node.focus();
    
  125. 
    
  126.     let nativeEvent = new MouseEvent('focus', {
    
  127.       bubbles: true,
    
  128.       cancelable: true,
    
  129.     });
    
  130.     node.dispatchEvent(nativeEvent);
    
  131.     expect(select).toHaveBeenCalledTimes(0);
    
  132. 
    
  133.     nativeEvent = new MouseEvent('mousedown', {
    
  134.       bubbles: true,
    
  135.       cancelable: true,
    
  136.     });
    
  137.     node.dispatchEvent(nativeEvent);
    
  138.     expect(select).toHaveBeenCalledTimes(0);
    
  139. 
    
  140.     nativeEvent = new MouseEvent('mouseup', {bubbles: true, cancelable: true});
    
  141.     node.dispatchEvent(nativeEvent);
    
  142.     expect(select).toHaveBeenCalledTimes(1);
    
  143.   });
    
  144. 
    
  145.   // Regression test for https://github.com/facebook/react/issues/11379
    
  146.   it('should not wait for `mouseup` after receiving `dragend`', () => {
    
  147.     const select = jest.fn();
    
  148.     const onSelect = event => {
    
  149.       expect(typeof event).toBe('object');
    
  150.       expect(event.type).toBe('select');
    
  151.       expect(event.target).toBe(node);
    
  152.       select(event.currentTarget);
    
  153.     };
    
  154. 
    
  155.     const node = ReactDOM.render(
    
  156.       <input type="text" onSelect={onSelect} />,
    
  157.       container,
    
  158.     );
    
  159.     node.focus();
    
  160. 
    
  161.     let nativeEvent = new MouseEvent('focus', {
    
  162.       bubbles: true,
    
  163.       cancelable: true,
    
  164.     });
    
  165.     node.dispatchEvent(nativeEvent);
    
  166.     expect(select).toHaveBeenCalledTimes(0);
    
  167. 
    
  168.     nativeEvent = new MouseEvent('mousedown', {
    
  169.       bubbles: true,
    
  170.       cancelable: true,
    
  171.     });
    
  172.     node.dispatchEvent(nativeEvent);
    
  173.     expect(select).toHaveBeenCalledTimes(0);
    
  174. 
    
  175.     nativeEvent = new MouseEvent('dragend', {bubbles: true, cancelable: true});
    
  176.     node.dispatchEvent(nativeEvent);
    
  177.     expect(select).toHaveBeenCalledTimes(1);
    
  178.   });
    
  179. 
    
  180.   it('should handle selectionchange events', function () {
    
  181.     const onSelect = jest.fn();
    
  182.     const node = ReactDOM.render(
    
  183.       <input type="text" onSelect={onSelect} />,
    
  184.       container,
    
  185.     );
    
  186.     node.focus();
    
  187. 
    
  188.     // Make sure the event was not called before we emit the selection change event
    
  189.     expect(onSelect).toHaveBeenCalledTimes(0);
    
  190. 
    
  191.     // This is dispatched e.g. when using CMD+a on macOS
    
  192.     document.dispatchEvent(
    
  193.       new Event('selectionchange', {bubbles: false, cancelable: false}),
    
  194.     );
    
  195. 
    
  196.     expect(onSelect).toHaveBeenCalledTimes(1);
    
  197.   });
    
  198. });