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. // This test is a hot mess. It heavily uses internals and relies on DOM even
    
  13. // though the responder plugin is only used in React Native. Sadness ensues.
    
  14. // The coverage is valuable though, so we will keep it for now.
    
  15. const {HostComponent} = require('react-reconciler/src/ReactWorkTags');
    
  16. 
    
  17. let EventBatching;
    
  18. let EventPluginUtils;
    
  19. let ResponderEventPlugin;
    
  20. 
    
  21. const touch = function (nodeHandle, i) {
    
  22.   return {target: nodeHandle, identifier: i};
    
  23. };
    
  24. 
    
  25. function injectComponentTree(ComponentTree) {
    
  26.   EventPluginUtils.setComponentTree(
    
  27.     ComponentTree.getFiberCurrentPropsFromNode,
    
  28.     ComponentTree.getInstanceFromNode,
    
  29.     ComponentTree.getNodeFromInstance,
    
  30.   );
    
  31. }
    
  32. 
    
  33. /**
    
  34.  * @param {NodeHandle} nodeHandle @see NodeHandle. Handle of target.
    
  35.  * @param {Array<Touch>} touches All active touches.
    
  36.  * @param {Array<Touch>} changedTouches Only the touches that have changed.
    
  37.  * @return {TouchEvent} Model of a touch event that is compliant with responder
    
  38.  * system plugin.
    
  39.  */
    
  40. const touchEvent = function (nodeHandle, touches, changedTouches) {
    
  41.   return {
    
  42.     target: nodeHandle,
    
  43.     changedTouches: changedTouches,
    
  44.     touches: touches,
    
  45.   };
    
  46. };
    
  47. 
    
  48. const subsequence = function (arr, indices) {
    
  49.   const ret = [];
    
  50.   for (let i = 0; i < indices.length; i++) {
    
  51.     const index = indices[i];
    
  52.     ret.push(arr[index]);
    
  53.   }
    
  54.   return ret;
    
  55. };
    
  56. 
    
  57. const antiSubsequence = function (arr, indices) {
    
  58.   const ret = [];
    
  59.   for (let i = 0; i < arr.length; i++) {
    
  60.     if (indices.indexOf(i) === -1) {
    
  61.       ret.push(arr[i]);
    
  62.     }
    
  63.   }
    
  64.   return ret;
    
  65. };
    
  66. 
    
  67. /**
    
  68.  * Helper for creating touch test config data.
    
  69.  * @param allTouchHandles
    
  70.  */
    
  71. const _touchConfig = function (
    
  72.   topType,
    
  73.   targetNodeHandle,
    
  74.   allTouchHandles,
    
  75.   changedIndices,
    
  76.   eventTarget,
    
  77. ) {
    
  78.   const allTouchObjects = allTouchHandles.map(touch);
    
  79.   const changedTouchObjects = subsequence(allTouchObjects, changedIndices);
    
  80.   const activeTouchObjects =
    
  81.     topType === 'topTouchStart'
    
  82.       ? allTouchObjects
    
  83.       : topType === 'topTouchMove'
    
  84.       ? allTouchObjects
    
  85.       : topType === 'topTouchEnd'
    
  86.       ? antiSubsequence(allTouchObjects, changedIndices)
    
  87.       : topType === 'topTouchCancel'
    
  88.       ? antiSubsequence(allTouchObjects, changedIndices)
    
  89.       : null;
    
  90. 
    
  91.   return {
    
  92.     nativeEvent: touchEvent(
    
  93.       targetNodeHandle,
    
  94.       activeTouchObjects,
    
  95.       changedTouchObjects,
    
  96.     ),
    
  97.     topLevelType: topType,
    
  98.     targetInst: getInstanceFromNode(targetNodeHandle),
    
  99.   };
    
  100. };
    
  101. 
    
  102. /**
    
  103.  * Creates test data for touch events using environment agnostic "node
    
  104.  * handles".
    
  105.  *
    
  106.  * @param {NodeHandle} nodeHandle Environment agnostic handle to DOM node.
    
  107.  * @param {Array<NodeHandle>} allTouchHandles Encoding of all "touches" in the
    
  108.  * form of a mapping from integer (touch `identifier`) to touch target. This is
    
  109.  * encoded in array form. Because of this, it is possible for two separate
    
  110.  * touches (meaning two separate indices) to have the same touch target ID -
    
  111.  * this corresponds to real world cases where two separate unique touches have
    
  112.  * the same target. These touches don't just represent all active touches,
    
  113.  * rather it also includes any touches that are not active, but are in the
    
  114.  * process of being removed.
    
  115.  * @param {Array<NodeHandle>} changedIndices Indices of `allTouchHandles` that
    
  116.  * have changed.
    
  117.  * @return {object} Config data used by test cases for extracting responder
    
  118.  * events.
    
  119.  */
    
  120. const startConfig = function (nodeHandle, allTouchHandles, changedIndices) {
    
  121.   return _touchConfig(
    
  122.     'topTouchStart',
    
  123.     nodeHandle,
    
  124.     allTouchHandles,
    
  125.     changedIndices,
    
  126.     nodeHandle,
    
  127.   );
    
  128. };
    
  129. 
    
  130. /**
    
  131.  * @see `startConfig`
    
  132.  */
    
  133. const moveConfig = function (nodeHandle, allTouchHandles, changedIndices) {
    
  134.   return _touchConfig(
    
  135.     'topTouchMove',
    
  136.     nodeHandle,
    
  137.     allTouchHandles,
    
  138.     changedIndices,
    
  139.     nodeHandle,
    
  140.   );
    
  141. };
    
  142. 
    
  143. /**
    
  144.  * @see `startConfig`
    
  145.  */
    
  146. const endConfig = function (nodeHandle, allTouchHandles, changedIndices) {
    
  147.   return _touchConfig(
    
  148.     'topTouchEnd',
    
  149.     nodeHandle,
    
  150.     allTouchHandles,
    
  151.     changedIndices,
    
  152.     nodeHandle,
    
  153.   );
    
  154. };
    
  155. 
    
  156. /**
    
  157.  * Test config for events that aren't negotiation related, but rather result of
    
  158.  * a negotiation.
    
  159.  *
    
  160.  * Returns object of the form:
    
  161.  *
    
  162.  *     {
    
  163.  *       responderReject: {
    
  164.  *         // Whatever "readableIDToID" was passed in.
    
  165.  *         grandParent: {order: NA, assertEvent: null, returnVal: blah},
    
  166.  *         ...
    
  167.  *         child: {order: NA, assertEvent: null, returnVal: blah},
    
  168.  *       }
    
  169.  *       responderGrant: {
    
  170.  *         grandParent: {order: NA, assertEvent: null, returnVal: blah},
    
  171.  *         ...
    
  172.  *         child: {order: NA, assertEvent: null, returnVal: blah}
    
  173.  *       }
    
  174.  *       ...
    
  175.  *     }
    
  176.  *
    
  177.  * After this is created, a test case would configure specific event orderings
    
  178.  * and optional assertions. Anything left with an `order` of `NA` will be
    
  179.  * required to never be invoked (the test runner will make sure it throws if
    
  180.  * ever invoked).
    
  181.  *
    
  182.  */
    
  183. const NA = -1;
    
  184. const oneEventLoopTestConfig = function (readableIDToID) {
    
  185.   const ret = {
    
  186.     // Negotiation
    
  187.     scrollShouldSetResponder: {bubbled: {}, captured: {}},
    
  188.     startShouldSetResponder: {bubbled: {}, captured: {}},
    
  189.     moveShouldSetResponder: {bubbled: {}, captured: {}},
    
  190.     responderTerminationRequest: {},
    
  191. 
    
  192.     // Non-negotiation
    
  193.     responderReject: {}, // These do not bubble capture.
    
  194.     responderGrant: {},
    
  195.     responderStart: {},
    
  196.     responderMove: {},
    
  197.     responderTerminate: {},
    
  198.     responderEnd: {},
    
  199.     responderRelease: {},
    
  200.   };
    
  201.   for (const eventName in ret) {
    
  202.     for (const readableNodeName in readableIDToID) {
    
  203.       if (ret[eventName].bubbled) {
    
  204.         // Two phase
    
  205.         ret[eventName].bubbled[readableNodeName] = {
    
  206.           order: NA,
    
  207.           assertEvent: null,
    
  208.           returnVal: undefined,
    
  209.         };
    
  210.         ret[eventName].captured[readableNodeName] = {
    
  211.           order: NA,
    
  212.           assertEvent: null,
    
  213.           returnVal: undefined,
    
  214.         };
    
  215.       } else {
    
  216.         ret[eventName][readableNodeName] = {
    
  217.           order: NA,
    
  218.           assertEvent: null,
    
  219.           returnVal: undefined,
    
  220.         };
    
  221.       }
    
  222.     }
    
  223.   }
    
  224.   return ret;
    
  225. };
    
  226. 
    
  227. /**
    
  228.  * @param {object} eventTestConfig
    
  229.  * @param {object} readableIDToID
    
  230.  */
    
  231. const registerTestHandlers = function (eventTestConfig, readableIDToID) {
    
  232.   const runs = {dispatchCount: 0};
    
  233.   const neverFire = function (readableID, registrationName) {
    
  234.     runs.dispatchCount++;
    
  235.     expect('').toBe(
    
  236.       'Event type: ' +
    
  237.         registrationName +
    
  238.         '\nShould never occur on:' +
    
  239.         readableID +
    
  240.         '\nFor event test config:\n' +
    
  241.         JSON.stringify(eventTestConfig) +
    
  242.         '\n',
    
  243.     );
    
  244.   };
    
  245. 
    
  246.   const registerOneEventType = function (
    
  247.     registrationName,
    
  248.     eventTypeTestConfig,
    
  249.   ) {
    
  250.     for (const readableID in eventTypeTestConfig) {
    
  251.       const nodeConfig = eventTypeTestConfig[readableID];
    
  252.       const id = readableIDToID[readableID];
    
  253.       const handler =
    
  254.         nodeConfig.order === NA
    
  255.           ? neverFire.bind(null, readableID, registrationName)
    
  256.           : // We partially apply readableID and nodeConfig, as they change in the
    
  257.             // parent closure across iterations.
    
  258.             function (rID, config, e) {
    
  259.               expect(
    
  260.                 rID +
    
  261.                   '->' +
    
  262.                   registrationName +
    
  263.                   ' index:' +
    
  264.                   runs.dispatchCount++,
    
  265.               ).toBe(rID + '->' + registrationName + ' index:' + config.order);
    
  266.               if (config.assertEvent) {
    
  267.                 config.assertEvent(e);
    
  268.               }
    
  269.               return config.returnVal;
    
  270.             }.bind(null, readableID, nodeConfig);
    
  271.       putListener(getInstanceFromNode(id), registrationName, handler);
    
  272.     }
    
  273.   };
    
  274.   for (const eventName in eventTestConfig) {
    
  275.     const oneEventTypeTestConfig = eventTestConfig[eventName];
    
  276.     const hasTwoPhase = !!oneEventTypeTestConfig.bubbled;
    
  277.     if (hasTwoPhase) {
    
  278.       registerOneEventType(
    
  279.         ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames
    
  280.           .bubbled,
    
  281.         oneEventTypeTestConfig.bubbled,
    
  282.       );
    
  283.       registerOneEventType(
    
  284.         ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames
    
  285.           .captured,
    
  286.         oneEventTypeTestConfig.captured,
    
  287.       );
    
  288.     } else {
    
  289.       registerOneEventType(
    
  290.         ResponderEventPlugin.eventTypes[eventName].registrationName,
    
  291.         oneEventTypeTestConfig,
    
  292.       );
    
  293.     }
    
  294.   }
    
  295.   return runs;
    
  296. };
    
  297. 
    
  298. const run = function (config, hierarchyConfig, nativeEventConfig) {
    
  299.   let max = NA;
    
  300.   const searchForMax = function (nodeConfig) {
    
  301.     for (const readableID in nodeConfig) {
    
  302.       const order = nodeConfig[readableID].order;
    
  303.       max = order > max ? order : max;
    
  304.     }
    
  305.   };
    
  306.   for (const eventName in config) {
    
  307.     const eventConfig = config[eventName];
    
  308.     if (eventConfig.bubbled) {
    
  309.       searchForMax(eventConfig.bubbled);
    
  310.       searchForMax(eventConfig.captured);
    
  311.     } else {
    
  312.       searchForMax(eventConfig);
    
  313.     }
    
  314.   }
    
  315. 
    
  316.   // Register the handlers
    
  317.   const runData = registerTestHandlers(config, hierarchyConfig);
    
  318. 
    
  319.   // Trigger the event
    
  320.   const extractedEvents = ResponderEventPlugin.extractEvents(
    
  321.     nativeEventConfig.topLevelType,
    
  322.     nativeEventConfig.targetInst,
    
  323.     nativeEventConfig.nativeEvent,
    
  324.     nativeEventConfig.target,
    
  325.     0,
    
  326.   );
    
  327. 
    
  328.   // At this point the negotiation events have been dispatched as part of the
    
  329.   // extraction process, but not the side effectful events. Below, we dispatch
    
  330.   // side effectful events.
    
  331.   EventBatching.runEventsInBatch(extractedEvents);
    
  332. 
    
  333.   // Ensure that every event that declared an `order`, was actually dispatched.
    
  334.   expect('number of events dispatched:' + runData.dispatchCount).toBe(
    
  335.     'number of events dispatched:' + (max + 1),
    
  336.   ); // +1 for extra ++
    
  337. };
    
  338. 
    
  339. const GRANDPARENT_HOST_NODE = {};
    
  340. const PARENT_HOST_NODE = {};
    
  341. const CHILD_HOST_NODE = {};
    
  342. const CHILD_HOST_NODE2 = {};
    
  343. 
    
  344. // These intentionally look like Fibers. ReactTreeTraversal depends on their field names.
    
  345. // TODO: we could test this with regular DOM nodes (and real fibers) instead.
    
  346. const GRANDPARENT_INST = {
    
  347.   return: null,
    
  348.   tag: HostComponent,
    
  349.   stateNode: GRANDPARENT_HOST_NODE,
    
  350.   memoizedProps: {},
    
  351. };
    
  352. const PARENT_INST = {
    
  353.   return: GRANDPARENT_INST,
    
  354.   tag: HostComponent,
    
  355.   stateNode: PARENT_HOST_NODE,
    
  356.   memoizedProps: {},
    
  357. };
    
  358. const CHILD_INST = {
    
  359.   return: PARENT_INST,
    
  360.   tag: HostComponent,
    
  361.   stateNode: CHILD_HOST_NODE,
    
  362.   memoizedProps: {},
    
  363. };
    
  364. const CHILD_INST2 = {
    
  365.   return: PARENT_INST,
    
  366.   tag: HostComponent,
    
  367.   stateNode: CHILD_HOST_NODE2,
    
  368.   memoizedProps: {},
    
  369. };
    
  370. 
    
  371. GRANDPARENT_HOST_NODE.testInstance = GRANDPARENT_INST;
    
  372. PARENT_HOST_NODE.testInstance = PARENT_INST;
    
  373. CHILD_HOST_NODE.testInstance = CHILD_INST;
    
  374. CHILD_HOST_NODE2.testInstance = CHILD_INST2;
    
  375. 
    
  376. const three = {
    
  377.   grandParent: GRANDPARENT_HOST_NODE,
    
  378.   parent: PARENT_HOST_NODE,
    
  379.   child: CHILD_HOST_NODE,
    
  380. };
    
  381. 
    
  382. const siblings = {
    
  383.   parent: PARENT_HOST_NODE,
    
  384.   childOne: CHILD_HOST_NODE,
    
  385.   childTwo: CHILD_HOST_NODE2,
    
  386. };
    
  387. 
    
  388. function getInstanceFromNode(node) {
    
  389.   return node.testInstance;
    
  390. }
    
  391. 
    
  392. function getNodeFromInstance(inst) {
    
  393.   return inst.stateNode;
    
  394. }
    
  395. 
    
  396. function getFiberCurrentPropsFromNode(node) {
    
  397.   return node.testInstance.memoizedProps;
    
  398. }
    
  399. 
    
  400. function putListener(instance, registrationName, handler) {
    
  401.   instance.memoizedProps[registrationName] = handler;
    
  402. }
    
  403. 
    
  404. function deleteAllListeners(instance) {
    
  405.   instance.memoizedProps = {};
    
  406. }
    
  407. 
    
  408. describe('ResponderEventPlugin', () => {
    
  409.   beforeEach(() => {
    
  410.     jest.resetModules();
    
  411. 
    
  412.     EventBatching = require('react-native-renderer/src/legacy-events/EventBatching');
    
  413.     EventPluginUtils = require('react-native-renderer/src/legacy-events/EventPluginUtils');
    
  414.     ResponderEventPlugin =
    
  415.       require('react-native-renderer/src/legacy-events/ResponderEventPlugin').default;
    
  416. 
    
  417.     deleteAllListeners(GRANDPARENT_INST);
    
  418.     deleteAllListeners(PARENT_INST);
    
  419.     deleteAllListeners(CHILD_INST);
    
  420.     deleteAllListeners(CHILD_INST2);
    
  421. 
    
  422.     injectComponentTree({
    
  423.       getInstanceFromNode,
    
  424.       getNodeFromInstance,
    
  425.       getFiberCurrentPropsFromNode,
    
  426.     });
    
  427.   });
    
  428. 
    
  429.   it('should do nothing when no one wants to respond', () => {
    
  430.     let config = oneEventLoopTestConfig(three);
    
  431.     config.startShouldSetResponder.captured.grandParent = {
    
  432.       order: 0,
    
  433.       returnVal: false,
    
  434.     };
    
  435.     config.startShouldSetResponder.captured.parent = {
    
  436.       order: 1,
    
  437.       returnVal: false,
    
  438.     };
    
  439.     config.startShouldSetResponder.captured.child = {
    
  440.       order: 2,
    
  441.       returnVal: false,
    
  442.     };
    
  443.     config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
    
  444.     config.startShouldSetResponder.bubbled.parent = {
    
  445.       order: 4,
    
  446.       returnVal: false,
    
  447.     };
    
  448.     config.startShouldSetResponder.bubbled.grandParent = {
    
  449.       order: 5,
    
  450.       returnVal: false,
    
  451.     };
    
  452.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  453.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  454. 
    
  455.     // Now no handlers should be called on `touchEnd`.
    
  456.     config = oneEventLoopTestConfig(three);
    
  457.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  458.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  459.   });
    
  460. 
    
  461.   /**
    
  462.    * Simple Start Granting
    
  463.    * --------------------
    
  464.    */
    
  465. 
    
  466.   it('should grant responder grandParent while capturing', () => {
    
  467.     let config = oneEventLoopTestConfig(three);
    
  468.     config.startShouldSetResponder.captured.grandParent = {
    
  469.       order: 0,
    
  470.       returnVal: true,
    
  471.     };
    
  472.     config.responderGrant.grandParent = {order: 1};
    
  473.     config.responderStart.grandParent = {order: 2};
    
  474.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  475.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  476.       getInstanceFromNode(three.grandParent),
    
  477.     );
    
  478. 
    
  479.     config = oneEventLoopTestConfig(three);
    
  480.     config.responderEnd.grandParent = {order: 0};
    
  481.     config.responderRelease.grandParent = {order: 1};
    
  482.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  483.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  484.   });
    
  485. 
    
  486.   it('should grant responder parent while capturing', () => {
    
  487.     let config = oneEventLoopTestConfig(three);
    
  488.     config.startShouldSetResponder.captured.grandParent = {
    
  489.       order: 0,
    
  490.       returnVal: false,
    
  491.     };
    
  492.     config.startShouldSetResponder.captured.parent = {
    
  493.       order: 1,
    
  494.       returnVal: true,
    
  495.     };
    
  496.     config.responderGrant.parent = {order: 2};
    
  497.     config.responderStart.parent = {order: 3};
    
  498.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  499.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  500.       getInstanceFromNode(three.parent),
    
  501.     );
    
  502. 
    
  503.     config = oneEventLoopTestConfig(three);
    
  504.     config.responderEnd.parent = {order: 0};
    
  505.     config.responderRelease.parent = {order: 1};
    
  506.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  507.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  508.   });
    
  509. 
    
  510.   it('should grant responder child while capturing', () => {
    
  511.     let config = oneEventLoopTestConfig(three);
    
  512.     config.startShouldSetResponder.captured.grandParent = {
    
  513.       order: 0,
    
  514.       returnVal: false,
    
  515.     };
    
  516.     config.startShouldSetResponder.captured.parent = {
    
  517.       order: 1,
    
  518.       returnVal: false,
    
  519.     };
    
  520.     config.startShouldSetResponder.captured.child = {order: 2, returnVal: true};
    
  521.     config.responderGrant.child = {order: 3};
    
  522.     config.responderStart.child = {order: 4};
    
  523.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  524.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  525.       getInstanceFromNode(three.child),
    
  526.     );
    
  527. 
    
  528.     config = oneEventLoopTestConfig(three);
    
  529.     config.responderEnd.child = {order: 0};
    
  530.     config.responderRelease.child = {order: 1};
    
  531.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  532.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  533.   });
    
  534. 
    
  535.   it('should grant responder child while bubbling', () => {
    
  536.     let config = oneEventLoopTestConfig(three);
    
  537.     config.startShouldSetResponder.captured.grandParent = {
    
  538.       order: 0,
    
  539.       returnVal: false,
    
  540.     };
    
  541.     config.startShouldSetResponder.captured.parent = {
    
  542.       order: 1,
    
  543.       returnVal: false,
    
  544.     };
    
  545.     config.startShouldSetResponder.captured.child = {
    
  546.       order: 2,
    
  547.       returnVal: false,
    
  548.     };
    
  549.     config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
    
  550.     config.responderGrant.child = {order: 4};
    
  551.     config.responderStart.child = {order: 5};
    
  552.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  553.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  554.       getInstanceFromNode(three.child),
    
  555.     );
    
  556. 
    
  557.     config = oneEventLoopTestConfig(three);
    
  558.     config.responderEnd.child = {order: 0};
    
  559.     config.responderRelease.child = {order: 1};
    
  560.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  561.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  562.   });
    
  563. 
    
  564.   it('should grant responder parent while bubbling', () => {
    
  565.     let config = oneEventLoopTestConfig(three);
    
  566.     config.startShouldSetResponder.captured.grandParent = {
    
  567.       order: 0,
    
  568.       returnVal: false,
    
  569.     };
    
  570.     config.startShouldSetResponder.captured.parent = {
    
  571.       order: 1,
    
  572.       returnVal: false,
    
  573.     };
    
  574.     config.startShouldSetResponder.captured.child = {
    
  575.       order: 2,
    
  576.       returnVal: false,
    
  577.     };
    
  578.     config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
    
  579.     config.startShouldSetResponder.bubbled.parent = {order: 4, returnVal: true};
    
  580.     config.responderGrant.parent = {order: 5};
    
  581.     config.responderStart.parent = {order: 6};
    
  582.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  583.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  584.       getInstanceFromNode(three.parent),
    
  585.     );
    
  586. 
    
  587.     config = oneEventLoopTestConfig(three);
    
  588.     config.responderEnd.parent = {order: 0};
    
  589.     config.responderRelease.parent = {order: 1};
    
  590.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  591.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  592.   });
    
  593. 
    
  594.   it('should grant responder grandParent while bubbling', () => {
    
  595.     let config = oneEventLoopTestConfig(three);
    
  596.     config.startShouldSetResponder.captured.grandParent = {
    
  597.       order: 0,
    
  598.       returnVal: false,
    
  599.     };
    
  600.     config.startShouldSetResponder.captured.parent = {
    
  601.       order: 1,
    
  602.       returnVal: false,
    
  603.     };
    
  604.     config.startShouldSetResponder.captured.child = {
    
  605.       order: 2,
    
  606.       returnVal: false,
    
  607.     };
    
  608.     config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
    
  609.     config.startShouldSetResponder.bubbled.parent = {
    
  610.       order: 4,
    
  611.       returnVal: false,
    
  612.     };
    
  613.     config.startShouldSetResponder.bubbled.grandParent = {
    
  614.       order: 5,
    
  615.       returnVal: true,
    
  616.     };
    
  617.     config.responderGrant.grandParent = {order: 6};
    
  618.     config.responderStart.grandParent = {order: 7};
    
  619.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  620.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  621.       getInstanceFromNode(three.grandParent),
    
  622.     );
    
  623. 
    
  624.     config = oneEventLoopTestConfig(three);
    
  625.     config.responderEnd.grandParent = {order: 0};
    
  626.     config.responderRelease.grandParent = {order: 1};
    
  627.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  628.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  629.   });
    
  630. 
    
  631.   /**
    
  632.    * Simple Move Granting
    
  633.    * --------------------
    
  634.    */
    
  635. 
    
  636.   it('should grant responder grandParent while capturing move', () => {
    
  637.     let config = oneEventLoopTestConfig(three);
    
  638. 
    
  639.     config.startShouldSetResponder.captured.grandParent = {order: 0};
    
  640.     config.startShouldSetResponder.captured.parent = {order: 1};
    
  641.     config.startShouldSetResponder.captured.child = {order: 2};
    
  642.     config.startShouldSetResponder.bubbled.child = {order: 3};
    
  643.     config.startShouldSetResponder.bubbled.parent = {order: 4};
    
  644.     config.startShouldSetResponder.bubbled.grandParent = {order: 5};
    
  645.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  646. 
    
  647.     config = oneEventLoopTestConfig(three);
    
  648.     config.moveShouldSetResponder.captured.grandParent = {
    
  649.       order: 0,
    
  650.       returnVal: true,
    
  651.     };
    
  652.     config.responderGrant.grandParent = {order: 1};
    
  653.     config.responderMove.grandParent = {order: 2};
    
  654.     run(config, three, moveConfig(three.child, [three.child], [0]));
    
  655.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  656.       getInstanceFromNode(three.grandParent),
    
  657.     );
    
  658. 
    
  659.     config = oneEventLoopTestConfig(three);
    
  660.     config.responderEnd.grandParent = {order: 0};
    
  661.     config.responderRelease.grandParent = {order: 1};
    
  662.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  663.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  664.   });
    
  665. 
    
  666.   it('should grant responder parent while capturing move', () => {
    
  667.     let config = oneEventLoopTestConfig(three);
    
  668. 
    
  669.     config.startShouldSetResponder.captured.grandParent = {order: 0};
    
  670.     config.startShouldSetResponder.captured.parent = {order: 1};
    
  671.     config.startShouldSetResponder.captured.child = {order: 2};
    
  672.     config.startShouldSetResponder.bubbled.child = {order: 3};
    
  673.     config.startShouldSetResponder.bubbled.parent = {order: 4};
    
  674.     config.startShouldSetResponder.bubbled.grandParent = {order: 5};
    
  675.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  676. 
    
  677.     config = oneEventLoopTestConfig(three);
    
  678.     config.moveShouldSetResponder.captured.grandParent = {
    
  679.       order: 0,
    
  680.       returnVal: false,
    
  681.     };
    
  682.     config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: true};
    
  683.     config.responderGrant.parent = {order: 2};
    
  684.     config.responderMove.parent = {order: 3};
    
  685.     run(config, three, moveConfig(three.child, [three.child], [0]));
    
  686.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  687.       getInstanceFromNode(three.parent),
    
  688.     );
    
  689. 
    
  690.     config = oneEventLoopTestConfig(three);
    
  691.     config.responderEnd.parent = {order: 0};
    
  692.     config.responderRelease.parent = {order: 1};
    
  693.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  694.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  695.   });
    
  696. 
    
  697.   it('should grant responder child while capturing move', () => {
    
  698.     let config = oneEventLoopTestConfig(three);
    
  699. 
    
  700.     config.startShouldSetResponder.captured.grandParent = {order: 0};
    
  701.     config.startShouldSetResponder.captured.parent = {order: 1};
    
  702.     config.startShouldSetResponder.captured.child = {order: 2};
    
  703.     config.startShouldSetResponder.bubbled.child = {order: 3};
    
  704.     config.startShouldSetResponder.bubbled.parent = {order: 4};
    
  705.     config.startShouldSetResponder.bubbled.grandParent = {order: 5};
    
  706.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  707. 
    
  708.     config = oneEventLoopTestConfig(three);
    
  709.     config.moveShouldSetResponder.captured.grandParent = {
    
  710.       order: 0,
    
  711.       returnVal: false,
    
  712.     };
    
  713.     config.moveShouldSetResponder.captured.parent = {
    
  714.       order: 1,
    
  715.       returnVal: false,
    
  716.     };
    
  717.     config.moveShouldSetResponder.captured.child = {order: 2, returnVal: true};
    
  718.     config.responderGrant.child = {order: 3};
    
  719.     config.responderMove.child = {order: 4};
    
  720.     run(config, three, moveConfig(three.child, [three.child], [0]));
    
  721.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  722.       getInstanceFromNode(three.child),
    
  723.     );
    
  724. 
    
  725.     config = oneEventLoopTestConfig(three);
    
  726.     config.responderEnd.child = {order: 0};
    
  727.     config.responderRelease.child = {order: 1};
    
  728.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  729.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  730.   });
    
  731. 
    
  732.   it('should grant responder child while bubbling move', () => {
    
  733.     let config = oneEventLoopTestConfig(three);
    
  734. 
    
  735.     config.startShouldSetResponder.captured.grandParent = {order: 0};
    
  736.     config.startShouldSetResponder.captured.parent = {order: 1};
    
  737.     config.startShouldSetResponder.captured.child = {order: 2};
    
  738.     config.startShouldSetResponder.bubbled.child = {order: 3};
    
  739.     config.startShouldSetResponder.bubbled.parent = {order: 4};
    
  740.     config.startShouldSetResponder.bubbled.grandParent = {order: 5};
    
  741.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  742. 
    
  743.     config = oneEventLoopTestConfig(three);
    
  744.     config.moveShouldSetResponder.captured.grandParent = {
    
  745.       order: 0,
    
  746.       returnVal: false,
    
  747.     };
    
  748.     config.moveShouldSetResponder.captured.parent = {
    
  749.       order: 1,
    
  750.       returnVal: false,
    
  751.     };
    
  752.     config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};
    
  753.     config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
    
  754.     config.responderGrant.child = {order: 4};
    
  755.     config.responderMove.child = {order: 5};
    
  756.     run(config, three, moveConfig(three.child, [three.child], [0]));
    
  757.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  758.       getInstanceFromNode(three.child),
    
  759.     );
    
  760. 
    
  761.     config = oneEventLoopTestConfig(three);
    
  762.     config.responderEnd.child = {order: 0};
    
  763.     config.responderRelease.child = {order: 1};
    
  764.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  765.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  766.   });
    
  767. 
    
  768.   it('should grant responder parent while bubbling move', () => {
    
  769.     let config = oneEventLoopTestConfig(three);
    
  770. 
    
  771.     config.startShouldSetResponder.captured.grandParent = {order: 0};
    
  772.     config.startShouldSetResponder.captured.parent = {order: 1};
    
  773.     config.startShouldSetResponder.captured.child = {order: 2};
    
  774.     config.startShouldSetResponder.bubbled.child = {order: 3};
    
  775.     config.startShouldSetResponder.bubbled.parent = {order: 4};
    
  776.     config.startShouldSetResponder.bubbled.grandParent = {order: 5};
    
  777.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  778. 
    
  779.     config = oneEventLoopTestConfig(three);
    
  780.     config.moveShouldSetResponder.captured.grandParent = {
    
  781.       order: 0,
    
  782.       returnVal: false,
    
  783.     };
    
  784.     config.moveShouldSetResponder.captured.parent = {
    
  785.       order: 1,
    
  786.       returnVal: false,
    
  787.     };
    
  788.     config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};
    
  789.     config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
    
  790.     config.moveShouldSetResponder.bubbled.parent = {order: 4, returnVal: true};
    
  791.     config.responderGrant.parent = {order: 5};
    
  792.     config.responderMove.parent = {order: 6};
    
  793.     run(config, three, moveConfig(three.child, [three.child], [0]));
    
  794.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  795.       getInstanceFromNode(three.parent),
    
  796.     );
    
  797. 
    
  798.     config = oneEventLoopTestConfig(three);
    
  799.     config.responderEnd.parent = {order: 0};
    
  800.     config.responderRelease.parent = {order: 1};
    
  801.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  802.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  803.   });
    
  804. 
    
  805.   it('should grant responder grandParent while bubbling move', () => {
    
  806.     let config = oneEventLoopTestConfig(three);
    
  807. 
    
  808.     config.startShouldSetResponder.captured.grandParent = {order: 0};
    
  809.     config.startShouldSetResponder.captured.parent = {order: 1};
    
  810.     config.startShouldSetResponder.captured.child = {order: 2};
    
  811.     config.startShouldSetResponder.bubbled.child = {order: 3};
    
  812.     config.startShouldSetResponder.bubbled.parent = {order: 4};
    
  813.     config.startShouldSetResponder.bubbled.grandParent = {order: 5};
    
  814.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  815. 
    
  816.     config = oneEventLoopTestConfig(three);
    
  817.     config.moveShouldSetResponder.captured.grandParent = {
    
  818.       order: 0,
    
  819.       returnVal: false,
    
  820.     };
    
  821.     config.moveShouldSetResponder.captured.parent = {
    
  822.       order: 1,
    
  823.       returnVal: false,
    
  824.     };
    
  825.     config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};
    
  826.     config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
    
  827.     config.moveShouldSetResponder.bubbled.parent = {order: 4, returnVal: false};
    
  828.     config.moveShouldSetResponder.bubbled.grandParent = {
    
  829.       order: 5,
    
  830.       returnVal: true,
    
  831.     };
    
  832.     config.responderGrant.grandParent = {order: 6};
    
  833.     config.responderMove.grandParent = {order: 7};
    
  834.     run(config, three, moveConfig(three.child, [three.child], [0]));
    
  835.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  836.       getInstanceFromNode(three.grandParent),
    
  837.     );
    
  838. 
    
  839.     config = oneEventLoopTestConfig(three);
    
  840.     config.responderEnd.grandParent = {order: 0};
    
  841.     config.responderRelease.grandParent = {order: 1};
    
  842.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  843.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  844.   });
    
  845. 
    
  846.   /**
    
  847.    * Common ancestor tests
    
  848.    * ---------------------
    
  849.    */
    
  850. 
    
  851.   it('should bubble negotiation to first common ancestor of responder', () => {
    
  852.     let config = oneEventLoopTestConfig(three);
    
  853.     config.startShouldSetResponder.captured.grandParent = {
    
  854.       order: 0,
    
  855.       returnVal: false,
    
  856.     };
    
  857.     config.startShouldSetResponder.captured.parent = {
    
  858.       order: 1,
    
  859.       returnVal: true,
    
  860.     };
    
  861.     config.responderGrant.parent = {order: 2};
    
  862.     config.responderStart.parent = {order: 3};
    
  863.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  864.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  865.       getInstanceFromNode(three.parent),
    
  866.     );
    
  867. 
    
  868.     // While `parent` is still responder, we create new handlers that verify
    
  869.     // the ordering of propagation, restarting the count at `0`.
    
  870.     config = oneEventLoopTestConfig(three);
    
  871.     config.startShouldSetResponder.captured.grandParent = {
    
  872.       order: 0,
    
  873.       returnVal: false,
    
  874.     };
    
  875. 
    
  876.     config.startShouldSetResponder.bubbled.grandParent = {
    
  877.       order: 1,
    
  878.       returnVal: false,
    
  879.     };
    
  880.     config.responderStart.parent = {order: 2};
    
  881.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  882.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  883.       getInstanceFromNode(three.parent),
    
  884.     );
    
  885. 
    
  886.     config = oneEventLoopTestConfig(three);
    
  887.     config.responderEnd.parent = {order: 0};
    
  888.     config.responderRelease.parent = {order: 1};
    
  889.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  890.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  891.   });
    
  892. 
    
  893.   it('should bubble negotiation to first common ancestor of responder then transfer', () => {
    
  894.     let config = oneEventLoopTestConfig(three);
    
  895.     config.startShouldSetResponder.captured.grandParent = {
    
  896.       order: 0,
    
  897.       returnVal: false,
    
  898.     };
    
  899.     config.startShouldSetResponder.captured.parent = {
    
  900.       order: 1,
    
  901.       returnVal: true,
    
  902.     };
    
  903.     config.responderGrant.parent = {order: 2};
    
  904.     config.responderStart.parent = {order: 3};
    
  905.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  906.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  907.       getInstanceFromNode(three.parent),
    
  908.     );
    
  909. 
    
  910.     config = oneEventLoopTestConfig(three);
    
  911. 
    
  912.     // Parent is responder, and responder is transferred by a second touch start
    
  913.     config.startShouldSetResponder.captured.grandParent = {
    
  914.       order: 0,
    
  915.       returnVal: true,
    
  916.     };
    
  917.     config.responderGrant.grandParent = {order: 1};
    
  918.     config.responderTerminationRequest.parent = {order: 2, returnVal: true};
    
  919.     config.responderTerminate.parent = {order: 3};
    
  920.     config.responderStart.grandParent = {order: 4};
    
  921.     run(
    
  922.       config,
    
  923.       three,
    
  924.       startConfig(three.child, [three.child, three.child], [1]),
    
  925.     );
    
  926.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  927.       getInstanceFromNode(three.grandParent),
    
  928.     );
    
  929. 
    
  930.     config = oneEventLoopTestConfig(three);
    
  931.     config.responderEnd.grandParent = {order: 0};
    
  932.     // one remains\ /one ended \
    
  933.     run(config, three, endConfig(three.child, [three.child, three.child], [1]));
    
  934.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  935.       getInstanceFromNode(three.grandParent),
    
  936.     );
    
  937. 
    
  938.     config = oneEventLoopTestConfig(three);
    
  939.     config.responderEnd.grandParent = {order: 0};
    
  940.     config.responderRelease.grandParent = {order: 1};
    
  941.     run(config, three, endConfig(three.child, [three.child], [0]));
    
  942.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  943.   });
    
  944. 
    
  945.   /**
    
  946.    * If nothing is responder, then the negotiation should propagate directly to
    
  947.    * the deepest target in the second touch.
    
  948.    */
    
  949.   it('should negotiate with deepest target on second touch if nothing is responder', () => {
    
  950.     // Initially nothing wants to become the responder
    
  951.     let config = oneEventLoopTestConfig(three);
    
  952.     config.startShouldSetResponder.captured.grandParent = {
    
  953.       order: 0,
    
  954.       returnVal: false,
    
  955.     };
    
  956.     config.startShouldSetResponder.captured.parent = {
    
  957.       order: 1,
    
  958.       returnVal: false,
    
  959.     };
    
  960.     config.startShouldSetResponder.bubbled.parent = {
    
  961.       order: 2,
    
  962.       returnVal: false,
    
  963.     };
    
  964.     config.startShouldSetResponder.bubbled.grandParent = {
    
  965.       order: 3,
    
  966.       returnVal: false,
    
  967.     };
    
  968. 
    
  969.     run(config, three, startConfig(three.parent, [three.parent], [0]));
    
  970.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  971. 
    
  972.     config = oneEventLoopTestConfig(three);
    
  973. 
    
  974.     // Now child wants to become responder. Negotiation should bubble as deep
    
  975.     // as the target is because we don't find first common ancestor (with
    
  976.     // current responder) because there is no current responder.
    
  977.     // (Even if this is the second active touch).
    
  978.     config.startShouldSetResponder.captured.grandParent = {
    
  979.       order: 0,
    
  980.       returnVal: false,
    
  981.     };
    
  982.     config.startShouldSetResponder.captured.parent = {
    
  983.       order: 1,
    
  984.       returnVal: false,
    
  985.     };
    
  986.     config.startShouldSetResponder.captured.child = {
    
  987.       order: 2,
    
  988.       returnVal: false,
    
  989.     };
    
  990.     config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
    
  991.     config.responderGrant.child = {order: 4};
    
  992.     config.responderStart.child = {order: 5};
    
  993.     //                                     /  Two active touches  \  /one of them new\
    
  994.     run(
    
  995.       config,
    
  996.       three,
    
  997.       startConfig(three.child, [three.parent, three.child], [1]),
    
  998.     );
    
  999.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1000.       getInstanceFromNode(three.child),
    
  1001.     );
    
  1002. 
    
  1003.     // Now we remove the original first touch, keeping the second touch that
    
  1004.     // started within the current responder (child). Nothing changes because
    
  1005.     // there's still touches that started inside of the current responder.
    
  1006.     config = oneEventLoopTestConfig(three);
    
  1007.     config.responderEnd.child = {order: 0};
    
  1008.     //                                      / one ended\  /one remains \
    
  1009.     run(
    
  1010.       config,
    
  1011.       three,
    
  1012.       endConfig(three.child, [three.parent, three.child], [0]),
    
  1013.     );
    
  1014.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1015.       getInstanceFromNode(three.child),
    
  1016.     );
    
  1017. 
    
  1018.     // Okay, now let's add back that first touch (nothing should change) and
    
  1019.     // then we'll try peeling back the touches in the opposite order to make
    
  1020.     // sure that first removing the second touch instantly causes responder to
    
  1021.     // be released.
    
  1022.     config = oneEventLoopTestConfig(three);
    
  1023.     config.startShouldSetResponder.captured.grandParent = {
    
  1024.       order: 0,
    
  1025.       returnVal: false,
    
  1026.     };
    
  1027.     config.startShouldSetResponder.captured.parent = {
    
  1028.       order: 1,
    
  1029.       returnVal: false,
    
  1030.     };
    
  1031.     config.startShouldSetResponder.bubbled.parent = {
    
  1032.       order: 2,
    
  1033.       returnVal: false,
    
  1034.     };
    
  1035.     config.startShouldSetResponder.bubbled.grandParent = {
    
  1036.       order: 3,
    
  1037.       returnVal: false,
    
  1038.     };
    
  1039.     // Interesting: child still gets moves even though touch target is parent!
    
  1040.     // Current responder gets a `responderStart` for any touch while responder.
    
  1041.     config.responderStart.child = {order: 4};
    
  1042.     //                                           /  Two active touches  \  /one of them new\
    
  1043.     run(
    
  1044.       config,
    
  1045.       three,
    
  1046.       startConfig(three.parent, [three.child, three.parent], [1]),
    
  1047.     );
    
  1048.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1049.       getInstanceFromNode(three.child),
    
  1050.     );
    
  1051. 
    
  1052.     // Now, move that new touch that had no effect, and did not start within
    
  1053.     // the current responder.
    
  1054.     config = oneEventLoopTestConfig(three);
    
  1055.     config.moveShouldSetResponder.captured.grandParent = {
    
  1056.       order: 0,
    
  1057.       returnVal: false,
    
  1058.     };
    
  1059.     config.moveShouldSetResponder.captured.parent = {
    
  1060.       order: 1,
    
  1061.       returnVal: false,
    
  1062.     };
    
  1063.     config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: false};
    
  1064.     config.moveShouldSetResponder.bubbled.grandParent = {
    
  1065.       order: 3,
    
  1066.       returnVal: false,
    
  1067.     };
    
  1068.     // Interesting: child still gets moves even though touch target is parent!
    
  1069.     // Current responder gets a `responderMove` for any touch while responder.
    
  1070.     config.responderMove.child = {order: 4};
    
  1071.     //                                     /  Two active touches  \  /one of them moved\
    
  1072.     run(
    
  1073.       config,
    
  1074.       three,
    
  1075.       moveConfig(three.parent, [three.child, three.parent], [1]),
    
  1076.     );
    
  1077.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1078.       getInstanceFromNode(three.child),
    
  1079.     );
    
  1080. 
    
  1081.     config = oneEventLoopTestConfig(three);
    
  1082.     config.responderEnd.child = {order: 0};
    
  1083.     config.responderRelease.child = {order: 1};
    
  1084.     //                                        /child end \ /parent remain\
    
  1085.     run(
    
  1086.       config,
    
  1087.       three,
    
  1088.       endConfig(three.child, [three.child, three.parent], [0]),
    
  1089.     );
    
  1090.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  1091.   });
    
  1092. 
    
  1093.   /**
    
  1094.    * If nothing is responder, then the negotiation should propagate directly to
    
  1095.    * the deepest target in the second touch.
    
  1096.    */
    
  1097.   it('should negotiate until first common ancestor when there are siblings', () => {
    
  1098.     // Initially nothing wants to become the responder
    
  1099.     let config = oneEventLoopTestConfig(siblings);
    
  1100.     config.startShouldSetResponder.captured.parent = {
    
  1101.       order: 0,
    
  1102.       returnVal: false,
    
  1103.     };
    
  1104.     config.startShouldSetResponder.captured.childOne = {
    
  1105.       order: 1,
    
  1106.       returnVal: false,
    
  1107.     };
    
  1108.     config.startShouldSetResponder.bubbled.childOne = {
    
  1109.       order: 2,
    
  1110.       returnVal: true,
    
  1111.     };
    
  1112.     config.responderGrant.childOne = {order: 3};
    
  1113.     config.responderStart.childOne = {order: 4};
    
  1114. 
    
  1115.     run(
    
  1116.       config,
    
  1117.       siblings,
    
  1118.       startConfig(siblings.childOne, [siblings.childOne], [0]),
    
  1119.     );
    
  1120.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1121.       getInstanceFromNode(siblings.childOne),
    
  1122.     );
    
  1123. 
    
  1124.     // If the touch target is the sibling item, the negotiation should only
    
  1125.     // propagate to first common ancestor of current responder and sibling (so
    
  1126.     // the parent).
    
  1127.     config = oneEventLoopTestConfig(siblings);
    
  1128.     config.startShouldSetResponder.captured.parent = {
    
  1129.       order: 0,
    
  1130.       returnVal: false,
    
  1131.     };
    
  1132.     config.startShouldSetResponder.bubbled.parent = {
    
  1133.       order: 1,
    
  1134.       returnVal: false,
    
  1135.     };
    
  1136.     config.responderStart.childOne = {order: 2};
    
  1137. 
    
  1138.     const touchConfig = startConfig(
    
  1139.       siblings.childTwo,
    
  1140.       [siblings.childOne, siblings.childTwo],
    
  1141.       [1],
    
  1142.     );
    
  1143.     run(config, siblings, touchConfig);
    
  1144.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1145.       getInstanceFromNode(siblings.childOne),
    
  1146.     );
    
  1147. 
    
  1148.     // move childOne
    
  1149.     config = oneEventLoopTestConfig(siblings);
    
  1150.     config.moveShouldSetResponder.captured.parent = {
    
  1151.       order: 0,
    
  1152.       returnVal: false,
    
  1153.     };
    
  1154.     config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};
    
  1155.     config.responderMove.childOne = {order: 2};
    
  1156.     run(
    
  1157.       config,
    
  1158.       siblings,
    
  1159.       moveConfig(
    
  1160.         siblings.childOne,
    
  1161.         [siblings.childOne, siblings.childTwo],
    
  1162.         [0],
    
  1163.       ),
    
  1164.     );
    
  1165.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1166.       getInstanceFromNode(siblings.childOne),
    
  1167.     );
    
  1168. 
    
  1169.     // move childTwo: Only negotiates to `parent`.
    
  1170.     config = oneEventLoopTestConfig(siblings);
    
  1171.     config.moveShouldSetResponder.captured.parent = {
    
  1172.       order: 0,
    
  1173.       returnVal: false,
    
  1174.     };
    
  1175.     config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};
    
  1176.     config.responderMove.childOne = {order: 2};
    
  1177.     run(
    
  1178.       config,
    
  1179.       siblings,
    
  1180.       moveConfig(
    
  1181.         siblings.childTwo,
    
  1182.         [siblings.childOne, siblings.childTwo],
    
  1183.         [1],
    
  1184.       ),
    
  1185.     );
    
  1186.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1187.       getInstanceFromNode(siblings.childOne),
    
  1188.     );
    
  1189.   });
    
  1190. 
    
  1191.   it('should notify of being rejected. responderStart/Move happens on current responder', () => {
    
  1192.     // Initially nothing wants to become the responder
    
  1193.     let config = oneEventLoopTestConfig(three);
    
  1194.     config.startShouldSetResponder.captured.grandParent = {
    
  1195.       order: 0,
    
  1196.       returnVal: false,
    
  1197.     };
    
  1198.     config.startShouldSetResponder.captured.parent = {
    
  1199.       order: 1,
    
  1200.       returnVal: false,
    
  1201.     };
    
  1202.     config.startShouldSetResponder.captured.child = {
    
  1203.       order: 2,
    
  1204.       returnVal: false,
    
  1205.     };
    
  1206.     config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
    
  1207.     config.responderGrant.child = {order: 4};
    
  1208.     config.responderStart.child = {order: 5};
    
  1209. 
    
  1210.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  1211.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1212.       getInstanceFromNode(three.child),
    
  1213.     );
    
  1214. 
    
  1215.     // Suppose parent wants to become responder on move, and is rejected
    
  1216.     config = oneEventLoopTestConfig(three);
    
  1217.     config.moveShouldSetResponder.captured.grandParent = {
    
  1218.       order: 0,
    
  1219.       returnVal: false,
    
  1220.     };
    
  1221.     config.moveShouldSetResponder.captured.parent = {
    
  1222.       order: 1,
    
  1223.       returnVal: false,
    
  1224.     };
    
  1225.     config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
    
  1226.     config.responderGrant.parent = {order: 3};
    
  1227.     config.responderTerminationRequest.child = {order: 4, returnVal: false};
    
  1228.     config.responderReject.parent = {order: 5};
    
  1229.     // The start/move should occur on the original responder if new one is rejected
    
  1230.     config.responderMove.child = {order: 6};
    
  1231. 
    
  1232.     let touchConfig = moveConfig(three.child, [three.child], [0]);
    
  1233.     run(config, three, touchConfig);
    
  1234.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1235.       getInstanceFromNode(three.child),
    
  1236.     );
    
  1237. 
    
  1238.     config = oneEventLoopTestConfig(three);
    
  1239.     config.startShouldSetResponder.captured.grandParent = {
    
  1240.       order: 0,
    
  1241.       returnVal: false,
    
  1242.     };
    
  1243.     config.startShouldSetResponder.captured.parent = {
    
  1244.       order: 1,
    
  1245.       returnVal: false,
    
  1246.     };
    
  1247.     config.startShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
    
  1248.     config.responderGrant.parent = {order: 3};
    
  1249.     config.responderTerminationRequest.child = {order: 4, returnVal: false};
    
  1250.     config.responderReject.parent = {order: 5};
    
  1251.     // The start/move should occur on the original responder if new one is rejected
    
  1252.     config.responderStart.child = {order: 6};
    
  1253. 
    
  1254.     touchConfig = startConfig(three.child, [three.child, three.child], [1]);
    
  1255.     run(config, three, touchConfig);
    
  1256.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1257.       getInstanceFromNode(three.child),
    
  1258.     );
    
  1259.   });
    
  1260. 
    
  1261.   it('should negotiate scroll', () => {
    
  1262.     // Initially nothing wants to become the responder
    
  1263.     let config = oneEventLoopTestConfig(three);
    
  1264.     config.startShouldSetResponder.captured.grandParent = {
    
  1265.       order: 0,
    
  1266.       returnVal: false,
    
  1267.     };
    
  1268.     config.startShouldSetResponder.captured.parent = {
    
  1269.       order: 1,
    
  1270.       returnVal: false,
    
  1271.     };
    
  1272.     config.startShouldSetResponder.captured.child = {
    
  1273.       order: 2,
    
  1274.       returnVal: false,
    
  1275.     };
    
  1276.     config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
    
  1277.     config.responderGrant.child = {order: 4};
    
  1278.     config.responderStart.child = {order: 5};
    
  1279. 
    
  1280.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  1281.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1282.       getInstanceFromNode(three.child),
    
  1283.     );
    
  1284. 
    
  1285.     // If the touch target is the sibling item, the negotiation should only
    
  1286.     // propagate to first common ancestor of current responder and sibling (so
    
  1287.     // the parent).
    
  1288.     config = oneEventLoopTestConfig(three);
    
  1289.     config.scrollShouldSetResponder.captured.grandParent = {
    
  1290.       order: 0,
    
  1291.       returnVal: false,
    
  1292.     };
    
  1293.     config.scrollShouldSetResponder.captured.parent = {
    
  1294.       order: 1,
    
  1295.       returnVal: false,
    
  1296.     };
    
  1297.     config.scrollShouldSetResponder.bubbled.parent = {
    
  1298.       order: 2,
    
  1299.       returnVal: true,
    
  1300.     };
    
  1301.     config.responderGrant.parent = {order: 3};
    
  1302.     config.responderTerminationRequest.child = {order: 4, returnVal: false};
    
  1303.     config.responderReject.parent = {order: 5};
    
  1304. 
    
  1305.     run(config, three, {
    
  1306.       topLevelType: 'topScroll',
    
  1307.       targetInst: getInstanceFromNode(three.parent),
    
  1308.       nativeEvent: {},
    
  1309.     });
    
  1310.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1311.       getInstanceFromNode(three.child),
    
  1312.     );
    
  1313. 
    
  1314.     // Now lets let the scroll take control this time.
    
  1315.     config = oneEventLoopTestConfig(three);
    
  1316.     config.scrollShouldSetResponder.captured.grandParent = {
    
  1317.       order: 0,
    
  1318.       returnVal: false,
    
  1319.     };
    
  1320.     config.scrollShouldSetResponder.captured.parent = {
    
  1321.       order: 1,
    
  1322.       returnVal: false,
    
  1323.     };
    
  1324.     config.scrollShouldSetResponder.bubbled.parent = {
    
  1325.       order: 2,
    
  1326.       returnVal: true,
    
  1327.     };
    
  1328.     config.responderGrant.parent = {order: 3};
    
  1329.     config.responderTerminationRequest.child = {order: 4, returnVal: true};
    
  1330.     config.responderTerminate.child = {order: 5};
    
  1331. 
    
  1332.     run(config, three, {
    
  1333.       topLevelType: 'topScroll',
    
  1334.       targetInst: getInstanceFromNode(three.parent),
    
  1335.       nativeEvent: {},
    
  1336.     });
    
  1337.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1338.       getInstanceFromNode(three.parent),
    
  1339.     );
    
  1340.   });
    
  1341. 
    
  1342.   it('should cancel correctly', () => {
    
  1343.     // Initially our child becomes responder
    
  1344.     let config = oneEventLoopTestConfig(three);
    
  1345.     config.startShouldSetResponder.captured.grandParent = {
    
  1346.       order: 0,
    
  1347.       returnVal: false,
    
  1348.     };
    
  1349.     config.startShouldSetResponder.captured.parent = {
    
  1350.       order: 1,
    
  1351.       returnVal: false,
    
  1352.     };
    
  1353.     config.startShouldSetResponder.captured.child = {
    
  1354.       order: 2,
    
  1355.       returnVal: false,
    
  1356.     };
    
  1357.     config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
    
  1358.     config.responderGrant.child = {order: 4};
    
  1359.     config.responderStart.child = {order: 5};
    
  1360. 
    
  1361.     run(config, three, startConfig(three.child, [three.child], [0]));
    
  1362.     expect(ResponderEventPlugin._getResponder()).toBe(
    
  1363.       getInstanceFromNode(three.child),
    
  1364.     );
    
  1365. 
    
  1366.     config = oneEventLoopTestConfig(three);
    
  1367.     config.responderEnd.child = {order: 0};
    
  1368.     config.responderTerminate.child = {order: 1};
    
  1369. 
    
  1370.     const nativeEvent = _touchConfig(
    
  1371.       'topTouchCancel',
    
  1372.       three.child,
    
  1373.       [three.child],
    
  1374.       [0],
    
  1375.     );
    
  1376.     run(config, three, nativeEvent);
    
  1377.     expect(ResponderEventPlugin._getResponder()).toBe(null);
    
  1378.   });
    
  1379. 
    
  1380.   it('should determine the first common ancestor correctly', () => {
    
  1381.     // This test was moved here from the ReactTreeTraversal test since only the
    
  1382.     // ResponderEventPlugin uses `getLowestCommonAncestor`
    
  1383.     const React = require('react');
    
  1384.     const ReactTestUtils = require('react-dom/test-utils');
    
  1385.     const getLowestCommonAncestor =
    
  1386.       require('react-native-renderer/src/legacy-events/ResponderEventPlugin').getLowestCommonAncestor;
    
  1387.     // This works by accident and will likely break in the future.
    
  1388.     const ReactDOMComponentTree = require('react-dom-bindings/src/client/ReactDOMComponentTree');
    
  1389. 
    
  1390.     class ChildComponent extends React.Component {
    
  1391.       divRef = React.createRef();
    
  1392.       div1Ref = React.createRef();
    
  1393.       div2Ref = React.createRef();
    
  1394. 
    
  1395.       render() {
    
  1396.         return (
    
  1397.           <div ref={this.divRef} id={this.props.id + '__DIV'}>
    
  1398.             <div ref={this.div1Ref} id={this.props.id + '__DIV_1'} />
    
  1399.             <div ref={this.div2Ref} id={this.props.id + '__DIV_2'} />
    
  1400.           </div>
    
  1401.         );
    
  1402.       }
    
  1403.     }
    
  1404. 
    
  1405.     class ParentComponent extends React.Component {
    
  1406.       pRef = React.createRef();
    
  1407.       p_P1Ref = React.createRef();
    
  1408.       p_P1_C1Ref = React.createRef();
    
  1409.       p_P1_C2Ref = React.createRef();
    
  1410.       p_OneOffRef = React.createRef();
    
  1411. 
    
  1412.       render() {
    
  1413.         return (
    
  1414.           <div ref={this.pRef} id="P">
    
  1415.             <div ref={this.p_P1Ref} id="P_P1">
    
  1416.               <ChildComponent ref={this.p_P1_C1Ref} id="P_P1_C1" />
    
  1417.               <ChildComponent ref={this.p_P1_C2Ref} id="P_P1_C2" />
    
  1418.             </div>
    
  1419.             <div ref={this.p_OneOffRef} id="P_OneOff" />
    
  1420.           </div>
    
  1421.         );
    
  1422.       }
    
  1423.     }
    
  1424. 
    
  1425.     const parent = ReactTestUtils.renderIntoDocument(<ParentComponent />);
    
  1426. 
    
  1427.     const ancestors = [
    
  1428.       // Common ancestor with self is self.
    
  1429.       {
    
  1430.         one: parent.p_P1_C1Ref.current.div1Ref.current,
    
  1431.         two: parent.p_P1_C1Ref.current.div1Ref.current,
    
  1432.         com: parent.p_P1_C1Ref.current.div1Ref.current,
    
  1433.       },
    
  1434.       // Common ancestor with self is self - even if topmost DOM.
    
  1435.       {
    
  1436.         one: parent.pRef.current,
    
  1437.         two: parent.pRef.current,
    
  1438.         com: parent.pRef.current,
    
  1439.       },
    
  1440.       // Siblings
    
  1441.       {
    
  1442.         one: parent.p_P1_C1Ref.current.div1Ref.current,
    
  1443.         two: parent.p_P1_C1Ref.current.div2Ref.current,
    
  1444.         com: parent.p_P1_C1Ref.current.divRef.current,
    
  1445.       },
    
  1446.       // Common ancestor with parent is the parent.
    
  1447.       {
    
  1448.         one: parent.p_P1_C1Ref.current.div1Ref.current,
    
  1449.         two: parent.p_P1_C1Ref.current.divRef.current,
    
  1450.         com: parent.p_P1_C1Ref.current.divRef.current,
    
  1451.       },
    
  1452.       // Common ancestor with grandparent is the grandparent.
    
  1453.       {
    
  1454.         one: parent.p_P1_C1Ref.current.div1Ref.current,
    
  1455.         two: parent.p_P1Ref.current,
    
  1456.         com: parent.p_P1Ref.current,
    
  1457.       },
    
  1458.       // Grandparent across subcomponent boundaries.
    
  1459.       {
    
  1460.         one: parent.p_P1_C1Ref.current.div1Ref.current,
    
  1461.         two: parent.p_P1_C2Ref.current.div1Ref.current,
    
  1462.         com: parent.p_P1Ref.current,
    
  1463.       },
    
  1464.       // Something deep with something one-off.
    
  1465.       {
    
  1466.         one: parent.p_P1_C1Ref.current.div1Ref.current,
    
  1467.         two: parent.p_OneOffRef.current,
    
  1468.         com: parent.pRef.current,
    
  1469.       },
    
  1470.     ];
    
  1471.     let i;
    
  1472.     for (i = 0; i < ancestors.length; i++) {
    
  1473.       const plan = ancestors[i];
    
  1474.       const firstCommon = getLowestCommonAncestor(
    
  1475.         ReactDOMComponentTree.getInstanceFromNode(plan.one),
    
  1476.         ReactDOMComponentTree.getInstanceFromNode(plan.two),
    
  1477.       );
    
  1478.       expect(firstCommon).toBe(
    
  1479.         ReactDOMComponentTree.getInstanceFromNode(plan.com),
    
  1480.       );
    
  1481.     }
    
  1482.   });
    
  1483. });