1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  */
    
  7. 
    
  8. 'use strict';
    
  9. 
    
  10. // Mock of the Native Hooks
    
  11. 
    
  12. const roots = new Map();
    
  13. const allocatedTags = new Set();
    
  14. 
    
  15. function dumpSubtree(info, indent) {
    
  16.   let out = '';
    
  17.   out += ' '.repeat(indent) + info.viewName + ' ' + JSON.stringify(info.props);
    
  18.   // eslint-disable-next-line no-for-of-loops/no-for-of-loops
    
  19.   for (const child of info.children) {
    
  20.     out += '\n' + dumpSubtree(child, indent + 2);
    
  21.   }
    
  22.   return out;
    
  23. }
    
  24. 
    
  25. const RCTFabricUIManager = {
    
  26.   __dumpChildSetForJestTestsOnly: function (childSet) {
    
  27.     const result = [];
    
  28.     // eslint-disable-next-line no-for-of-loops/no-for-of-loops
    
  29.     for (const child of childSet) {
    
  30.       result.push(dumpSubtree(child, 0));
    
  31.     }
    
  32.     return result.join('\n');
    
  33.   },
    
  34.   __dumpHierarchyForJestTestsOnly: function () {
    
  35.     const result = [];
    
  36.     // eslint-disable-next-line no-for-of-loops/no-for-of-loops
    
  37.     for (const [rootTag, childSet] of roots) {
    
  38.       result.push(rootTag);
    
  39.       // eslint-disable-next-line no-for-of-loops/no-for-of-loops
    
  40.       for (const child of childSet) {
    
  41.         result.push(dumpSubtree(child, 1));
    
  42.       }
    
  43.     }
    
  44.     return result.join('\n');
    
  45.   },
    
  46.   createNode: jest.fn(
    
  47.     function createNode(reactTag, viewName, rootTag, props, eventTarget) {
    
  48.       if (allocatedTags.has(reactTag)) {
    
  49.         throw new Error(`Created two native views with tag ${reactTag}`);
    
  50.       }
    
  51. 
    
  52.       allocatedTags.add(reactTag);
    
  53.       return {
    
  54.         reactTag: reactTag,
    
  55.         viewName: viewName,
    
  56.         props: props,
    
  57.         children: [],
    
  58.       };
    
  59.     },
    
  60.   ),
    
  61.   cloneNode: jest.fn(function cloneNode(node) {
    
  62.     return {
    
  63.       reactTag: node.reactTag,
    
  64.       viewName: node.viewName,
    
  65.       props: node.props,
    
  66.       children: node.children,
    
  67.     };
    
  68.   }),
    
  69.   cloneNodeWithNewChildren: jest.fn(
    
  70.     function cloneNodeWithNewChildren(node, children) {
    
  71.       return {
    
  72.         reactTag: node.reactTag,
    
  73.         viewName: node.viewName,
    
  74.         props: node.props,
    
  75.         children: children ?? [],
    
  76.       };
    
  77.     },
    
  78.   ),
    
  79.   cloneNodeWithNewProps: jest.fn(
    
  80.     function cloneNodeWithNewProps(node, newPropsDiff) {
    
  81.       return {
    
  82.         reactTag: node.reactTag,
    
  83.         viewName: node.viewName,
    
  84.         props: {...node.props, ...newPropsDiff},
    
  85.         children: node.children,
    
  86.       };
    
  87.     },
    
  88.   ),
    
  89.   cloneNodeWithNewChildrenAndProps: jest.fn(
    
  90.     function cloneNodeWithNewChildrenAndProps(node, newPropsDiff) {
    
  91.       let children = [];
    
  92.       if (arguments.length === 3) {
    
  93.         children = newPropsDiff;
    
  94.         newPropsDiff = arguments[2];
    
  95.       }
    
  96. 
    
  97.       return {
    
  98.         reactTag: node.reactTag,
    
  99.         viewName: node.viewName,
    
  100.         props: {...node.props, ...newPropsDiff},
    
  101.         children,
    
  102.       };
    
  103.     },
    
  104.   ),
    
  105.   appendChild: jest.fn(function appendChild(parentNode, childNode) {
    
  106.     parentNode.children.push(childNode);
    
  107.   }),
    
  108. 
    
  109.   createChildSet: jest.fn(function createChildSet() {
    
  110.     return [];
    
  111.   }),
    
  112. 
    
  113.   appendChildToSet: jest.fn(function appendChildToSet(childSet, childNode) {
    
  114.     childSet.push(childNode);
    
  115.   }),
    
  116. 
    
  117.   completeRoot: jest.fn(function completeRoot(rootTag, newChildSet) {
    
  118.     roots.set(rootTag, newChildSet);
    
  119.   }),
    
  120. 
    
  121.   dispatchCommand: jest.fn(),
    
  122. 
    
  123.   setNativeProps: jest.fn(),
    
  124. 
    
  125.   sendAccessibilityEvent: jest.fn(),
    
  126. 
    
  127.   registerEventHandler: jest.fn(function registerEventHandler(callback) {}),
    
  128. 
    
  129.   measure: jest.fn(function measure(node, callback) {
    
  130.     if (typeof node !== 'object') {
    
  131.       throw new Error(
    
  132.         `Expected node to be an object, was passed "${typeof node}"`,
    
  133.       );
    
  134.     }
    
  135. 
    
  136.     if (typeof node.viewName !== 'string') {
    
  137.       throw new Error('Expected node to be a host node.');
    
  138.     }
    
  139. 
    
  140.     callback(10, 10, 100, 100, 0, 0);
    
  141.   }),
    
  142.   measureInWindow: jest.fn(function measureInWindow(node, callback) {
    
  143.     if (typeof node !== 'object') {
    
  144.       throw new Error(
    
  145.         `Expected node to be an object, was passed "${typeof node}"`,
    
  146.       );
    
  147.     }
    
  148. 
    
  149.     if (typeof node.viewName !== 'string') {
    
  150.       throw new Error('Expected node to be a host node.');
    
  151.     }
    
  152. 
    
  153.     callback(10, 10, 100, 100);
    
  154.   }),
    
  155.   getBoundingClientRect: jest.fn(function getBoundingClientRect(node) {
    
  156.     if (typeof node !== 'object') {
    
  157.       throw new Error(
    
  158.         `Expected node to be an object, was passed "${typeof node}"`,
    
  159.       );
    
  160.     }
    
  161. 
    
  162.     if (typeof node.viewName !== 'string') {
    
  163.       throw new Error('Expected node to be a host node.');
    
  164.     }
    
  165. 
    
  166.     return [10, 10, 100, 100];
    
  167.   }),
    
  168.   measureLayout: jest.fn(
    
  169.     function measureLayout(node, relativeNode, fail, success) {
    
  170.       if (typeof node !== 'object') {
    
  171.         throw new Error(
    
  172.           `Expected node to be an object, was passed "${typeof node}"`,
    
  173.         );
    
  174.       }
    
  175. 
    
  176.       if (typeof node.viewName !== 'string') {
    
  177.         throw new Error('Expected node to be a host node.');
    
  178.       }
    
  179. 
    
  180.       if (typeof relativeNode !== 'object') {
    
  181.         throw new Error(
    
  182.           `Expected relative node to be an object, was passed "${typeof relativeNode}"`,
    
  183.         );
    
  184.       }
    
  185. 
    
  186.       if (typeof relativeNode.viewName !== 'string') {
    
  187.         throw new Error('Expected relative node to be a host node.');
    
  188.       }
    
  189. 
    
  190.       success(1, 1, 100, 100);
    
  191.     },
    
  192.   ),
    
  193.   setIsJSResponder: jest.fn(),
    
  194. };
    
  195. 
    
  196. global.nativeFabricUIManager = RCTFabricUIManager;
    
  197. 
    
  198. // DOMRect isn't provided by jsdom, but it's used by `ReactFabricHostComponent`.
    
  199. // This is a basic implementation for testing.
    
  200. global.DOMRect = class DOMRect {
    
  201.   constructor(x, y, width, height) {
    
  202.     this.x = x;
    
  203.     this.y = y;
    
  204.     this.width = width;
    
  205.     this.height = height;
    
  206.   }
    
  207. 
    
  208.   toJSON() {
    
  209.     const {x, y, width, height} = this;
    
  210.     return {x, y, width, height};
    
  211.   }
    
  212. };