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!!