Best JavaScript code snippet using playwright-internal
ResponderEventPlugin-test.internal.js
Source:ResponderEventPlugin-test.internal.js  
...73      activeTouchObjects,74      changedTouchObjects,75    ),76    topLevelType: topType,77    targetInst: getInstanceFromNode(targetNodeHandle),78  };79};80/**81 * Creates test data for touch events using environment agnostic "node82 * handles".83 *84 * @param {NodeHandle} nodeHandle Environment agnostic handle to DOM node.85 * @param {Array<NodeHandle>} allTouchHandles Encoding of all "touches" in the86 * form of a mapping from integer (touch `identifier`) to touch target. This is87 * encoded in array form. Because of this, it is possible for two separate88 * touches (meaning two separate indices) to have the same touch target ID -89 * this corresponds to real world cases where two separate unique touches have90 * the same target. These touches don't just represent all active touches,91 * rather it also includes any touches that are not active, but are in the92 * process of being removed.93 * @param {Array<NodeHandle>} changedIndices Indices of `allTouchHandles` that94 * have changed.95 * @return {object} Config data used by test cases for extracting responder96 * events.97 */98const startConfig = function(nodeHandle, allTouchHandles, changedIndices) {99  return _touchConfig(100    'topTouchStart',101    nodeHandle,102    allTouchHandles,103    changedIndices,104    nodeHandle,105  );106};107/**108 * @see `startConfig`109 */110const moveConfig = function(nodeHandle, allTouchHandles, changedIndices) {111  return _touchConfig(112    'topTouchMove',113    nodeHandle,114    allTouchHandles,115    changedIndices,116    nodeHandle,117  );118};119/**120 * @see `startConfig`121 */122const endConfig = function(nodeHandle, allTouchHandles, changedIndices) {123  return _touchConfig(124    'topTouchEnd',125    nodeHandle,126    allTouchHandles,127    changedIndices,128    nodeHandle,129  );130};131/**132 * Test config for events that aren't negotiation related, but rather result of133 * a negotiation.134 *135 * Returns object of the form:136 *137 *     {138 *       responderReject: {139 *         // Whatever "readableIDToID" was passed in.140 *         grandParent: {order: NA, assertEvent: null, returnVal: blah},141 *         ...142 *         child: {order: NA, assertEvent: null, returnVal: blah},143 *       }144 *       responderGrant: {145 *         grandParent: {order: NA, assertEvent: null, returnVal: blah},146 *         ...147 *         child: {order: NA, assertEvent: null, returnVal: blah}148 *       }149 *       ...150 *     }151 *152 * After this is created, a test case would configure specific event orderings153 * and optional assertions. Anything left with an `order` of `NA` will be154 * required to never be invoked (the test runner will make sure it throws if155 * ever invoked).156 *157 */158const NA = -1;159const oneEventLoopTestConfig = function(readableIDToID) {160  const ret = {161    // Negotiation162    scrollShouldSetResponder: {bubbled: {}, captured: {}},163    startShouldSetResponder: {bubbled: {}, captured: {}},164    moveShouldSetResponder: {bubbled: {}, captured: {}},165    responderTerminationRequest: {},166    // Non-negotiation167    responderReject: {}, // These do not bubble capture.168    responderGrant: {},169    responderStart: {},170    responderMove: {},171    responderTerminate: {},172    responderEnd: {},173    responderRelease: {},174  };175  for (const eventName in ret) {176    for (const readableNodeName in readableIDToID) {177      if (ret[eventName].bubbled) {178        // Two phase179        ret[eventName].bubbled[readableNodeName] = {180          order: NA,181          assertEvent: null,182          returnVal: undefined,183        };184        ret[eventName].captured[readableNodeName] = {185          order: NA,186          assertEvent: null,187          returnVal: undefined,188        };189      } else {190        ret[eventName][readableNodeName] = {191          order: NA,192          assertEvent: null,193          returnVal: undefined,194        };195      }196    }197  }198  return ret;199};200/**201 * @param {object} eventTestConfig202 * @param {object} readableIDToID203 */204const registerTestHandlers = function(eventTestConfig, readableIDToID) {205  const runs = {dispatchCount: 0};206  const neverFire = function(readableID, registrationName) {207    runs.dispatchCount++;208    expect('').toBe(209      'Event type: ' +210        registrationName +211        '\nShould never occur on:' +212        readableID +213        '\nFor event test config:\n' +214        JSON.stringify(eventTestConfig) +215        '\n',216    );217  };218  const registerOneEventType = function(registrationName, eventTypeTestConfig) {219    for (const readableID in eventTypeTestConfig) {220      const nodeConfig = eventTypeTestConfig[readableID];221      const id = readableIDToID[readableID];222      const handler =223        nodeConfig.order === NA224          ? neverFire.bind(null, readableID, registrationName)225          : // We partially apply readableID and nodeConfig, as they change in the226            // parent closure across iterations.227            function(rID, config, e) {228              expect(229                rID +230                  '->' +231                  registrationName +232                  ' index:' +233                  runs.dispatchCount++,234              ).toBe(rID + '->' + registrationName + ' index:' + config.order);235              if (config.assertEvent) {236                config.assertEvent(e);237              }238              return config.returnVal;239            }.bind(null, readableID, nodeConfig);240      putListener(getInstanceFromNode(id), registrationName, handler);241    }242  };243  for (const eventName in eventTestConfig) {244    const oneEventTypeTestConfig = eventTestConfig[eventName];245    const hasTwoPhase = !!oneEventTypeTestConfig.bubbled;246    if (hasTwoPhase) {247      registerOneEventType(248        ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames249          .bubbled,250        oneEventTypeTestConfig.bubbled,251      );252      registerOneEventType(253        ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames254          .captured,255        oneEventTypeTestConfig.captured,256      );257    } else {258      registerOneEventType(259        ResponderEventPlugin.eventTypes[eventName].registrationName,260        oneEventTypeTestConfig,261      );262    }263  }264  return runs;265};266const run = function(config, hierarchyConfig, nativeEventConfig) {267  let max = NA;268  const searchForMax = function(nodeConfig) {269    for (const readableID in nodeConfig) {270      const order = nodeConfig[readableID].order;271      max = order > max ? order : max;272    }273  };274  for (const eventName in config) {275    const eventConfig = config[eventName];276    if (eventConfig.bubbled) {277      searchForMax(eventConfig.bubbled);278      searchForMax(eventConfig.captured);279    } else {280      searchForMax(eventConfig);281    }282  }283  // Register the handlers284  const runData = registerTestHandlers(config, hierarchyConfig);285  // Trigger the event286  const extractedEvents = ResponderEventPlugin.extractEvents(287    nativeEventConfig.topLevelType,288    nativeEventConfig.targetInst,289    nativeEventConfig.nativeEvent,290    nativeEventConfig.target,291  );292  // At this point the negotiation events have been dispatched as part of the293  // extraction process, but not the side effectful events. Below, we dispatch294  // side effectful events.295  EventPluginHub.runEventsInBatch(extractedEvents, true);296  // Ensure that every event that declared an `order`, was actually dispatched.297  expect('number of events dispatched:' + runData.dispatchCount).toBe(298    'number of events dispatched:' + (max + 1),299  ); // +1 for extra ++300};301const GRANDPARENT_HOST_NODE = {};302const PARENT_HOST_NODE = {};303const CHILD_HOST_NODE = {};304const CHILD_HOST_NODE2 = {};305// These intentionally look like Fibers. ReactTreeTraversal depends on their field names.306// TODO: we could test this with regular DOM nodes (and real fibers) instead.307const GRANDPARENT_INST = {308  return: null,309  tag: HostComponent,310  stateNode: GRANDPARENT_HOST_NODE,311  memoizedProps: {},312};313const PARENT_INST = {314  return: GRANDPARENT_INST,315  tag: HostComponent,316  stateNode: PARENT_HOST_NODE,317  memoizedProps: {},318};319const CHILD_INST = {320  return: PARENT_INST,321  tag: HostComponent,322  stateNode: CHILD_HOST_NODE,323  memoizedProps: {},324};325const CHILD_INST2 = {326  return: PARENT_INST,327  tag: HostComponent,328  stateNode: CHILD_HOST_NODE2,329  memoizedProps: {},330};331GRANDPARENT_HOST_NODE.testInstance = GRANDPARENT_INST;332PARENT_HOST_NODE.testInstance = PARENT_INST;333CHILD_HOST_NODE.testInstance = CHILD_INST;334CHILD_HOST_NODE2.testInstance = CHILD_INST2;335const three = {336  grandParent: GRANDPARENT_HOST_NODE,337  parent: PARENT_HOST_NODE,338  child: CHILD_HOST_NODE,339};340const siblings = {341  parent: PARENT_HOST_NODE,342  childOne: CHILD_HOST_NODE,343  childTwo: CHILD_HOST_NODE2,344};345function getInstanceFromNode(node) {346  return node.testInstance;347}348function getNodeFromInstance(inst) {349  return inst.stateNode;350}351function getFiberCurrentPropsFromNode(node) {352  return node.testInstance.memoizedProps;353}354function putListener(instance, registrationName, handler) {355  instance.memoizedProps[registrationName] = handler;356}357function deleteAllListeners(instance) {358  instance.memoizedProps = {};359}360describe('ResponderEventPlugin', () => {361  beforeEach(() => {362    jest.resetModules();363    const ReactDOM = require('react-dom');364    const ReactDOMUnstableNativeDependencies = require('react-dom/unstable-native-dependencies');365    EventPluginHub =366      ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED367        .EventPluginHub;368    const injectComponentTree =369      ReactDOMUnstableNativeDependencies.injectComponentTree;370    ResponderEventPlugin =371      ReactDOMUnstableNativeDependencies.ResponderEventPlugin;372    deleteAllListeners(GRANDPARENT_INST);373    deleteAllListeners(PARENT_INST);374    deleteAllListeners(CHILD_INST);375    deleteAllListeners(CHILD_INST2);376    injectComponentTree({377      getInstanceFromNode,378      getNodeFromInstance,379      getFiberCurrentPropsFromNode,380    });381  });382  it('should do nothing when no one wants to respond', () => {383    let config = oneEventLoopTestConfig(three);384    config.startShouldSetResponder.captured.grandParent = {385      order: 0,386      returnVal: false,387    };388    config.startShouldSetResponder.captured.parent = {389      order: 1,390      returnVal: false,391    };392    config.startShouldSetResponder.captured.child = {393      order: 2,394      returnVal: false,395    };396    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};397    config.startShouldSetResponder.bubbled.parent = {398      order: 4,399      returnVal: false,400    };401    config.startShouldSetResponder.bubbled.grandParent = {402      order: 5,403      returnVal: false,404    };405    run(config, three, startConfig(three.child, [three.child], [0]));406    expect(ResponderEventPlugin._getResponder()).toBe(null);407    // Now no handlers should be called on `touchEnd`.408    config = oneEventLoopTestConfig(three);409    run(config, three, endConfig(three.child, [three.child], [0]));410    expect(ResponderEventPlugin._getResponder()).toBe(null);411  });412  /**413   * Simple Start Granting414   * --------------------415   */416  it('should grant responder grandParent while capturing', () => {417    let config = oneEventLoopTestConfig(three);418    config.startShouldSetResponder.captured.grandParent = {419      order: 0,420      returnVal: true,421    };422    config.responderGrant.grandParent = {order: 1};423    config.responderStart.grandParent = {order: 2};424    run(config, three, startConfig(three.child, [three.child], [0]));425    expect(ResponderEventPlugin._getResponder()).toBe(426      getInstanceFromNode(three.grandParent),427    );428    config = oneEventLoopTestConfig(three);429    config.responderEnd.grandParent = {order: 0};430    config.responderRelease.grandParent = {order: 1};431    run(config, three, endConfig(three.child, [three.child], [0]));432    expect(ResponderEventPlugin._getResponder()).toBe(null);433  });434  it('should grant responder parent while capturing', () => {435    let config = oneEventLoopTestConfig(three);436    config.startShouldSetResponder.captured.grandParent = {437      order: 0,438      returnVal: false,439    };440    config.startShouldSetResponder.captured.parent = {441      order: 1,442      returnVal: true,443    };444    config.responderGrant.parent = {order: 2};445    config.responderStart.parent = {order: 3};446    run(config, three, startConfig(three.child, [three.child], [0]));447    expect(ResponderEventPlugin._getResponder()).toBe(448      getInstanceFromNode(three.parent),449    );450    config = oneEventLoopTestConfig(three);451    config.responderEnd.parent = {order: 0};452    config.responderRelease.parent = {order: 1};453    run(config, three, endConfig(three.child, [three.child], [0]));454    expect(ResponderEventPlugin._getResponder()).toBe(null);455  });456  it('should grant responder child while capturing', () => {457    let config = oneEventLoopTestConfig(three);458    config.startShouldSetResponder.captured.grandParent = {459      order: 0,460      returnVal: false,461    };462    config.startShouldSetResponder.captured.parent = {463      order: 1,464      returnVal: false,465    };466    config.startShouldSetResponder.captured.child = {order: 2, returnVal: true};467    config.responderGrant.child = {order: 3};468    config.responderStart.child = {order: 4};469    run(config, three, startConfig(three.child, [three.child], [0]));470    expect(ResponderEventPlugin._getResponder()).toBe(471      getInstanceFromNode(three.child),472    );473    config = oneEventLoopTestConfig(three);474    config.responderEnd.child = {order: 0};475    config.responderRelease.child = {order: 1};476    run(config, three, endConfig(three.child, [three.child], [0]));477    expect(ResponderEventPlugin._getResponder()).toBe(null);478  });479  it('should grant responder child while bubbling', () => {480    let config = oneEventLoopTestConfig(three);481    config.startShouldSetResponder.captured.grandParent = {482      order: 0,483      returnVal: false,484    };485    config.startShouldSetResponder.captured.parent = {486      order: 1,487      returnVal: false,488    };489    config.startShouldSetResponder.captured.child = {490      order: 2,491      returnVal: false,492    };493    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};494    config.responderGrant.child = {order: 4};495    config.responderStart.child = {order: 5};496    run(config, three, startConfig(three.child, [three.child], [0]));497    expect(ResponderEventPlugin._getResponder()).toBe(498      getInstanceFromNode(three.child),499    );500    config = oneEventLoopTestConfig(three);501    config.responderEnd.child = {order: 0};502    config.responderRelease.child = {order: 1};503    run(config, three, endConfig(three.child, [three.child], [0]));504    expect(ResponderEventPlugin._getResponder()).toBe(null);505  });506  it('should grant responder parent while bubbling', () => {507    let config = oneEventLoopTestConfig(three);508    config.startShouldSetResponder.captured.grandParent = {509      order: 0,510      returnVal: false,511    };512    config.startShouldSetResponder.captured.parent = {513      order: 1,514      returnVal: false,515    };516    config.startShouldSetResponder.captured.child = {517      order: 2,518      returnVal: false,519    };520    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};521    config.startShouldSetResponder.bubbled.parent = {order: 4, returnVal: true};522    config.responderGrant.parent = {order: 5};523    config.responderStart.parent = {order: 6};524    run(config, three, startConfig(three.child, [three.child], [0]));525    expect(ResponderEventPlugin._getResponder()).toBe(526      getInstanceFromNode(three.parent),527    );528    config = oneEventLoopTestConfig(three);529    config.responderEnd.parent = {order: 0};530    config.responderRelease.parent = {order: 1};531    run(config, three, endConfig(three.child, [three.child], [0]));532    expect(ResponderEventPlugin._getResponder()).toBe(null);533  });534  it('should grant responder grandParent while bubbling', () => {535    let config = oneEventLoopTestConfig(three);536    config.startShouldSetResponder.captured.grandParent = {537      order: 0,538      returnVal: false,539    };540    config.startShouldSetResponder.captured.parent = {541      order: 1,542      returnVal: false,543    };544    config.startShouldSetResponder.captured.child = {545      order: 2,546      returnVal: false,547    };548    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};549    config.startShouldSetResponder.bubbled.parent = {550      order: 4,551      returnVal: false,552    };553    config.startShouldSetResponder.bubbled.grandParent = {554      order: 5,555      returnVal: true,556    };557    config.responderGrant.grandParent = {order: 6};558    config.responderStart.grandParent = {order: 7};559    run(config, three, startConfig(three.child, [three.child], [0]));560    expect(ResponderEventPlugin._getResponder()).toBe(561      getInstanceFromNode(three.grandParent),562    );563    config = oneEventLoopTestConfig(three);564    config.responderEnd.grandParent = {order: 0};565    config.responderRelease.grandParent = {order: 1};566    run(config, three, endConfig(three.child, [three.child], [0]));567    expect(ResponderEventPlugin._getResponder()).toBe(null);568  });569  /**570   * Simple Move Granting571   * --------------------572   */573  it('should grant responder grandParent while capturing move', () => {574    let config = oneEventLoopTestConfig(three);575    config.startShouldSetResponder.captured.grandParent = {order: 0};576    config.startShouldSetResponder.captured.parent = {order: 1};577    config.startShouldSetResponder.captured.child = {order: 2};578    config.startShouldSetResponder.bubbled.child = {order: 3};579    config.startShouldSetResponder.bubbled.parent = {order: 4};580    config.startShouldSetResponder.bubbled.grandParent = {order: 5};581    run(config, three, startConfig(three.child, [three.child], [0]));582    config = oneEventLoopTestConfig(three);583    config.moveShouldSetResponder.captured.grandParent = {584      order: 0,585      returnVal: true,586    };587    config.responderGrant.grandParent = {order: 1};588    config.responderMove.grandParent = {order: 2};589    run(config, three, moveConfig(three.child, [three.child], [0]));590    expect(ResponderEventPlugin._getResponder()).toBe(591      getInstanceFromNode(three.grandParent),592    );593    config = oneEventLoopTestConfig(three);594    config.responderEnd.grandParent = {order: 0};595    config.responderRelease.grandParent = {order: 1};596    run(config, three, endConfig(three.child, [three.child], [0]));597    expect(ResponderEventPlugin._getResponder()).toBe(null);598  });599  it('should grant responder parent while capturing move', () => {600    let config = oneEventLoopTestConfig(three);601    config.startShouldSetResponder.captured.grandParent = {order: 0};602    config.startShouldSetResponder.captured.parent = {order: 1};603    config.startShouldSetResponder.captured.child = {order: 2};604    config.startShouldSetResponder.bubbled.child = {order: 3};605    config.startShouldSetResponder.bubbled.parent = {order: 4};606    config.startShouldSetResponder.bubbled.grandParent = {order: 5};607    run(config, three, startConfig(three.child, [three.child], [0]));608    config = oneEventLoopTestConfig(three);609    config.moveShouldSetResponder.captured.grandParent = {610      order: 0,611      returnVal: false,612    };613    config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: true};614    config.responderGrant.parent = {order: 2};615    config.responderMove.parent = {order: 3};616    run(config, three, moveConfig(three.child, [three.child], [0]));617    expect(ResponderEventPlugin._getResponder()).toBe(618      getInstanceFromNode(three.parent),619    );620    config = oneEventLoopTestConfig(three);621    config.responderEnd.parent = {order: 0};622    config.responderRelease.parent = {order: 1};623    run(config, three, endConfig(three.child, [three.child], [0]));624    expect(ResponderEventPlugin._getResponder()).toBe(null);625  });626  it('should grant responder child while capturing move', () => {627    let config = oneEventLoopTestConfig(three);628    config.startShouldSetResponder.captured.grandParent = {order: 0};629    config.startShouldSetResponder.captured.parent = {order: 1};630    config.startShouldSetResponder.captured.child = {order: 2};631    config.startShouldSetResponder.bubbled.child = {order: 3};632    config.startShouldSetResponder.bubbled.parent = {order: 4};633    config.startShouldSetResponder.bubbled.grandParent = {order: 5};634    run(config, three, startConfig(three.child, [three.child], [0]));635    config = oneEventLoopTestConfig(three);636    config.moveShouldSetResponder.captured.grandParent = {637      order: 0,638      returnVal: false,639    };640    config.moveShouldSetResponder.captured.parent = {641      order: 1,642      returnVal: false,643    };644    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: true};645    config.responderGrant.child = {order: 3};646    config.responderMove.child = {order: 4};647    run(config, three, moveConfig(three.child, [three.child], [0]));648    expect(ResponderEventPlugin._getResponder()).toBe(649      getInstanceFromNode(three.child),650    );651    config = oneEventLoopTestConfig(three);652    config.responderEnd.child = {order: 0};653    config.responderRelease.child = {order: 1};654    run(config, three, endConfig(three.child, [three.child], [0]));655    expect(ResponderEventPlugin._getResponder()).toBe(null);656  });657  it('should grant responder child while bubbling move', () => {658    let config = oneEventLoopTestConfig(three);659    config.startShouldSetResponder.captured.grandParent = {order: 0};660    config.startShouldSetResponder.captured.parent = {order: 1};661    config.startShouldSetResponder.captured.child = {order: 2};662    config.startShouldSetResponder.bubbled.child = {order: 3};663    config.startShouldSetResponder.bubbled.parent = {order: 4};664    config.startShouldSetResponder.bubbled.grandParent = {order: 5};665    run(config, three, startConfig(three.child, [three.child], [0]));666    config = oneEventLoopTestConfig(three);667    config.moveShouldSetResponder.captured.grandParent = {668      order: 0,669      returnVal: false,670    };671    config.moveShouldSetResponder.captured.parent = {672      order: 1,673      returnVal: false,674    };675    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};676    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: true};677    config.responderGrant.child = {order: 4};678    config.responderMove.child = {order: 5};679    run(config, three, moveConfig(three.child, [three.child], [0]));680    expect(ResponderEventPlugin._getResponder()).toBe(681      getInstanceFromNode(three.child),682    );683    config = oneEventLoopTestConfig(three);684    config.responderEnd.child = {order: 0};685    config.responderRelease.child = {order: 1};686    run(config, three, endConfig(three.child, [three.child], [0]));687    expect(ResponderEventPlugin._getResponder()).toBe(null);688  });689  it('should grant responder parent while bubbling move', () => {690    let config = oneEventLoopTestConfig(three);691    config.startShouldSetResponder.captured.grandParent = {order: 0};692    config.startShouldSetResponder.captured.parent = {order: 1};693    config.startShouldSetResponder.captured.child = {order: 2};694    config.startShouldSetResponder.bubbled.child = {order: 3};695    config.startShouldSetResponder.bubbled.parent = {order: 4};696    config.startShouldSetResponder.bubbled.grandParent = {order: 5};697    run(config, three, startConfig(three.child, [three.child], [0]));698    config = oneEventLoopTestConfig(three);699    config.moveShouldSetResponder.captured.grandParent = {700      order: 0,701      returnVal: false,702    };703    config.moveShouldSetResponder.captured.parent = {704      order: 1,705      returnVal: false,706    };707    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};708    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: false};709    config.moveShouldSetResponder.bubbled.parent = {order: 4, returnVal: true};710    config.responderGrant.parent = {order: 5};711    config.responderMove.parent = {order: 6};712    run(config, three, moveConfig(three.child, [three.child], [0]));713    expect(ResponderEventPlugin._getResponder()).toBe(714      getInstanceFromNode(three.parent),715    );716    config = oneEventLoopTestConfig(three);717    config.responderEnd.parent = {order: 0};718    config.responderRelease.parent = {order: 1};719    run(config, three, endConfig(three.child, [three.child], [0]));720    expect(ResponderEventPlugin._getResponder()).toBe(null);721  });722  it('should grant responder grandParent while bubbling move', () => {723    let config = oneEventLoopTestConfig(three);724    config.startShouldSetResponder.captured.grandParent = {order: 0};725    config.startShouldSetResponder.captured.parent = {order: 1};726    config.startShouldSetResponder.captured.child = {order: 2};727    config.startShouldSetResponder.bubbled.child = {order: 3};728    config.startShouldSetResponder.bubbled.parent = {order: 4};729    config.startShouldSetResponder.bubbled.grandParent = {order: 5};730    run(config, three, startConfig(three.child, [three.child], [0]));731    config = oneEventLoopTestConfig(three);732    config.moveShouldSetResponder.captured.grandParent = {733      order: 0,734      returnVal: false,735    };736    config.moveShouldSetResponder.captured.parent = {737      order: 1,738      returnVal: false,739    };740    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};741    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: false};742    config.moveShouldSetResponder.bubbled.parent = {order: 4, returnVal: false};743    config.moveShouldSetResponder.bubbled.grandParent = {744      order: 5,745      returnVal: true,746    };747    config.responderGrant.grandParent = {order: 6};748    config.responderMove.grandParent = {order: 7};749    run(config, three, moveConfig(three.child, [three.child], [0]));750    expect(ResponderEventPlugin._getResponder()).toBe(751      getInstanceFromNode(three.grandParent),752    );753    config = oneEventLoopTestConfig(three);754    config.responderEnd.grandParent = {order: 0};755    config.responderRelease.grandParent = {order: 1};756    run(config, three, endConfig(three.child, [three.child], [0]));757    expect(ResponderEventPlugin._getResponder()).toBe(null);758  });759  /**760   * Common ancestor tests761   * ---------------------762   */763  it('should bubble negotiation to first common ancestor of responder', () => {764    let config = oneEventLoopTestConfig(three);765    config.startShouldSetResponder.captured.grandParent = {766      order: 0,767      returnVal: false,768    };769    config.startShouldSetResponder.captured.parent = {770      order: 1,771      returnVal: true,772    };773    config.responderGrant.parent = {order: 2};774    config.responderStart.parent = {order: 3};775    run(config, three, startConfig(three.child, [three.child], [0]));776    expect(ResponderEventPlugin._getResponder()).toBe(777      getInstanceFromNode(three.parent),778    );779    // While `parent` is still responder, we create new handlers that verify780    // the ordering of propagation, restarting the count at `0`.781    config = oneEventLoopTestConfig(three);782    config.startShouldSetResponder.captured.grandParent = {783      order: 0,784      returnVal: false,785    };786    config.startShouldSetResponder.bubbled.grandParent = {787      order: 1,788      returnVal: false,789    };790    config.responderStart.parent = {order: 2};791    run(config, three, startConfig(three.child, [three.child], [0]));792    expect(ResponderEventPlugin._getResponder()).toBe(793      getInstanceFromNode(three.parent),794    );795    config = oneEventLoopTestConfig(three);796    config.responderEnd.parent = {order: 0};797    config.responderRelease.parent = {order: 1};798    run(config, three, endConfig(three.child, [three.child], [0]));799    expect(ResponderEventPlugin._getResponder()).toBe(null);800  });801  it('should bubble negotiation to first common ancestor of responder then transfer', () => {802    let config = oneEventLoopTestConfig(three);803    config.startShouldSetResponder.captured.grandParent = {804      order: 0,805      returnVal: false,806    };807    config.startShouldSetResponder.captured.parent = {808      order: 1,809      returnVal: true,810    };811    config.responderGrant.parent = {order: 2};812    config.responderStart.parent = {order: 3};813    run(config, three, startConfig(three.child, [three.child], [0]));814    expect(ResponderEventPlugin._getResponder()).toBe(815      getInstanceFromNode(three.parent),816    );817    config = oneEventLoopTestConfig(three);818    // Parent is responder, and responder is transferred by a second touch start819    config.startShouldSetResponder.captured.grandParent = {820      order: 0,821      returnVal: true,822    };823    config.responderGrant.grandParent = {order: 1};824    config.responderTerminationRequest.parent = {order: 2, returnVal: true};825    config.responderTerminate.parent = {order: 3};826    config.responderStart.grandParent = {order: 4};827    run(828      config,829      three,830      startConfig(three.child, [three.child, three.child], [1]),831    );832    expect(ResponderEventPlugin._getResponder()).toBe(833      getInstanceFromNode(three.grandParent),834    );835    config = oneEventLoopTestConfig(three);836    config.responderEnd.grandParent = {order: 0};837    // one remains\ /one ended \838    run(config, three, endConfig(three.child, [three.child, three.child], [1]));839    expect(ResponderEventPlugin._getResponder()).toBe(840      getInstanceFromNode(three.grandParent),841    );842    config = oneEventLoopTestConfig(three);843    config.responderEnd.grandParent = {order: 0};844    config.responderRelease.grandParent = {order: 1};845    run(config, three, endConfig(three.child, [three.child], [0]));846    expect(ResponderEventPlugin._getResponder()).toBe(null);847  });848  /**849   * If nothing is responder, then the negotiation should propagate directly to850   * the deepest target in the second touch.851   */852  it('should negotiate with deepest target on second touch if nothing is responder', () => {853    // Initially nothing wants to become the responder854    let config = oneEventLoopTestConfig(three);855    config.startShouldSetResponder.captured.grandParent = {856      order: 0,857      returnVal: false,858    };859    config.startShouldSetResponder.captured.parent = {860      order: 1,861      returnVal: false,862    };863    config.startShouldSetResponder.bubbled.parent = {864      order: 2,865      returnVal: false,866    };867    config.startShouldSetResponder.bubbled.grandParent = {868      order: 3,869      returnVal: false,870    };871    run(config, three, startConfig(three.parent, [three.parent], [0]));872    expect(ResponderEventPlugin._getResponder()).toBe(null);873    config = oneEventLoopTestConfig(three);874    // Now child wants to become responder. Negotiation should bubble as deep875    // as the target is because we don't find first common ancestor (with876    // current responder) because there is no current responder.877    // (Even if this is the second active touch).878    config.startShouldSetResponder.captured.grandParent = {879      order: 0,880      returnVal: false,881    };882    config.startShouldSetResponder.captured.parent = {883      order: 1,884      returnVal: false,885    };886    config.startShouldSetResponder.captured.child = {887      order: 2,888      returnVal: false,889    };890    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};891    config.responderGrant.child = {order: 4};892    config.responderStart.child = {order: 5};893    //                                     /  Two active touches  \  /one of them new\894    run(895      config,896      three,897      startConfig(three.child, [three.parent, three.child], [1]),898    );899    expect(ResponderEventPlugin._getResponder()).toBe(900      getInstanceFromNode(three.child),901    );902    // Now we remove the original first touch, keeping the second touch that903    // started within the current responder (child). Nothing changes because904    // there's still touches that started inside of the current responder.905    config = oneEventLoopTestConfig(three);906    config.responderEnd.child = {order: 0};907    //                                      / one ended\  /one remains \908    run(909      config,910      three,911      endConfig(three.child, [three.parent, three.child], [0]),912    );913    expect(ResponderEventPlugin._getResponder()).toBe(914      getInstanceFromNode(three.child),915    );916    // Okay, now let's add back that first touch (nothing should change) and917    // then we'll try peeling back the touches in the opposite order to make918    // sure that first removing the second touch instantly causes responder to919    // be released.920    config = oneEventLoopTestConfig(three);921    config.startShouldSetResponder.captured.grandParent = {922      order: 0,923      returnVal: false,924    };925    config.startShouldSetResponder.captured.parent = {926      order: 1,927      returnVal: false,928    };929    config.startShouldSetResponder.bubbled.parent = {930      order: 2,931      returnVal: false,932    };933    config.startShouldSetResponder.bubbled.grandParent = {934      order: 3,935      returnVal: false,936    };937    // Interesting: child still gets moves even though touch target is parent!938    // Current responder gets a `responderStart` for any touch while responder.939    config.responderStart.child = {order: 4};940    //                                           /  Two active touches  \  /one of them new\941    run(942      config,943      three,944      startConfig(three.parent, [three.child, three.parent], [1]),945    );946    expect(ResponderEventPlugin._getResponder()).toBe(947      getInstanceFromNode(three.child),948    );949    // Now, move that new touch that had no effect, and did not start within950    // the current responder.951    config = oneEventLoopTestConfig(three);952    config.moveShouldSetResponder.captured.grandParent = {953      order: 0,954      returnVal: false,955    };956    config.moveShouldSetResponder.captured.parent = {957      order: 1,958      returnVal: false,959    };960    config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: false};961    config.moveShouldSetResponder.bubbled.grandParent = {962      order: 3,963      returnVal: false,964    };965    // Interesting: child still gets moves even though touch target is parent!966    // Current responder gets a `responderMove` for any touch while responder.967    config.responderMove.child = {order: 4};968    //                                     /  Two active touches  \  /one of them moved\969    run(970      config,971      three,972      moveConfig(three.parent, [three.child, three.parent], [1]),973    );974    expect(ResponderEventPlugin._getResponder()).toBe(975      getInstanceFromNode(three.child),976    );977    config = oneEventLoopTestConfig(three);978    config.responderEnd.child = {order: 0};979    config.responderRelease.child = {order: 1};980    //                                        /child end \ /parent remain\981    run(982      config,983      three,984      endConfig(three.child, [three.child, three.parent], [0]),985    );986    expect(ResponderEventPlugin._getResponder()).toBe(null);987  });988  /**989   * If nothing is responder, then the negotiation should propagate directly to990   * the deepest target in the second touch.991   */992  it('should negotiate until first common ancestor when there are siblings', () => {993    // Initially nothing wants to become the responder994    let config = oneEventLoopTestConfig(siblings);995    config.startShouldSetResponder.captured.parent = {996      order: 0,997      returnVal: false,998    };999    config.startShouldSetResponder.captured.childOne = {1000      order: 1,1001      returnVal: false,1002    };1003    config.startShouldSetResponder.bubbled.childOne = {1004      order: 2,1005      returnVal: true,1006    };1007    config.responderGrant.childOne = {order: 3};1008    config.responderStart.childOne = {order: 4};1009    run(1010      config,1011      siblings,1012      startConfig(siblings.childOne, [siblings.childOne], [0]),1013    );1014    expect(ResponderEventPlugin._getResponder()).toBe(1015      getInstanceFromNode(siblings.childOne),1016    );1017    // If the touch target is the sibling item, the negotiation should only1018    // propagate to first common ancestor of current responder and sibling (so1019    // the parent).1020    config = oneEventLoopTestConfig(siblings);1021    config.startShouldSetResponder.captured.parent = {1022      order: 0,1023      returnVal: false,1024    };1025    config.startShouldSetResponder.bubbled.parent = {1026      order: 1,1027      returnVal: false,1028    };1029    config.responderStart.childOne = {order: 2};1030    const touchConfig = startConfig(1031      siblings.childTwo,1032      [siblings.childOne, siblings.childTwo],1033      [1],1034    );1035    run(config, siblings, touchConfig);1036    expect(ResponderEventPlugin._getResponder()).toBe(1037      getInstanceFromNode(siblings.childOne),1038    );1039    // move childOne1040    config = oneEventLoopTestConfig(siblings);1041    config.moveShouldSetResponder.captured.parent = {1042      order: 0,1043      returnVal: false,1044    };1045    config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};1046    config.responderMove.childOne = {order: 2};1047    run(1048      config,1049      siblings,1050      moveConfig(1051        siblings.childOne,1052        [siblings.childOne, siblings.childTwo],1053        [0],1054      ),1055    );1056    expect(ResponderEventPlugin._getResponder()).toBe(1057      getInstanceFromNode(siblings.childOne),1058    );1059    // move childTwo: Only negotiates to `parent`.1060    config = oneEventLoopTestConfig(siblings);1061    config.moveShouldSetResponder.captured.parent = {1062      order: 0,1063      returnVal: false,1064    };1065    config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};1066    config.responderMove.childOne = {order: 2};1067    run(1068      config,1069      siblings,1070      moveConfig(1071        siblings.childTwo,1072        [siblings.childOne, siblings.childTwo],1073        [1],1074      ),1075    );1076    expect(ResponderEventPlugin._getResponder()).toBe(1077      getInstanceFromNode(siblings.childOne),1078    );1079  });1080  it('should notify of being rejected. responderStart/Move happens on current responder', () => {1081    // Initially nothing wants to become the responder1082    let config = oneEventLoopTestConfig(three);1083    config.startShouldSetResponder.captured.grandParent = {1084      order: 0,1085      returnVal: false,1086    };1087    config.startShouldSetResponder.captured.parent = {1088      order: 1,1089      returnVal: false,1090    };1091    config.startShouldSetResponder.captured.child = {1092      order: 2,1093      returnVal: false,1094    };1095    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};1096    config.responderGrant.child = {order: 4};1097    config.responderStart.child = {order: 5};1098    run(config, three, startConfig(three.child, [three.child], [0]));1099    expect(ResponderEventPlugin._getResponder()).toBe(1100      getInstanceFromNode(three.child),1101    );1102    // Suppose parent wants to become responder on move, and is rejected1103    config = oneEventLoopTestConfig(three);1104    config.moveShouldSetResponder.captured.grandParent = {1105      order: 0,1106      returnVal: false,1107    };1108    config.moveShouldSetResponder.captured.parent = {1109      order: 1,1110      returnVal: false,1111    };1112    config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};1113    config.responderGrant.parent = {order: 3};1114    config.responderTerminationRequest.child = {order: 4, returnVal: false};1115    config.responderReject.parent = {order: 5};1116    // The start/move should occur on the original responder if new one is rejected1117    config.responderMove.child = {order: 6};1118    let touchConfig = moveConfig(three.child, [three.child], [0]);1119    run(config, three, touchConfig);1120    expect(ResponderEventPlugin._getResponder()).toBe(1121      getInstanceFromNode(three.child),1122    );1123    config = oneEventLoopTestConfig(three);1124    config.startShouldSetResponder.captured.grandParent = {1125      order: 0,1126      returnVal: false,1127    };1128    config.startShouldSetResponder.captured.parent = {1129      order: 1,1130      returnVal: false,1131    };1132    config.startShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};1133    config.responderGrant.parent = {order: 3};1134    config.responderTerminationRequest.child = {order: 4, returnVal: false};1135    config.responderReject.parent = {order: 5};1136    // The start/move should occur on the original responder if new one is rejected1137    config.responderStart.child = {order: 6};1138    touchConfig = startConfig(three.child, [three.child, three.child], [1]);1139    run(config, three, touchConfig);1140    expect(ResponderEventPlugin._getResponder()).toBe(1141      getInstanceFromNode(three.child),1142    );1143  });1144  it('should negotiate scroll', () => {1145    // Initially nothing wants to become the responder1146    let config = oneEventLoopTestConfig(three);1147    config.startShouldSetResponder.captured.grandParent = {1148      order: 0,1149      returnVal: false,1150    };1151    config.startShouldSetResponder.captured.parent = {1152      order: 1,1153      returnVal: false,1154    };1155    config.startShouldSetResponder.captured.child = {1156      order: 2,1157      returnVal: false,1158    };1159    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};1160    config.responderGrant.child = {order: 4};1161    config.responderStart.child = {order: 5};1162    run(config, three, startConfig(three.child, [three.child], [0]));1163    expect(ResponderEventPlugin._getResponder()).toBe(1164      getInstanceFromNode(three.child),1165    );1166    // If the touch target is the sibling item, the negotiation should only1167    // propagate to first common ancestor of current responder and sibling (so1168    // the parent).1169    config = oneEventLoopTestConfig(three);1170    config.scrollShouldSetResponder.captured.grandParent = {1171      order: 0,1172      returnVal: false,1173    };1174    config.scrollShouldSetResponder.captured.parent = {1175      order: 1,1176      returnVal: false,1177    };1178    config.scrollShouldSetResponder.bubbled.parent = {1179      order: 2,1180      returnVal: true,1181    };1182    config.responderGrant.parent = {order: 3};1183    config.responderTerminationRequest.child = {order: 4, returnVal: false};1184    config.responderReject.parent = {order: 5};1185    run(config, three, {1186      topLevelType: 'topScroll',1187      targetInst: getInstanceFromNode(three.parent),1188      nativeEvent: {},1189    });1190    expect(ResponderEventPlugin._getResponder()).toBe(1191      getInstanceFromNode(three.child),1192    );1193    // Now lets let the scroll take control this time.1194    config = oneEventLoopTestConfig(three);1195    config.scrollShouldSetResponder.captured.grandParent = {1196      order: 0,1197      returnVal: false,1198    };1199    config.scrollShouldSetResponder.captured.parent = {1200      order: 1,1201      returnVal: false,1202    };1203    config.scrollShouldSetResponder.bubbled.parent = {1204      order: 2,1205      returnVal: true,1206    };1207    config.responderGrant.parent = {order: 3};1208    config.responderTerminationRequest.child = {order: 4, returnVal: true};1209    config.responderTerminate.child = {order: 5};1210    run(config, three, {1211      topLevelType: 'topScroll',1212      targetInst: getInstanceFromNode(three.parent),1213      nativeEvent: {},1214    });1215    expect(ResponderEventPlugin._getResponder()).toBe(1216      getInstanceFromNode(three.parent),1217    );1218  });1219  it('should cancel correctly', () => {1220    // Initially our child becomes responder1221    let config = oneEventLoopTestConfig(three);1222    config.startShouldSetResponder.captured.grandParent = {1223      order: 0,1224      returnVal: false,1225    };1226    config.startShouldSetResponder.captured.parent = {1227      order: 1,1228      returnVal: false,1229    };1230    config.startShouldSetResponder.captured.child = {1231      order: 2,1232      returnVal: false,1233    };1234    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};1235    config.responderGrant.child = {order: 4};1236    config.responderStart.child = {order: 5};1237    run(config, three, startConfig(three.child, [three.child], [0]));1238    expect(ResponderEventPlugin._getResponder()).toBe(1239      getInstanceFromNode(three.child),1240    );1241    config = oneEventLoopTestConfig(three);1242    config.responderEnd.child = {order: 0};1243    config.responderTerminate.child = {order: 1};1244    const nativeEvent = _touchConfig(1245      'topTouchCancel',1246      three.child,1247      [three.child],1248      [0],1249    );1250    run(config, three, nativeEvent);1251    expect(ResponderEventPlugin._getResponder()).toBe(null);1252  });1253  it('should determine the first common ancestor correctly', () => {1254    // This test was moved here from the ReactTreeTraversal test since only the1255    // ResponderEventPlugin uses `getLowestCommonAncestor`1256    const React = require('react');1257    const ReactTestUtils = require('react-dom/test-utils');1258    const ReactTreeTraversal = require('shared/ReactTreeTraversal');1259    const ReactDOMComponentTree = require('../../react-dom/src/client/ReactDOMComponentTree');1260    class ChildComponent extends React.Component {1261      render() {1262        return (1263          <div ref="DIV" id={this.props.id + '__DIV'}>1264            <div ref="DIV_1" id={this.props.id + '__DIV_1'} />1265            <div ref="DIV_2" id={this.props.id + '__DIV_2'} />1266          </div>1267        );1268      }1269    }1270    class ParentComponent extends React.Component {1271      render() {1272        return (1273          <div ref="P" id="P">1274            <div ref="P_P1" id="P_P1">1275              <ChildComponent ref="P_P1_C1" id="P_P1_C1" />1276              <ChildComponent ref="P_P1_C2" id="P_P1_C2" />1277            </div>1278            <div ref="P_OneOff" id="P_OneOff" />1279          </div>1280        );1281      }1282    }1283    const parent = ReactTestUtils.renderIntoDocument(<ParentComponent />);1284    const ancestors = [1285      // Common ancestor with self is self.1286      {1287        one: parent.refs.P_P1_C1.refs.DIV_1,1288        two: parent.refs.P_P1_C1.refs.DIV_1,1289        com: parent.refs.P_P1_C1.refs.DIV_1,1290      },1291      // Common ancestor with self is self - even if topmost DOM.1292      {one: parent.refs.P, two: parent.refs.P, com: parent.refs.P},1293      // Siblings1294      {1295        one: parent.refs.P_P1_C1.refs.DIV_1,1296        two: parent.refs.P_P1_C1.refs.DIV_2,1297        com: parent.refs.P_P1_C1.refs.DIV,1298      },1299      // Common ancestor with parent is the parent.1300      {1301        one: parent.refs.P_P1_C1.refs.DIV_1,1302        two: parent.refs.P_P1_C1.refs.DIV,1303        com: parent.refs.P_P1_C1.refs.DIV,1304      },1305      // Common ancestor with grandparent is the grandparent.1306      {1307        one: parent.refs.P_P1_C1.refs.DIV_1,1308        two: parent.refs.P_P1,1309        com: parent.refs.P_P1,1310      },1311      // Grandparent across subcomponent boundaries.1312      {1313        one: parent.refs.P_P1_C1.refs.DIV_1,1314        two: parent.refs.P_P1_C2.refs.DIV_1,1315        com: parent.refs.P_P1,1316      },1317      // Something deep with something one-off.1318      {1319        one: parent.refs.P_P1_C1.refs.DIV_1,1320        two: parent.refs.P_OneOff,1321        com: parent.refs.P,1322      },1323    ];1324    let i;1325    for (i = 0; i < ancestors.length; i++) {1326      const plan = ancestors[i];1327      const firstCommon = ReactTreeTraversal.getLowestCommonAncestor(1328        ReactDOMComponentTree.getInstanceFromNode(plan.one),1329        ReactDOMComponentTree.getInstanceFromNode(plan.two),1330      );1331      expect(firstCommon).toBe(1332        ReactDOMComponentTree.getInstanceFromNode(plan.com),1333      );1334    }1335  });...ResponderEventPlugin-test.js
Source:ResponderEventPlugin-test.js  
...74      activeTouchObjects,75      changedTouchObjects,76    ),77    topLevelType: topType,78    targetInst: getInstanceFromNode(targetNodeHandle),79  };80};81/**82 * Creates test data for touch events using environment agnostic "node83 * handles".84 *85 * @param {NodeHandle} nodeHandle Environment agnostic handle to DOM node.86 * @param {Array<NodeHandle>} allTouchHandles Encoding of all "touches" in the87 * form of a mapping from integer (touch `identifier`) to touch target. This is88 * encoded in array form. Because of this, it is possible for two separate89 * touches (meaning two separate indices) to have the same touch target ID -90 * this corresponds to real world cases where two separate unique touches have91 * the same target. These touches don't just represent all active touches,92 * rather it also includes any touches that are not active, but are in the93 * process of being removed.94 * @param {Array<NodeHandle>} changedIndices Indices of `allTouchHandles` that95 * have changed.96 * @return {object} Config data used by test cases for extracting responder97 * events.98 */99var startConfig = function(nodeHandle, allTouchHandles, changedIndices) {100  return _touchConfig(101    'topTouchStart',102    nodeHandle,103    allTouchHandles,104    changedIndices,105    nodeHandle,106  );107};108/**109 * @see `startConfig`110 */111var moveConfig = function(nodeHandle, allTouchHandles, changedIndices) {112  return _touchConfig(113    'topTouchMove',114    nodeHandle,115    allTouchHandles,116    changedIndices,117    nodeHandle,118  );119};120/**121 * @see `startConfig`122 */123var endConfig = function(nodeHandle, allTouchHandles, changedIndices) {124  return _touchConfig(125    'topTouchEnd',126    nodeHandle,127    allTouchHandles,128    changedIndices,129    nodeHandle,130  );131};132/**133 * Test config for events that aren't negotiation related, but rather result of134 * a negotiation.135 *136 * Returns object of the form:137 *138 *     {139 *       responderReject: {140 *         // Whatever "readableIDToID" was passed in.141 *         grandParent: {order: NA, assertEvent: null, returnVal: blah},142 *         ...143 *         child: {order: NA, assertEvent: null, returnVal: blah},144 *       }145 *       responderGrant: {146 *         grandParent: {order: NA, assertEvent: null, returnVal: blah},147 *         ...148 *         child: {order: NA, assertEvent: null, returnVal: blah}149 *       }150 *       ...151 *     }152 *153 * After this is created, a test case would configure specific event orderings154 * and optional assertions. Anything left with an `order` of `NA` will be155 * required to never be invoked (the test runner will make sure it throws if156 * ever invoked).157 *158 */159var NA = -1;160var oneEventLoopTestConfig = function(readableIDToID) {161  var ret = {162    // Negotiation163    scrollShouldSetResponder: {bubbled: {}, captured: {}},164    startShouldSetResponder: {bubbled: {}, captured: {}},165    moveShouldSetResponder: {bubbled: {}, captured: {}},166    responderTerminationRequest: {},167    // Non-negotiation168    responderReject: {}, // These do not bubble capture.169    responderGrant: {},170    responderStart: {},171    responderMove: {},172    responderTerminate: {},173    responderEnd: {},174    responderRelease: {},175  };176  for (var eventName in ret) {177    for (var readableNodeName in readableIDToID) {178      if (ret[eventName].bubbled) {179        // Two phase180        ret[eventName].bubbled[readableNodeName] = {181          order: NA,182          assertEvent: null,183          returnVal: undefined,184        };185        ret[eventName].captured[readableNodeName] = {186          order: NA,187          assertEvent: null,188          returnVal: undefined,189        };190      } else {191        ret[eventName][readableNodeName] = {192          order: NA,193          assertEvent: null,194          returnVal: undefined,195        };196      }197    }198  }199  return ret;200};201/**202 * @param {object} eventTestConfig203 * @param {object} readableIDToID204 */205var registerTestHandlers = function(eventTestConfig, readableIDToID) {206  var runs = {dispatchCount: 0};207  var neverFire = function(readableID, registrationName) {208    runs.dispatchCount++;209    expect('').toBe(210      'Event type: ' +211        registrationName +212        '\nShould never occur on:' +213        readableID +214        '\nFor event test config:\n' +215        JSON.stringify(eventTestConfig) +216        '\n',217    );218  };219  var registerOneEventType = function(registrationName, eventTypeTestConfig) {220    for (var readableID in eventTypeTestConfig) {221      var nodeConfig = eventTypeTestConfig[readableID];222      var id = readableIDToID[readableID];223      var handler = nodeConfig.order === NA224        ? neverFire.bind(null, readableID, registrationName)225        : // We partially apply readableID and nodeConfig, as they change in the226          // parent closure across iterations.227          function(rID, config, e) {228            expect(229              rID + '->' + registrationName + ' index:' + runs.dispatchCount++,230            ).toBe(rID + '->' + registrationName + ' index:' + config.order);231            if (config.assertEvent) {232              config.assertEvent(e);233            }234            return config.returnVal;235          }.bind(null, readableID, nodeConfig);236      putListener(getInstanceFromNode(id), registrationName, handler);237    }238  };239  for (var eventName in eventTestConfig) {240    var oneEventTypeTestConfig = eventTestConfig[eventName];241    var hasTwoPhase = !!oneEventTypeTestConfig.bubbled;242    if (hasTwoPhase) {243      registerOneEventType(244        ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames245          .bubbled,246        oneEventTypeTestConfig.bubbled,247      );248      registerOneEventType(249        ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames250          .captured,251        oneEventTypeTestConfig.captured,252      );253    } else {254      registerOneEventType(255        ResponderEventPlugin.eventTypes[eventName].registrationName,256        oneEventTypeTestConfig,257      );258    }259  }260  return runs;261};262var run = function(config, hierarchyConfig, nativeEventConfig) {263  var max = NA;264  var searchForMax = function(nodeConfig) {265    for (var readableID in nodeConfig) {266      var order = nodeConfig[readableID].order;267      max = order > max ? order : max;268    }269  };270  for (var eventName in config) {271    var eventConfig = config[eventName];272    if (eventConfig.bubbled) {273      searchForMax(eventConfig.bubbled);274      searchForMax(eventConfig.captured);275    } else {276      searchForMax(eventConfig);277    }278  }279  // Register the handlers280  var runData = registerTestHandlers(config, hierarchyConfig);281  // Trigger the event282  var extractedEvents = ResponderEventPlugin.extractEvents(283    nativeEventConfig.topLevelType,284    nativeEventConfig.targetInst,285    nativeEventConfig.nativeEvent,286    nativeEventConfig.target,287  );288  // At this point the negotiation events have been dispatched as part of the289  // extraction process, but not the side effectful events. Below, we dispatch290  // side effectful events.291  EventPluginHub.enqueueEvents(extractedEvents);292  EventPluginHub.processEventQueue(true);293  // Ensure that every event that declared an `order`, was actually dispatched.294  expect('number of events dispatched:' + runData.dispatchCount).toBe(295    'number of events dispatched:' + (max + 1),296  ); // +1 for extra ++297};298var GRANDPARENT_HOST_NODE = {};299var PARENT_HOST_NODE = {};300var CHILD_HOST_NODE = {};301var CHILD_HOST_NODE2 = {};302var GRANDPARENT_INST = {303  _hostParent: null,304  _rootNodeID: '1',305  _hostNode: GRANDPARENT_HOST_NODE,306  _currentElement: {props: {}},307};308var PARENT_INST = {309  _hostParent: GRANDPARENT_INST,310  _rootNodeID: '2',311  _hostNode: PARENT_HOST_NODE,312  _currentElement: {props: {}},313};314var CHILD_INST = {315  _hostParent: PARENT_INST,316  _rootNodeID: '3',317  _hostNode: CHILD_HOST_NODE,318  _currentElement: {props: {}},319};320var CHILD_INST2 = {321  _hostParent: PARENT_INST,322  _rootNodeID: '4',323  _hostNode: CHILD_HOST_NODE2,324  _currentElement: {props: {}},325};326GRANDPARENT_HOST_NODE._reactInstance = GRANDPARENT_INST;327PARENT_HOST_NODE._reactInstance = PARENT_INST;328CHILD_HOST_NODE._reactInstance = CHILD_INST;329CHILD_HOST_NODE2._reactInstance = CHILD_INST2;330var three = {331  grandParent: GRANDPARENT_HOST_NODE,332  parent: PARENT_HOST_NODE,333  child: CHILD_HOST_NODE,334};335var siblings = {336  parent: PARENT_HOST_NODE,337  childOne: CHILD_HOST_NODE,338  childTwo: CHILD_HOST_NODE2,339};340function getInstanceFromNode(node) {341  return node._reactInstance;342}343function getNodeFromInstance(inst) {344  return inst._hostNode;345}346function putListener(node, registrationName, handler) {347  node._currentElement.props[registrationName] = handler;348}349function deleteAllListeners(node) {350  node._currentElement.props = {};351}352describe('ResponderEventPlugin', () => {353  beforeEach(() => {354    jest.resetModules();355    EventPluginHub = require('EventPluginHub');356    EventPluginUtils = require('EventPluginUtils');357    ResponderEventPlugin = require('ResponderEventPlugin');358    deleteAllListeners(GRANDPARENT_INST);359    deleteAllListeners(PARENT_INST);360    deleteAllListeners(CHILD_INST);361    deleteAllListeners(CHILD_INST2);362    EventPluginUtils.injection.injectComponentTree({363      getInstanceFromNode,364      getNodeFromInstance,365    });366  });367  it('should do nothing when no one wants to respond', () => {368    var config = oneEventLoopTestConfig(three);369    config.startShouldSetResponder.captured.grandParent = {370      order: 0,371      returnVal: false,372    };373    config.startShouldSetResponder.captured.parent = {374      order: 1,375      returnVal: false,376    };377    config.startShouldSetResponder.captured.child = {378      order: 2,379      returnVal: false,380    };381    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};382    config.startShouldSetResponder.bubbled.parent = {383      order: 4,384      returnVal: false,385    };386    config.startShouldSetResponder.bubbled.grandParent = {387      order: 5,388      returnVal: false,389    };390    run(config, three, startConfig(three.child, [three.child], [0]));391    expect(ResponderEventPlugin._getResponder()).toBe(null);392    // Now no handlers should be called on `touchEnd`.393    config = oneEventLoopTestConfig(three);394    run(config, three, endConfig(three.child, [three.child], [0]));395    expect(ResponderEventPlugin._getResponder()).toBe(null);396  });397  /**398   * Simple Start Granting399   * --------------------400   */401  it('should grant responder grandParent while capturing', () => {402    var config = oneEventLoopTestConfig(three);403    config.startShouldSetResponder.captured.grandParent = {404      order: 0,405      returnVal: true,406    };407    config.responderGrant.grandParent = {order: 1};408    config.responderStart.grandParent = {order: 2};409    run(config, three, startConfig(three.child, [three.child], [0]));410    expect(ResponderEventPlugin._getResponder()).toBe(411      getInstanceFromNode(three.grandParent),412    );413    config = oneEventLoopTestConfig(three);414    config.responderEnd.grandParent = {order: 0};415    config.responderRelease.grandParent = {order: 1};416    run(config, three, endConfig(three.child, [three.child], [0]));417    expect(ResponderEventPlugin._getResponder()).toBe(null);418  });419  it('should grant responder parent while capturing', () => {420    var config = oneEventLoopTestConfig(three);421    config.startShouldSetResponder.captured.grandParent = {422      order: 0,423      returnVal: false,424    };425    config.startShouldSetResponder.captured.parent = {426      order: 1,427      returnVal: true,428    };429    config.responderGrant.parent = {order: 2};430    config.responderStart.parent = {order: 3};431    run(config, three, startConfig(three.child, [three.child], [0]));432    expect(ResponderEventPlugin._getResponder()).toBe(433      getInstanceFromNode(three.parent),434    );435    config = oneEventLoopTestConfig(three);436    config.responderEnd.parent = {order: 0};437    config.responderRelease.parent = {order: 1};438    run(config, three, endConfig(three.child, [three.child], [0]));439    expect(ResponderEventPlugin._getResponder()).toBe(null);440  });441  it('should grant responder child while capturing', () => {442    var config = oneEventLoopTestConfig(three);443    config.startShouldSetResponder.captured.grandParent = {444      order: 0,445      returnVal: false,446    };447    config.startShouldSetResponder.captured.parent = {448      order: 1,449      returnVal: false,450    };451    config.startShouldSetResponder.captured.child = {order: 2, returnVal: true};452    config.responderGrant.child = {order: 3};453    config.responderStart.child = {order: 4};454    run(config, three, startConfig(three.child, [three.child], [0]));455    expect(ResponderEventPlugin._getResponder()).toBe(456      getInstanceFromNode(three.child),457    );458    config = oneEventLoopTestConfig(three);459    config.responderEnd.child = {order: 0};460    config.responderRelease.child = {order: 1};461    run(config, three, endConfig(three.child, [three.child], [0]));462    expect(ResponderEventPlugin._getResponder()).toBe(null);463  });464  it('should grant responder child while bubbling', () => {465    var config = oneEventLoopTestConfig(three);466    config.startShouldSetResponder.captured.grandParent = {467      order: 0,468      returnVal: false,469    };470    config.startShouldSetResponder.captured.parent = {471      order: 1,472      returnVal: false,473    };474    config.startShouldSetResponder.captured.child = {475      order: 2,476      returnVal: false,477    };478    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};479    config.responderGrant.child = {order: 4};480    config.responderStart.child = {order: 5};481    run(config, three, startConfig(three.child, [three.child], [0]));482    expect(ResponderEventPlugin._getResponder()).toBe(483      getInstanceFromNode(three.child),484    );485    config = oneEventLoopTestConfig(three);486    config.responderEnd.child = {order: 0};487    config.responderRelease.child = {order: 1};488    run(config, three, endConfig(three.child, [three.child], [0]));489    expect(ResponderEventPlugin._getResponder()).toBe(null);490  });491  it('should grant responder parent while bubbling', () => {492    var config = oneEventLoopTestConfig(three);493    config.startShouldSetResponder.captured.grandParent = {494      order: 0,495      returnVal: false,496    };497    config.startShouldSetResponder.captured.parent = {498      order: 1,499      returnVal: false,500    };501    config.startShouldSetResponder.captured.child = {502      order: 2,503      returnVal: false,504    };505    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};506    config.startShouldSetResponder.bubbled.parent = {order: 4, returnVal: true};507    config.responderGrant.parent = {order: 5};508    config.responderStart.parent = {order: 6};509    run(config, three, startConfig(three.child, [three.child], [0]));510    expect(ResponderEventPlugin._getResponder()).toBe(511      getInstanceFromNode(three.parent),512    );513    config = oneEventLoopTestConfig(three);514    config.responderEnd.parent = {order: 0};515    config.responderRelease.parent = {order: 1};516    run(config, three, endConfig(three.child, [three.child], [0]));517    expect(ResponderEventPlugin._getResponder()).toBe(null);518  });519  it('should grant responder grandParent while bubbling', () => {520    var config = oneEventLoopTestConfig(three);521    config.startShouldSetResponder.captured.grandParent = {522      order: 0,523      returnVal: false,524    };525    config.startShouldSetResponder.captured.parent = {526      order: 1,527      returnVal: false,528    };529    config.startShouldSetResponder.captured.child = {530      order: 2,531      returnVal: false,532    };533    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};534    config.startShouldSetResponder.bubbled.parent = {535      order: 4,536      returnVal: false,537    };538    config.startShouldSetResponder.bubbled.grandParent = {539      order: 5,540      returnVal: true,541    };542    config.responderGrant.grandParent = {order: 6};543    config.responderStart.grandParent = {order: 7};544    run(config, three, startConfig(three.child, [three.child], [0]));545    expect(ResponderEventPlugin._getResponder()).toBe(546      getInstanceFromNode(three.grandParent),547    );548    config = oneEventLoopTestConfig(three);549    config.responderEnd.grandParent = {order: 0};550    config.responderRelease.grandParent = {order: 1};551    run(config, three, endConfig(three.child, [three.child], [0]));552    expect(ResponderEventPlugin._getResponder()).toBe(null);553  });554  /**555   * Simple Move Granting556   * --------------------557   */558  it('should grant responder grandParent while capturing move', () => {559    var config = oneEventLoopTestConfig(three);560    config.startShouldSetResponder.captured.grandParent = {order: 0};561    config.startShouldSetResponder.captured.parent = {order: 1};562    config.startShouldSetResponder.captured.child = {order: 2};563    config.startShouldSetResponder.bubbled.child = {order: 3};564    config.startShouldSetResponder.bubbled.parent = {order: 4};565    config.startShouldSetResponder.bubbled.grandParent = {order: 5};566    run(config, three, startConfig(three.child, [three.child], [0]));567    config = oneEventLoopTestConfig(three);568    config.moveShouldSetResponder.captured.grandParent = {569      order: 0,570      returnVal: true,571    };572    config.responderGrant.grandParent = {order: 1};573    config.responderMove.grandParent = {order: 2};574    run(config, three, moveConfig(three.child, [three.child], [0]));575    expect(ResponderEventPlugin._getResponder()).toBe(576      getInstanceFromNode(three.grandParent),577    );578    config = oneEventLoopTestConfig(three);579    config.responderEnd.grandParent = {order: 0};580    config.responderRelease.grandParent = {order: 1};581    run(config, three, endConfig(three.child, [three.child], [0]));582    expect(ResponderEventPlugin._getResponder()).toBe(null);583  });584  it('should grant responder parent while capturing move', () => {585    var config = oneEventLoopTestConfig(three);586    config.startShouldSetResponder.captured.grandParent = {order: 0};587    config.startShouldSetResponder.captured.parent = {order: 1};588    config.startShouldSetResponder.captured.child = {order: 2};589    config.startShouldSetResponder.bubbled.child = {order: 3};590    config.startShouldSetResponder.bubbled.parent = {order: 4};591    config.startShouldSetResponder.bubbled.grandParent = {order: 5};592    run(config, three, startConfig(three.child, [three.child], [0]));593    config = oneEventLoopTestConfig(three);594    config.moveShouldSetResponder.captured.grandParent = {595      order: 0,596      returnVal: false,597    };598    config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: true};599    config.responderGrant.parent = {order: 2};600    config.responderMove.parent = {order: 3};601    run(config, three, moveConfig(three.child, [three.child], [0]));602    expect(ResponderEventPlugin._getResponder()).toBe(603      getInstanceFromNode(three.parent),604    );605    config = oneEventLoopTestConfig(three);606    config.responderEnd.parent = {order: 0};607    config.responderRelease.parent = {order: 1};608    run(config, three, endConfig(three.child, [three.child], [0]));609    expect(ResponderEventPlugin._getResponder()).toBe(null);610  });611  it('should grant responder child while capturing move', () => {612    var config = oneEventLoopTestConfig(three);613    config.startShouldSetResponder.captured.grandParent = {order: 0};614    config.startShouldSetResponder.captured.parent = {order: 1};615    config.startShouldSetResponder.captured.child = {order: 2};616    config.startShouldSetResponder.bubbled.child = {order: 3};617    config.startShouldSetResponder.bubbled.parent = {order: 4};618    config.startShouldSetResponder.bubbled.grandParent = {order: 5};619    run(config, three, startConfig(three.child, [three.child], [0]));620    config = oneEventLoopTestConfig(three);621    config.moveShouldSetResponder.captured.grandParent = {622      order: 0,623      returnVal: false,624    };625    config.moveShouldSetResponder.captured.parent = {626      order: 1,627      returnVal: false,628    };629    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: true};630    config.responderGrant.child = {order: 3};631    config.responderMove.child = {order: 4};632    run(config, three, moveConfig(three.child, [three.child], [0]));633    expect(ResponderEventPlugin._getResponder()).toBe(634      getInstanceFromNode(three.child),635    );636    config = oneEventLoopTestConfig(three);637    config.responderEnd.child = {order: 0};638    config.responderRelease.child = {order: 1};639    run(config, three, endConfig(three.child, [three.child], [0]));640    expect(ResponderEventPlugin._getResponder()).toBe(null);641  });642  it('should grant responder child while bubbling move', () => {643    var config = oneEventLoopTestConfig(three);644    config.startShouldSetResponder.captured.grandParent = {order: 0};645    config.startShouldSetResponder.captured.parent = {order: 1};646    config.startShouldSetResponder.captured.child = {order: 2};647    config.startShouldSetResponder.bubbled.child = {order: 3};648    config.startShouldSetResponder.bubbled.parent = {order: 4};649    config.startShouldSetResponder.bubbled.grandParent = {order: 5};650    run(config, three, startConfig(three.child, [three.child], [0]));651    config = oneEventLoopTestConfig(three);652    config.moveShouldSetResponder.captured.grandParent = {653      order: 0,654      returnVal: false,655    };656    config.moveShouldSetResponder.captured.parent = {657      order: 1,658      returnVal: false,659    };660    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};661    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: true};662    config.responderGrant.child = {order: 4};663    config.responderMove.child = {order: 5};664    run(config, three, moveConfig(three.child, [three.child], [0]));665    expect(ResponderEventPlugin._getResponder()).toBe(666      getInstanceFromNode(three.child),667    );668    config = oneEventLoopTestConfig(three);669    config.responderEnd.child = {order: 0};670    config.responderRelease.child = {order: 1};671    run(config, three, endConfig(three.child, [three.child], [0]));672    expect(ResponderEventPlugin._getResponder()).toBe(null);673  });674  it('should grant responder parent while bubbling move', () => {675    var config = oneEventLoopTestConfig(three);676    config.startShouldSetResponder.captured.grandParent = {order: 0};677    config.startShouldSetResponder.captured.parent = {order: 1};678    config.startShouldSetResponder.captured.child = {order: 2};679    config.startShouldSetResponder.bubbled.child = {order: 3};680    config.startShouldSetResponder.bubbled.parent = {order: 4};681    config.startShouldSetResponder.bubbled.grandParent = {order: 5};682    run(config, three, startConfig(three.child, [three.child], [0]));683    config = oneEventLoopTestConfig(three);684    config.moveShouldSetResponder.captured.grandParent = {685      order: 0,686      returnVal: false,687    };688    config.moveShouldSetResponder.captured.parent = {689      order: 1,690      returnVal: false,691    };692    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};693    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: false};694    config.moveShouldSetResponder.bubbled.parent = {order: 4, returnVal: true};695    config.responderGrant.parent = {order: 5};696    config.responderMove.parent = {order: 6};697    run(config, three, moveConfig(three.child, [three.child], [0]));698    expect(ResponderEventPlugin._getResponder()).toBe(699      getInstanceFromNode(three.parent),700    );701    config = oneEventLoopTestConfig(three);702    config.responderEnd.parent = {order: 0};703    config.responderRelease.parent = {order: 1};704    run(config, three, endConfig(three.child, [three.child], [0]));705    expect(ResponderEventPlugin._getResponder()).toBe(null);706  });707  it('should grant responder grandParent while bubbling move', () => {708    var config = oneEventLoopTestConfig(three);709    config.startShouldSetResponder.captured.grandParent = {order: 0};710    config.startShouldSetResponder.captured.parent = {order: 1};711    config.startShouldSetResponder.captured.child = {order: 2};712    config.startShouldSetResponder.bubbled.child = {order: 3};713    config.startShouldSetResponder.bubbled.parent = {order: 4};714    config.startShouldSetResponder.bubbled.grandParent = {order: 5};715    run(config, three, startConfig(three.child, [three.child], [0]));716    config = oneEventLoopTestConfig(three);717    config.moveShouldSetResponder.captured.grandParent = {718      order: 0,719      returnVal: false,720    };721    config.moveShouldSetResponder.captured.parent = {722      order: 1,723      returnVal: false,724    };725    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};726    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: false};727    config.moveShouldSetResponder.bubbled.parent = {order: 4, returnVal: false};728    config.moveShouldSetResponder.bubbled.grandParent = {729      order: 5,730      returnVal: true,731    };732    config.responderGrant.grandParent = {order: 6};733    config.responderMove.grandParent = {order: 7};734    run(config, three, moveConfig(three.child, [three.child], [0]));735    expect(ResponderEventPlugin._getResponder()).toBe(736      getInstanceFromNode(three.grandParent),737    );738    config = oneEventLoopTestConfig(three);739    config.responderEnd.grandParent = {order: 0};740    config.responderRelease.grandParent = {order: 1};741    run(config, three, endConfig(three.child, [three.child], [0]));742    expect(ResponderEventPlugin._getResponder()).toBe(null);743  });744  /**745   * Common ancestor tests746   * ---------------------747   */748  it('should bubble negotiation to first common ancestor of responder', () => {749    var config = oneEventLoopTestConfig(three);750    config.startShouldSetResponder.captured.grandParent = {751      order: 0,752      returnVal: false,753    };754    config.startShouldSetResponder.captured.parent = {755      order: 1,756      returnVal: true,757    };758    config.responderGrant.parent = {order: 2};759    config.responderStart.parent = {order: 3};760    run(config, three, startConfig(three.child, [three.child], [0]));761    expect(ResponderEventPlugin._getResponder()).toBe(762      getInstanceFromNode(three.parent),763    );764    // While `parent` is still responder, we create new handlers that verify765    // the ordering of propagation, restarting the count at `0`.766    config = oneEventLoopTestConfig(three);767    config.startShouldSetResponder.captured.grandParent = {768      order: 0,769      returnVal: false,770    };771    config.startShouldSetResponder.bubbled.grandParent = {772      order: 1,773      returnVal: false,774    };775    config.responderStart.parent = {order: 2};776    run(config, three, startConfig(three.child, [three.child], [0]));777    expect(ResponderEventPlugin._getResponder()).toBe(778      getInstanceFromNode(three.parent),779    );780    config = oneEventLoopTestConfig(three);781    config.responderEnd.parent = {order: 0};782    config.responderRelease.parent = {order: 1};783    run(config, three, endConfig(three.child, [three.child], [0]));784    expect(ResponderEventPlugin._getResponder()).toBe(null);785  });786  it('should bubble negotiation to first common ancestor of responder then transfer', () => {787    var config = oneEventLoopTestConfig(three);788    config.startShouldSetResponder.captured.grandParent = {789      order: 0,790      returnVal: false,791    };792    config.startShouldSetResponder.captured.parent = {793      order: 1,794      returnVal: true,795    };796    config.responderGrant.parent = {order: 2};797    config.responderStart.parent = {order: 3};798    run(config, three, startConfig(three.child, [three.child], [0]));799    expect(ResponderEventPlugin._getResponder()).toBe(800      getInstanceFromNode(three.parent),801    );802    config = oneEventLoopTestConfig(three);803    // Parent is responder, and responder is transferred by a second touch start804    config.startShouldSetResponder.captured.grandParent = {805      order: 0,806      returnVal: true,807    };808    config.responderGrant.grandParent = {order: 1};809    config.responderTerminationRequest.parent = {order: 2, returnVal: true};810    config.responderTerminate.parent = {order: 3};811    config.responderStart.grandParent = {order: 4};812    run(813      config,814      three,815      startConfig(three.child, [three.child, three.child], [1]),816    );817    expect(ResponderEventPlugin._getResponder()).toBe(818      getInstanceFromNode(three.grandParent),819    );820    config = oneEventLoopTestConfig(three);821    config.responderEnd.grandParent = {order: 0};822    // one remains\ /one ended \823    run(config, three, endConfig(three.child, [three.child, three.child], [1]));824    expect(ResponderEventPlugin._getResponder()).toBe(825      getInstanceFromNode(three.grandParent),826    );827    config = oneEventLoopTestConfig(three);828    config.responderEnd.grandParent = {order: 0};829    config.responderRelease.grandParent = {order: 1};830    run(config, three, endConfig(three.child, [three.child], [0]));831    expect(ResponderEventPlugin._getResponder()).toBe(null);832  });833  /**834   * If nothing is responder, then the negotiation should propagate directly to835   * the deepest target in the second touch.836   */837  it('should negotiate with deepest target on second touch if nothing is responder', () => {838    // Initially nothing wants to become the responder839    var config = oneEventLoopTestConfig(three);840    config.startShouldSetResponder.captured.grandParent = {841      order: 0,842      returnVal: false,843    };844    config.startShouldSetResponder.captured.parent = {845      order: 1,846      returnVal: false,847    };848    config.startShouldSetResponder.bubbled.parent = {849      order: 2,850      returnVal: false,851    };852    config.startShouldSetResponder.bubbled.grandParent = {853      order: 3,854      returnVal: false,855    };856    run(config, three, startConfig(three.parent, [three.parent], [0]));857    expect(ResponderEventPlugin._getResponder()).toBe(null);858    config = oneEventLoopTestConfig(three);859    // Now child wants to become responder. Negotiation should bubble as deep860    // as the target is because we don't find first common ancestor (with861    // current responder) because there is no current responder.862    // (Even if this is the second active touch).863    config.startShouldSetResponder.captured.grandParent = {864      order: 0,865      returnVal: false,866    };867    config.startShouldSetResponder.captured.parent = {868      order: 1,869      returnVal: false,870    };871    config.startShouldSetResponder.captured.child = {872      order: 2,873      returnVal: false,874    };875    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};876    config.responderGrant.child = {order: 4};877    config.responderStart.child = {order: 5};878    //                                     /  Two active touches  \  /one of them new\879    run(880      config,881      three,882      startConfig(three.child, [three.parent, three.child], [1]),883    );884    expect(ResponderEventPlugin._getResponder()).toBe(885      getInstanceFromNode(three.child),886    );887    // Now we remove the original first touch, keeping the second touch that888    // started within the current responder (child). Nothing changes because889    // there's still touches that started inside of the current responder.890    config = oneEventLoopTestConfig(three);891    config.responderEnd.child = {order: 0};892    //                                      / one ended\  /one remains \893    run(894      config,895      three,896      endConfig(three.child, [three.parent, three.child], [0]),897    );898    expect(ResponderEventPlugin._getResponder()).toBe(899      getInstanceFromNode(three.child),900    );901    // Okay, now let's add back that first touch (nothing should change) and902    // then we'll try peeling back the touches in the opposite order to make903    // sure that first removing the second touch instantly causes responder to904    // be released.905    config = oneEventLoopTestConfig(three);906    config.startShouldSetResponder.captured.grandParent = {907      order: 0,908      returnVal: false,909    };910    config.startShouldSetResponder.captured.parent = {911      order: 1,912      returnVal: false,913    };914    config.startShouldSetResponder.bubbled.parent = {915      order: 2,916      returnVal: false,917    };918    config.startShouldSetResponder.bubbled.grandParent = {919      order: 3,920      returnVal: false,921    };922    // Interesting: child still gets moves even though touch target is parent!923    // Current responder gets a `responderStart` for any touch while responder.924    config.responderStart.child = {order: 4};925    //                                           /  Two active touches  \  /one of them new\926    run(927      config,928      three,929      startConfig(three.parent, [three.child, three.parent], [1]),930    );931    expect(ResponderEventPlugin._getResponder()).toBe(932      getInstanceFromNode(three.child),933    );934    // Now, move that new touch that had no effect, and did not start within935    // the current responder.936    config = oneEventLoopTestConfig(three);937    config.moveShouldSetResponder.captured.grandParent = {938      order: 0,939      returnVal: false,940    };941    config.moveShouldSetResponder.captured.parent = {942      order: 1,943      returnVal: false,944    };945    config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: false};946    config.moveShouldSetResponder.bubbled.grandParent = {947      order: 3,948      returnVal: false,949    };950    // Interesting: child still gets moves even though touch target is parent!951    // Current responder gets a `responderMove` for any touch while responder.952    config.responderMove.child = {order: 4};953    //                                     /  Two active touches  \  /one of them moved\954    run(955      config,956      three,957      moveConfig(three.parent, [three.child, three.parent], [1]),958    );959    expect(ResponderEventPlugin._getResponder()).toBe(960      getInstanceFromNode(three.child),961    );962    config = oneEventLoopTestConfig(three);963    config.responderEnd.child = {order: 0};964    config.responderRelease.child = {order: 1};965    //                                        /child end \ /parent remain\966    run(967      config,968      three,969      endConfig(three.child, [three.child, three.parent], [0]),970    );971    expect(ResponderEventPlugin._getResponder()).toBe(null);972  });973  /**974   * If nothing is responder, then the negotiation should propagate directly to975   * the deepest target in the second touch.976   */977  it('should negotiate until first common ancestor when there are siblings', () => {978    // Initially nothing wants to become the responder979    var config = oneEventLoopTestConfig(siblings);980    config.startShouldSetResponder.captured.parent = {981      order: 0,982      returnVal: false,983    };984    config.startShouldSetResponder.captured.childOne = {985      order: 1,986      returnVal: false,987    };988    config.startShouldSetResponder.bubbled.childOne = {989      order: 2,990      returnVal: true,991    };992    config.responderGrant.childOne = {order: 3};993    config.responderStart.childOne = {order: 4};994    run(995      config,996      siblings,997      startConfig(siblings.childOne, [siblings.childOne], [0]),998    );999    expect(ResponderEventPlugin._getResponder()).toBe(1000      getInstanceFromNode(siblings.childOne),1001    );1002    // If the touch target is the sibling item, the negotiation should only1003    // propagate to first common ancestor of current responder and sibling (so1004    // the parent).1005    config = oneEventLoopTestConfig(siblings);1006    config.startShouldSetResponder.captured.parent = {1007      order: 0,1008      returnVal: false,1009    };1010    config.startShouldSetResponder.bubbled.parent = {1011      order: 1,1012      returnVal: false,1013    };1014    config.responderStart.childOne = {order: 2};1015    var touchConfig = startConfig(1016      siblings.childTwo,1017      [siblings.childOne, siblings.childTwo],1018      [1],1019    );1020    run(config, siblings, touchConfig);1021    expect(ResponderEventPlugin._getResponder()).toBe(1022      getInstanceFromNode(siblings.childOne),1023    );1024    // move childOne1025    config = oneEventLoopTestConfig(siblings);1026    config.moveShouldSetResponder.captured.parent = {1027      order: 0,1028      returnVal: false,1029    };1030    config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};1031    config.responderMove.childOne = {order: 2};1032    run(1033      config,1034      siblings,1035      moveConfig(1036        siblings.childOne,1037        [siblings.childOne, siblings.childTwo],1038        [0],1039      ),1040    );1041    expect(ResponderEventPlugin._getResponder()).toBe(1042      getInstanceFromNode(siblings.childOne),1043    );1044    // move childTwo: Only negotiates to `parent`.1045    config = oneEventLoopTestConfig(siblings);1046    config.moveShouldSetResponder.captured.parent = {1047      order: 0,1048      returnVal: false,1049    };1050    config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};1051    config.responderMove.childOne = {order: 2};1052    run(1053      config,1054      siblings,1055      moveConfig(1056        siblings.childTwo,1057        [siblings.childOne, siblings.childTwo],1058        [1],1059      ),1060    );1061    expect(ResponderEventPlugin._getResponder()).toBe(1062      getInstanceFromNode(siblings.childOne),1063    );1064  });1065  it('should notify of being rejected. responderStart/Move happens on current responder', () => {1066    // Initially nothing wants to become the responder1067    var config = oneEventLoopTestConfig(three);1068    config.startShouldSetResponder.captured.grandParent = {1069      order: 0,1070      returnVal: false,1071    };1072    config.startShouldSetResponder.captured.parent = {1073      order: 1,1074      returnVal: false,1075    };1076    config.startShouldSetResponder.captured.child = {1077      order: 2,1078      returnVal: false,1079    };1080    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};1081    config.responderGrant.child = {order: 4};1082    config.responderStart.child = {order: 5};1083    run(config, three, startConfig(three.child, [three.child], [0]));1084    expect(ResponderEventPlugin._getResponder()).toBe(1085      getInstanceFromNode(three.child),1086    );1087    // Suppose parent wants to become responder on move, and is rejected1088    config = oneEventLoopTestConfig(three);1089    config.moveShouldSetResponder.captured.grandParent = {1090      order: 0,1091      returnVal: false,1092    };1093    config.moveShouldSetResponder.captured.parent = {1094      order: 1,1095      returnVal: false,1096    };1097    config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};1098    config.responderGrant.parent = {order: 3};1099    config.responderTerminationRequest.child = {order: 4, returnVal: false};1100    config.responderReject.parent = {order: 5};1101    // The start/move should occur on the original responder if new one is rejected1102    config.responderMove.child = {order: 6};1103    var touchConfig = moveConfig(three.child, [three.child], [0]);1104    run(config, three, touchConfig);1105    expect(ResponderEventPlugin._getResponder()).toBe(1106      getInstanceFromNode(three.child),1107    );1108    config = oneEventLoopTestConfig(three);1109    config.startShouldSetResponder.captured.grandParent = {1110      order: 0,1111      returnVal: false,1112    };1113    config.startShouldSetResponder.captured.parent = {1114      order: 1,1115      returnVal: false,1116    };1117    config.startShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};1118    config.responderGrant.parent = {order: 3};1119    config.responderTerminationRequest.child = {order: 4, returnVal: false};1120    config.responderReject.parent = {order: 5};1121    // The start/move should occur on the original responder if new one is rejected1122    config.responderStart.child = {order: 6};1123    touchConfig = startConfig(three.child, [three.child, three.child], [1]);1124    run(config, three, touchConfig);1125    expect(ResponderEventPlugin._getResponder()).toBe(1126      getInstanceFromNode(three.child),1127    );1128  });1129  it('should negotiate scroll', () => {1130    // Initially nothing wants to become the responder1131    var config = oneEventLoopTestConfig(three);1132    config.startShouldSetResponder.captured.grandParent = {1133      order: 0,1134      returnVal: false,1135    };1136    config.startShouldSetResponder.captured.parent = {1137      order: 1,1138      returnVal: false,1139    };1140    config.startShouldSetResponder.captured.child = {1141      order: 2,1142      returnVal: false,1143    };1144    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};1145    config.responderGrant.child = {order: 4};1146    config.responderStart.child = {order: 5};1147    run(config, three, startConfig(three.child, [three.child], [0]));1148    expect(ResponderEventPlugin._getResponder()).toBe(1149      getInstanceFromNode(three.child),1150    );1151    // If the touch target is the sibling item, the negotiation should only1152    // propagate to first common ancestor of current responder and sibling (so1153    // the parent).1154    config = oneEventLoopTestConfig(three);1155    config.scrollShouldSetResponder.captured.grandParent = {1156      order: 0,1157      returnVal: false,1158    };1159    config.scrollShouldSetResponder.captured.parent = {1160      order: 1,1161      returnVal: false,1162    };1163    config.scrollShouldSetResponder.bubbled.parent = {1164      order: 2,1165      returnVal: true,1166    };1167    config.responderGrant.parent = {order: 3};1168    config.responderTerminationRequest.child = {order: 4, returnVal: false};1169    config.responderReject.parent = {order: 5};1170    run(config, three, {1171      topLevelType: 'topScroll',1172      targetInst: getInstanceFromNode(three.parent),1173      nativeEvent: {},1174    });1175    expect(ResponderEventPlugin._getResponder()).toBe(1176      getInstanceFromNode(three.child),1177    );1178    // Now lets let the scroll take control this time.1179    config = oneEventLoopTestConfig(three);1180    config.scrollShouldSetResponder.captured.grandParent = {1181      order: 0,1182      returnVal: false,1183    };1184    config.scrollShouldSetResponder.captured.parent = {1185      order: 1,1186      returnVal: false,1187    };1188    config.scrollShouldSetResponder.bubbled.parent = {1189      order: 2,1190      returnVal: true,1191    };1192    config.responderGrant.parent = {order: 3};1193    config.responderTerminationRequest.child = {order: 4, returnVal: true};1194    config.responderTerminate.child = {order: 5};1195    run(config, three, {1196      topLevelType: 'topScroll',1197      targetInst: getInstanceFromNode(three.parent),1198      nativeEvent: {},1199    });1200    expect(ResponderEventPlugin._getResponder()).toBe(1201      getInstanceFromNode(three.parent),1202    );1203  });1204  it('should cancel correctly', () => {1205    // Initially our child becomes responder1206    var config = oneEventLoopTestConfig(three);1207    config.startShouldSetResponder.captured.grandParent = {1208      order: 0,1209      returnVal: false,1210    };1211    config.startShouldSetResponder.captured.parent = {1212      order: 1,1213      returnVal: false,1214    };1215    config.startShouldSetResponder.captured.child = {1216      order: 2,1217      returnVal: false,1218    };1219    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};1220    config.responderGrant.child = {order: 4};1221    config.responderStart.child = {order: 5};1222    run(config, three, startConfig(three.child, [three.child], [0]));1223    expect(ResponderEventPlugin._getResponder()).toBe(1224      getInstanceFromNode(three.child),1225    );1226    config = oneEventLoopTestConfig(three);1227    config.responderEnd.child = {order: 0};1228    config.responderTerminate.child = {order: 1};1229    var nativeEvent = _touchConfig(1230      'topTouchCancel',1231      three.child,1232      [three.child],1233      [0],1234    );1235    run(config, three, nativeEvent);1236    expect(ResponderEventPlugin._getResponder()).toBe(null);1237  });1238});ReactHostOperationHistoryHook-test.js
Source:ReactHostOperationHistoryHook-test.js  
...37    it('gets recorded for host roots', () => {38      var node = document.createElement('div');39      ReactHostOperationHistoryHook._preventClearing = true;40      ReactDOM.render(<div><p>Hi.</p></div>, node);41      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);42      assertHistoryMatches([43        {44          instanceID: inst._debugID,45          type: 'mount',46          payload: ReactDOMFeatureFlags.useCreateElement47            ? 'DIV'48            : '<div data-reactroot="" data-reactid="1"><p data-reactid="2">Hi.</p></div>',49        },50      ]);51    });52    it('gets recorded for composite roots', () => {53      function Foo() {54        return <div><p>Hi.</p></div>;55      }56      var node = document.createElement('div');57      ReactHostOperationHistoryHook._preventClearing = true;58      ReactDOM.render(<Foo />, node);59      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);60      assertHistoryMatches([61        {62          instanceID: inst._debugID,63          type: 'mount',64          payload: ReactDOMFeatureFlags.useCreateElement65            ? 'DIV'66            : '<div data-reactroot="" data-reactid="1">' +67                '<p data-reactid="2">Hi.</p></div>',68        },69      ]);70    });71    it('gets ignored for composite roots that return null', () => {72      function Foo() {73        return null;74      }75      var node = document.createElement('div');76      ReactHostOperationHistoryHook._preventClearing = true;77      ReactDOM.render(<Foo />, node);78      // Empty DOM components should be invisible to hooks.79      assertHistoryMatches([]);80    });81    it('gets recorded when a native is mounted deeply instead of null', () => {82      var element;83      function Foo() {84        return element;85      }86      ReactHostOperationHistoryHook._preventClearing = true;87      var node = document.createElement('div');88      element = null;89      ReactDOM.render(<Foo />, node);90      element = <span />;91      ReactDOM.render(<Foo />, node);92      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);93      // Since empty components should be invisible to hooks,94      // we record a "mount" event rather than a "replace with".95      assertHistoryMatches([96        {97          instanceID: inst._debugID,98          type: 'mount',99          payload: 'SPAN',100        },101      ]);102    });103  });104  describe('update styles', () => {105    it('gets recorded during mount', () => {106      var node = document.createElement('div');107      ReactHostOperationHistoryHook._preventClearing = true;108      ReactDOM.render(109        <div110          style={{111            color: 'red',112            backgroundColor: 'yellow',113          }}114        />,115        node,116      );117      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);118      if (ReactDOMFeatureFlags.useCreateElement) {119        assertHistoryMatches([120          {121            instanceID: inst._debugID,122            type: 'update styles',123            payload: {124              color: 'red',125              backgroundColor: 'yellow',126            },127          },128          {129            instanceID: inst._debugID,130            type: 'mount',131            payload: 'DIV',132          },133        ]);134      } else {135        assertHistoryMatches([136          {137            instanceID: inst._debugID,138            type: 'mount',139            payload:140              '<div style="color:red;background-color:yellow;" ' +141                'data-reactroot="" data-reactid="1"></div>',142          },143        ]);144      }145    });146    it('gets recorded during an update', () => {147      var node = document.createElement('div');148      ReactDOM.render(<div />, node);149      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);150      ReactHostOperationHistoryHook._preventClearing = true;151      ReactDOM.render(<div style={{color: 'red'}} />, node);152      ReactDOM.render(153        <div154          style={{155            color: 'blue',156            backgroundColor: 'yellow',157          }}158        />,159        node,160      );161      ReactDOM.render(<div style={{backgroundColor: 'green'}} />, node);162      ReactDOM.render(<div />, node);163      assertHistoryMatches([164        {165          instanceID: inst._debugID,166          type: 'update styles',167          payload: {color: 'red'},168        },169        {170          instanceID: inst._debugID,171          type: 'update styles',172          payload: {color: 'blue', backgroundColor: 'yellow'},173        },174        {175          instanceID: inst._debugID,176          type: 'update styles',177          payload: {color: '', backgroundColor: 'green'},178        },179        {180          instanceID: inst._debugID,181          type: 'update styles',182          payload: {backgroundColor: ''},183        },184      ]);185    });186    it('gets ignored if the styles are shallowly equal', () => {187      var node = document.createElement('div');188      ReactDOM.render(<div />, node);189      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);190      ReactHostOperationHistoryHook._preventClearing = true;191      ReactDOM.render(192        <div193          style={{194            color: 'red',195            backgroundColor: 'yellow',196          }}197        />,198        node,199      );200      ReactDOM.render(201        <div202          style={{203            color: 'red',204            backgroundColor: 'yellow',205          }}206        />,207        node,208      );209      assertHistoryMatches([210        {211          instanceID: inst._debugID,212          type: 'update styles',213          payload: {214            color: 'red',215            backgroundColor: 'yellow',216          },217        },218      ]);219    });220  });221  describe('update attribute', () => {222    describe('simple attribute', () => {223      it('gets recorded during mount', () => {224        var node = document.createElement('div');225        ReactHostOperationHistoryHook._preventClearing = true;226        ReactDOM.render(<div className="rad" tabIndex={42} />, node);227        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);228        if (ReactDOMFeatureFlags.useCreateElement) {229          assertHistoryMatches([230            {231              instanceID: inst._debugID,232              type: 'update attribute',233              payload: {className: 'rad'},234            },235            {236              instanceID: inst._debugID,237              type: 'update attribute',238              payload: {tabIndex: 42},239            },240            {241              instanceID: inst._debugID,242              type: 'mount',243              payload: 'DIV',244            },245          ]);246        } else {247          assertHistoryMatches([248            {249              instanceID: inst._debugID,250              type: 'mount',251              payload:252                '<div class="rad" tabindex="42" data-reactroot="" ' +253                  'data-reactid="1"></div>',254            },255          ]);256        }257      });258      it('gets recorded during an update', () => {259        var node = document.createElement('div');260        ReactDOM.render(<div />, node);261        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);262        ReactHostOperationHistoryHook._preventClearing = true;263        ReactDOM.render(<div className="rad" />, node);264        ReactDOM.render(<div className="mad" tabIndex={42} />, node);265        ReactDOM.render(<div tabIndex={43} />, node);266        assertHistoryMatches([267          {268            instanceID: inst._debugID,269            type: 'update attribute',270            payload: {className: 'rad'},271          },272          {273            instanceID: inst._debugID,274            type: 'update attribute',275            payload: {className: 'mad'},276          },277          {278            instanceID: inst._debugID,279            type: 'update attribute',280            payload: {tabIndex: 42},281          },282          {283            instanceID: inst._debugID,284            type: 'remove attribute',285            payload: 'className',286          },287          {288            instanceID: inst._debugID,289            type: 'update attribute',290            payload: {tabIndex: 43},291          },292        ]);293      });294    });295    describe('attribute that gets removed with certain values', () => {296      it('gets recorded as a removal during an update', () => {297        var node = document.createElement('div');298        ReactDOM.render(<div />, node);299        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);300        ReactHostOperationHistoryHook._preventClearing = true;301        ReactDOM.render(<div disabled={true} />, node);302        ReactDOM.render(<div disabled={false} />, node);303        assertHistoryMatches([304          {305            instanceID: inst._debugID,306            type: 'update attribute',307            payload: {disabled: true},308          },309          {310            instanceID: inst._debugID,311            type: 'remove attribute',312            payload: 'disabled',313          },314        ]);315      });316    });317    describe('custom attribute', () => {318      it('gets recorded during mount', () => {319        var node = document.createElement('div');320        ReactHostOperationHistoryHook._preventClearing = true;321        ReactDOM.render(<div data-x="rad" data-y={42} />, node);322        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);323        if (ReactDOMFeatureFlags.useCreateElement) {324          assertHistoryMatches([325            {326              instanceID: inst._debugID,327              type: 'update attribute',328              payload: {'data-x': 'rad'},329            },330            {331              instanceID: inst._debugID,332              type: 'update attribute',333              payload: {'data-y': 42},334            },335            {336              instanceID: inst._debugID,337              type: 'mount',338              payload: 'DIV',339            },340          ]);341        } else {342          assertHistoryMatches([343            {344              instanceID: inst._debugID,345              type: 'mount',346              payload:347                '<div data-x="rad" data-y="42" data-reactroot="" ' +348                  'data-reactid="1"></div>',349            },350          ]);351        }352      });353      it('gets recorded during an update', () => {354        var node = document.createElement('div');355        ReactDOM.render(<div />, node);356        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);357        ReactHostOperationHistoryHook._preventClearing = true;358        ReactDOM.render(<div data-x="rad" />, node);359        ReactDOM.render(<div data-x="mad" data-y={42} />, node);360        ReactDOM.render(<div data-y={43} />, node);361        assertHistoryMatches([362          {363            instanceID: inst._debugID,364            type: 'update attribute',365            payload: {'data-x': 'rad'},366          },367          {368            instanceID: inst._debugID,369            type: 'update attribute',370            payload: {'data-x': 'mad'},371          },372          {373            instanceID: inst._debugID,374            type: 'update attribute',375            payload: {'data-y': 42},376          },377          {378            instanceID: inst._debugID,379            type: 'remove attribute',380            payload: 'data-x',381          },382          {383            instanceID: inst._debugID,384            type: 'update attribute',385            payload: {'data-y': 43},386          },387        ]);388      });389    });390    describe('attribute on a web component', () => {391      it('gets recorded during mount', () => {392        var node = document.createElement('div');393        ReactHostOperationHistoryHook._preventClearing = true;394        ReactDOM.render(<my-component className="rad" tabIndex={42} />, node);395        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);396        if (ReactDOMFeatureFlags.useCreateElement) {397          assertHistoryMatches([398            {399              instanceID: inst._debugID,400              type: 'update attribute',401              payload: {className: 'rad'},402            },403            {404              instanceID: inst._debugID,405              type: 'update attribute',406              payload: {tabIndex: 42},407            },408            {409              instanceID: inst._debugID,410              type: 'mount',411              payload: 'MY-COMPONENT',412            },413          ]);414        } else {415          assertHistoryMatches([416            {417              instanceID: inst._debugID,418              type: 'mount',419              payload:420                '<my-component className="rad" tabIndex="42" ' +421                  'data-reactroot="" data-reactid="1"></my-component>',422            },423          ]);424        }425      });426      it('gets recorded during an update', () => {427        var node = document.createElement('div');428        ReactDOM.render(<my-component />, node);429        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);430        ReactHostOperationHistoryHook._preventClearing = true;431        ReactDOM.render(<my-component className="rad" />, node);432        ReactDOM.render(<my-component className="mad" tabIndex={42} />, node);433        ReactDOM.render(<my-component tabIndex={43} />, node);434        assertHistoryMatches([435          {436            instanceID: inst._debugID,437            type: 'update attribute',438            payload: {className: 'rad'},439          },440          {441            instanceID: inst._debugID,442            type: 'update attribute',443            payload: {className: 'mad'},444          },445          {446            instanceID: inst._debugID,447            type: 'update attribute',448            payload: {tabIndex: 42},449          },450          {451            instanceID: inst._debugID,452            type: 'remove attribute',453            payload: 'className',454          },455          {456            instanceID: inst._debugID,457            type: 'update attribute',458            payload: {tabIndex: 43},459          },460        ]);461      });462    });463  });464  describe('replace text', () => {465    describe('text content', () => {466      it('gets recorded during an update from text content', () => {467        var node = document.createElement('div');468        ReactDOM.render(<div>Hi.</div>, node);469        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);470        ReactHostOperationHistoryHook._preventClearing = true;471        ReactDOM.render(<div>Bye.</div>, node);472        assertHistoryMatches([473          {474            instanceID: inst._debugID,475            type: 'replace text',476            payload: 'Bye.',477          },478        ]);479      });480      it('gets recorded during an update from html', () => {481        var node = document.createElement('div');482        ReactDOM.render(483          <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,484          node,485        );486        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);487        ReactHostOperationHistoryHook._preventClearing = true;488        ReactDOM.render(<div>Bye.</div>, node);489        assertHistoryMatches([490          {491            instanceID: inst._debugID,492            type: 'replace text',493            payload: 'Bye.',494          },495        ]);496      });497      it('gets recorded during an update from children', () => {498        var node = document.createElement('div');499        ReactDOM.render(<div><span /><p /></div>, node);500        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);501        ReactHostOperationHistoryHook._preventClearing = true;502        ReactDOM.render(<div>Bye.</div>, node);503        assertHistoryMatches([504          {505            instanceID: inst._debugID,506            type: 'remove child',507            payload: {fromIndex: 0},508          },509          {510            instanceID: inst._debugID,511            type: 'remove child',512            payload: {fromIndex: 1},513          },514          {515            instanceID: inst._debugID,516            type: 'replace text',517            payload: 'Bye.',518          },519        ]);520      });521      it('gets ignored if new text is equal', () => {522        var node = document.createElement('div');523        ReactDOM.render(<div>Hi.</div>, node);524        ReactHostOperationHistoryHook._preventClearing = true;525        ReactDOM.render(<div>Hi.</div>, node);526        assertHistoryMatches([]);527      });528    });529    describe('text node', () => {530      it('gets recorded during an update', () => {531        var node = document.createElement('div');532        ReactDOM.render(<div>{'Hi.'}{42}</div>, node);533        var inst1 = ReactDOMComponentTree.getInstanceFromNode(534          node.firstChild.childNodes[0],535        );536        var inst2 = ReactDOMComponentTree.getInstanceFromNode(537          node.firstChild.childNodes[3],538        );539        ReactHostOperationHistoryHook._preventClearing = true;540        ReactDOM.render(<div>{'Bye.'}{43}</div>, node);541        assertHistoryMatches([542          {543            instanceID: inst1._debugID,544            type: 'replace text',545            payload: 'Bye.',546          },547          {548            instanceID: inst2._debugID,549            type: 'replace text',550            payload: '43',551          },552        ]);553      });554      it('gets ignored if new text is equal', () => {555        var node = document.createElement('div');556        ReactDOM.render(<div>{'Hi.'}{42}</div>, node);557        ReactHostOperationHistoryHook._preventClearing = true;558        ReactDOM.render(<div>{'Hi.'}{42}</div>, node);559        assertHistoryMatches([]);560      });561    });562  });563  describe('replace with', () => {564    it('gets recorded when composite renders to a different type', () => {565      var element;566      function Foo() {567        return element;568      }569      var node = document.createElement('div');570      element = <div />;571      ReactDOM.render(<Foo />, node);572      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);573      element = <span />;574      ReactHostOperationHistoryHook._preventClearing = true;575      ReactDOM.render(<Foo />, node);576      assertHistoryMatches([577        {578          instanceID: inst._debugID,579          type: 'replace with',580          payload: 'SPAN',581        },582      ]);583    });584    it('gets recorded when composite renders to null after a native', () => {585      var element;586      function Foo() {587        return element;588      }589      var node = document.createElement('div');590      element = <span />;591      ReactDOM.render(<Foo />, node);592      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);593      element = null;594      ReactHostOperationHistoryHook._preventClearing = true;595      ReactDOM.render(<Foo />, node);596      assertHistoryMatches([597        {598          instanceID: inst._debugID,599          type: 'replace with',600          payload: '#comment',601        },602      ]);603    });604    it('gets ignored if the type has not changed', () => {605      var element;606      function Foo() {607        return element;608      }609      var node = document.createElement('div');610      element = <div />;611      ReactDOM.render(<Foo />, node);612      element = <div />;613      ReactHostOperationHistoryHook._preventClearing = true;614      ReactDOM.render(<Foo />, node);615      assertHistoryMatches([]);616    });617  });618  describe('replace children', () => {619    it('gets recorded during an update from text content', () => {620      var node = document.createElement('div');621      ReactDOM.render(<div>Hi.</div>, node);622      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);623      ReactHostOperationHistoryHook._preventClearing = true;624      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />, node);625      assertHistoryMatches([626        {627          instanceID: inst._debugID,628          type: 'replace children',629          payload: 'Bye.',630        },631      ]);632    });633    it('gets recorded during an update from html', () => {634      var node = document.createElement('div');635      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);636      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);637      ReactHostOperationHistoryHook._preventClearing = true;638      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />, node);639      assertHistoryMatches([640        {641          instanceID: inst._debugID,642          type: 'replace children',643          payload: 'Bye.',644        },645      ]);646    });647    it('gets recorded during an update from children', () => {648      var node = document.createElement('div');649      ReactDOM.render(<div><span /><p /></div>, node);650      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);651      ReactHostOperationHistoryHook._preventClearing = true;652      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);653      assertHistoryMatches([654        {655          instanceID: inst._debugID,656          type: 'remove child',657          payload: {fromIndex: 0},658        },659        {660          instanceID: inst._debugID,661          type: 'remove child',662          payload: {fromIndex: 1},663        },664        {665          instanceID: inst._debugID,666          type: 'replace children',667          payload: 'Hi.',668        },669      ]);670    });671    it('gets ignored if new html is equal', () => {672      var node = document.createElement('div');673      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);674      ReactHostOperationHistoryHook._preventClearing = true;675      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);676      assertHistoryMatches([]);677    });678  });679  describe('insert child', () => {680    it('gets reported when a child is inserted', () => {681      var node = document.createElement('div');682      ReactDOM.render(<div><span /></div>, node);683      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);684      ReactHostOperationHistoryHook._preventClearing = true;685      ReactDOM.render(<div><span /><p /></div>, node);686      assertHistoryMatches([687        {688          instanceID: inst._debugID,689          type: 'insert child',690          payload: {toIndex: 1, content: 'P'},691        },692      ]);693    });694  });695  describe('move child', () => {696    it('gets reported when a child is inserted', () => {697      var node = document.createElement('div');698      ReactDOM.render(<div><span key="a" /><p key="b" /></div>, node);699      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);700      ReactHostOperationHistoryHook._preventClearing = true;701      ReactDOM.render(<div><p key="b" /><span key="a" /></div>, node);702      assertHistoryMatches([703        {704          instanceID: inst._debugID,705          type: 'move child',706          payload: {fromIndex: 0, toIndex: 1},707        },708      ]);709    });710  });711  describe('remove child', () => {712    it('gets reported when a child is removed', () => {713      var node = document.createElement('div');714      ReactDOM.render(<div><span key="a" /><p key="b" /></div>, node);715      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);716      ReactHostOperationHistoryHook._preventClearing = true;717      ReactDOM.render(<div><span key="a" /></div>, node);718      assertHistoryMatches([719        {720          instanceID: inst._debugID,721          type: 'remove child',722          payload: {fromIndex: 1},723        },724      ]);725    });726  });...ReactEventListener-test.js
Source:ReactEventListener-test.js  
...62      });63      var calls = handleTopLevel.mock.calls;64      expect(calls.length).toBe(2);65      expect(calls[0][EVENT_TARGET_PARAM])66        .toBe(ReactDOMComponentTree.getInstanceFromNode(childControl));67      expect(calls[1][EVENT_TARGET_PARAM])68        .toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));69    });70    it('should propagate events two levels down', function() {71      var childContainer = document.createElement('div');72      var childControl = <div>Child</div>;73      var parentContainer = document.createElement('div');74      var parentControl = <div>Parent</div>;75      var grandParentContainer = document.createElement('div');76      var grandParentControl = <div>Parent</div>;77      childControl = ReactDOM.render(childControl, childContainer);78      parentControl =79        ReactDOM.render(parentControl, parentContainer);80      grandParentControl =81        ReactDOM.render(grandParentControl, grandParentContainer);82      ReactDOM.findDOMNode(parentControl).appendChild(childContainer);83      ReactDOM.findDOMNode(grandParentControl).appendChild(parentContainer);84      var callback = ReactEventListener.dispatchEvent.bind(null, 'test');85      callback({86        target: ReactDOM.findDOMNode(childControl),87      });88      var calls = handleTopLevel.mock.calls;89      expect(calls.length).toBe(3);90      expect(calls[0][EVENT_TARGET_PARAM])91        .toBe(ReactDOMComponentTree.getInstanceFromNode(childControl));92      expect(calls[1][EVENT_TARGET_PARAM])93        .toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));94      expect(calls[2][EVENT_TARGET_PARAM])95        .toBe(ReactDOMComponentTree.getInstanceFromNode(grandParentControl));96    });97    it('should not get confused by disappearing elements', function() {98      var childContainer = document.createElement('div');99      var childControl = <div>Child</div>;100      var parentContainer = document.createElement('div');101      var parentControl = <div>Parent</div>;102      childControl = ReactDOM.render(childControl, childContainer);103      parentControl =104        ReactDOM.render(parentControl, parentContainer);105      ReactDOM.findDOMNode(parentControl).appendChild(childContainer);106      // ReactBrowserEventEmitter.handleTopLevel might remove the107      // target from the DOM. Here, we have handleTopLevel remove the108      // node when the first event handlers are called; we'll still109      // expect to receive a second call for the parent control.110      var childNode = ReactDOM.findDOMNode(childControl);111      handleTopLevel.mockImplementation(112        function(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent) {113          if (topLevelTarget === childNode) {114            ReactDOM.unmountComponentAtNode(childContainer);115          }116        }117      );118      var callback = ReactEventListener.dispatchEvent.bind(null, 'test');119      callback({120        target: childNode,121      });122      var calls = handleTopLevel.mock.calls;123      expect(calls.length).toBe(2);124      expect(calls[0][EVENT_TARGET_PARAM])125        .toBe(ReactDOMComponentTree.getInstanceFromNode(childNode));126      expect(calls[1][EVENT_TARGET_PARAM])127        .toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));128    });129    it('should batch between handlers from different roots', function() {130      var childContainer = document.createElement('div');131      var parentContainer = document.createElement('div');132      var childControl = ReactDOM.render(133        <div>Child</div>,134        childContainer135      );136      var parentControl = ReactDOM.render(137        <div>Parent</div>,138        parentContainer139      );140      ReactDOM.findDOMNode(parentControl).appendChild(childContainer);141      // Suppose an event handler in each root enqueues an update to the142      // childControl element -- the two updates should get batched together.143      var childNode = ReactDOM.findDOMNode(childControl);144      handleTopLevel.mockImplementation(145        function(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent) {146          ReactDOM.render(147            <div>{topLevelTarget === childNode ? '1' : '2'}</div>,148            childContainer149          );150          // Since we're batching, neither update should yet have gone through.151          expect(childNode.textContent).toBe('Child');152        }153      );154      var callback =155        ReactEventListener.dispatchEvent.bind(ReactEventListener, 'test');156      callback({157        target: childNode,158      });159      var calls = handleTopLevel.mock.calls;160      expect(calls.length).toBe(2);161      expect(childNode.textContent).toBe('2');162    });163  });164  it('should not fire duplicate events for a React DOM tree', function() {165    var Wrapper = React.createClass({166      getInner: function() {167        return this.refs.inner;168      },169      render: function() {170        var inner = <div ref="inner">Inner</div>;171        return <div><div id="outer">{inner}</div></div>;172      },173    });174    var instance = ReactTestUtils.renderIntoDocument(<Wrapper />);175    var callback = ReactEventListener.dispatchEvent.bind(null, 'test');176    callback({177      target: ReactDOM.findDOMNode(instance.getInner()),178    });179    var calls = handleTopLevel.mock.calls;180    expect(calls.length).toBe(1);181    expect(calls[0][EVENT_TARGET_PARAM])182      .toBe(ReactDOMComponentTree.getInstanceFromNode(instance.getInner()));183  });...ce23cbEventPluginUtils.js
Source:ce23cbEventPluginUtils.js  
...146executeDirectDispatch:executeDirectDispatch,147executeDispatchesInOrder:executeDispatchesInOrder,148executeDispatchesInOrderStopAtTrue:executeDispatchesInOrderStopAtTrue,149hasDispatches:hasDispatches,150getInstanceFromNode:function getInstanceFromNode(node){151return ComponentTree.getInstanceFromNode(node);152},153getNodeFromInstance:function getNodeFromInstance(node){154return ComponentTree.getNodeFromInstance(node);155},156isAncestor:function isAncestor(a,b){157return TreeTraversal.isAncestor(a,b);158},159getLowestCommonAncestor:function getLowestCommonAncestor(a,b){160return TreeTraversal.getLowestCommonAncestor(a,b);161},162getParentInstance:function getParentInstance(inst){163return TreeTraversal.getParentInstance(inst);164},165traverseTwoPhase:function traverseTwoPhase(target,fn,arg){...Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3  const browser = await chromium.launch({ headless: false });4  const context = await browser.newContext();5  const page = await context.newPage();6  await page.fill('input[type="text"]', 'Hello World');7  const elementHandle = await page.$('input[type="text"]');8  const instance = await elementHandle._internalHandler.getInstanceFromNode();9  console.log(instance);10  await browser.close();11})();Using AI Code Generation
1const { webkit } = require('playwright');2(async () => {3  const browser = await webkit.launch();4  const context = await browser.newContext();5  const page = await context.newPage();6  const element = await page.$('text=Get started');7  const playwright = require('playwright');8  const internal = playwright._impl;9  const elementHandle = await internal.getExistingElementHandle(element);10  const internalElement = internal.getInstanceFromNode(elementHandle);11  console.log(internalElement);12  await browser.close();13})();Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3  const browser = await chromium.launch();4  const page = await browser.newPage();5  const frame = page.mainFrame();6  const elementHandle = await frame.$('input');7  const elementHandle2 = await frame.$('button');8  const page2 = elementHandle2._page;9  const frame2 = elementHandle2._frame;10  const elementHandle3 = await frame2.$('div');11  const page3 = elementHandle3._page;12  const frame3 = elementHandle3._frame;13  const elementHandle4 = await frame3.$('span');14  const page4 = elementHandle4._page;15  const frame4 = elementHandle4._frame;16  const elementHandle5 = await frame4.$('div');17  const page5 = elementHandle5._page;18  const frame5 = elementHandle5._frame;19  const elementHandle6 = await frame5.$('div');20  const page6 = elementHandle6._page;21  const frame6 = elementHandle6._frame;22  const elementHandle7 = await frame6.$('div');23  const page7 = elementHandle7._page;24  const frame7 = elementHandle7._frame;25  const elementHandle8 = await frame7.$('div');26  const page8 = elementHandle8._page;27  const frame8 = elementHandle8._frame;28  const elementHandle9 = await frame8.$('div');29  const page9 = elementHandle9._page;30  const frame9 = elementHandle9._frame;31  const elementHandle10 = await frame9.$('div');32  const page10 = elementHandle10._page;33  const frame10 = elementHandle10._frame;34  const elementHandle11 = await frame10.$('div');35  const page11 = elementHandle11._page;36  const frame11 = elementHandle11._frame;37  const elementHandle12 = await frame11.$('div');38  const page12 = elementHandle12._page;39  const frame12 = elementHandle12._frame;40  const elementHandle13 = await frame12.$('div');41  const page13 = elementHandle13._page;42  const frame13 = elementHandle13._frame;43  const elementHandle14 = await frame13.$('div');44  const page14 = elementHandle14._page;Using AI Code Generation
1const { Playwright } = require('playwright');2const playwright = new Playwright();3const { chromium } = playwright;4const browser = await chromium.launch();5const context = await browser.newContext();6const page = await context.newPage();7const element = await page.$('button');8const page1 = element._page;9await browser.close();10const { chromium } = require('playwright');11const browser = await chromium.launch();12const context = await browser.newContext();13const page = await context.newPage();14const element = await page.$('button');15const page1 = await page.evaluateHandle((element) => element.ownerDocument.defaultView, element);16await browser.close();17## 3. Using `page.mainFrame().executionContext()` method18const { chromium } = require('playwright');19const browser = await chromium.launch();20const context = await browser.newContext();21const page = await context.newPage();22const element = await page.$('button');23const page1 = await element.executionContext().evaluateHandle((element) => element.ownerDocument.defaultView, element);24await browser.close();25## 4. Using `page.mainFrame().executionContext()` method with `page.$eval` method26const { chromium } = require('playwright');27const browser = await chromium.launch();28const context = await browser.newContext();29const page = await context.newPage();30const page1 = await page.$eval('button', (element) => element.ownerDocument.defaultView);31await browser.close();32## 5. Using `page.mainFrame().executionContext()` method with `page.$$eval` method33const { chromium } = require('playwright');34const browser = await chromium.launch();Using AI Code Generation
1const { getInstanceFromNode } = require('playwright/lib/protocol/helper');2const { chromium } = require('playwright');3(async () => {4  const browser = await chromium.launch({ headless: false });5  const page = await browser.newPage();6  const frame = page.mainFrame();7  const frameManager = getInstanceFromNode(frame, 'FrameManager');8  const frameTree = await frameManager.frameTree();9  console.log(frameTree);10  await browser.close();11})();12#### frameManager.frameTree()13const { chromium } = require('playwright');14const { getInstanceFromNode } = require('playwright/lib/protocol/helper');15(async () => {16  const browser = await chromium.launch({ headless: false });17  const page = await browser.newPage();18  const frame = page.mainFrame();19  const frameManager = getInstanceFromNode(frame, 'FrameManager');20  const frameTree = await frameManager.frameTree();21  console.log(frameTree);22  await browser.close();23})();Using AI Code Generation
1const { getInstanceFromNode } = require("playwright/lib/server/dom");2const { chromium } = require("playwright");3const { expect } = require("chai");4(async () => {5  const browser = await chromium.launch();6  const context = await browser.newContext();7  const page = await context.newPage();8  const handle = await getInstanceFromNode(button);9  expect(handle._remoteObject.description).to.equal("HTMLInputElement");10  await browser.close();11})();Using AI Code Generation
1const { getInstanceFromNode } = require('playwright');2const page = getInstanceFromNode(document.querySelector('iframe')).page;3const { chromium } = require('playwright');4(async () => {5  const browser = await chromium.launch({ headless: false });6  const page = await browser.newPage();7  await page.screenshot({ path: `google.png` });8  await browser.close();9})();Using AI Code Generation
1const { getInstanceFromNode } = require('playwright/lib/server/dom');2const { chromium } = require('playwright');3const path = require('path');4const fs = require('fs');5const expect = require('expect');6(async () => {7  const browser = await chromium.launch();8  const context = await browser.newContext();9  const page = await context.newPage();10  const input = await page.$('input[name="q"]');11  const inputHandle = await input.asElement();12  const inputImpl = await getInstanceFromNode(inputHandle);13  expect(inputImpl._node.name).toBe('q');14  await browser.close();15})();Using AI Code Generation
1const { getInstanceFromNode } = require('playwright/lib/server/dom');2const element = await page.$('button');3const internalElement = getInstanceFromNode(element);4const internalElement2 = await page.evaluateHandle((element) => {5  return getInstanceFromNode(element);6}, element);7const internalElement3 = await page.evaluateHandle((element) => {8  return element._delegate;9}, element);10const internalElement4 = await page.evaluateHandle((element) => {11  return element._element;12}, element);13const internalElement5 = await page.evaluateHandle((element) => {14  return element._page._delegate;15}, element);16const internalElement6 = await page.evaluateHandle((element) => {17  return element._page._delegate._browserContext;18}, element);19const internalElement7 = await page.evaluateHandle((element) => {20  return element._page._delegate._browserContext._browser;21}, element);22const internalElement8 = await page.evaluateHandle((element) => {23  return element._page._delegate._browserContext._browser._connection;24}, element);25const internalElement9 = await page.evaluateHandle((element) => {26  return element._page._delegate._browserContext._browser._connection._transport;27}, element);28const internalElement10 = await page.evaluateHandle((element) => {29  return element._page._delegate._browserContext._browser._connection._transport._ws;30}, element);31const internalElement11 = await page.evaluateHandle((element) => {32  return element._page._delegate._browserContext._browser._connection._transport._ws._socket;33}, element);34const internalElement12 = await page.evaluateHandle((element) => {35  return element._page._delegate._browserContext._browser._connection._transport._ws._socket._handle;36}, element);37const internalElement13 = await page.evaluateHandle((element) => {38  return element._page._delegate._browserContext._browser._connection._transport._ws._socket._handle._externalStream;39}, element);40const internalElement14 = await page.evaluateHandle((element) => {41  return element._page._delegate._browserContext._browser._connection._transport._ws._socket._handle._externalStream._handle;42}, element);43const internalElement15 = await page.evaluateHandle((element) => {LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!
