diff --git a/packages/react-dom/src/__tests__/ReactTestUtils-test.js b/packages/react-dom/src/__tests__/ReactTestUtils-test.js deleted file mode 100644 index 534b3538eb49b..0000000000000 --- a/packages/react-dom/src/__tests__/ReactTestUtils-test.js +++ /dev/null @@ -1,735 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @emails react-core - */ - -'use strict'; - -let React; -let ReactDOMClient; -let ReactDOMServer; -let ReactTestUtils; -let act; - -function getTestDocument(markup) { - const doc = document.implementation.createHTMLDocument(''); - doc.open(); - doc.write( - markup || - 'test doc', - ); - doc.close(); - return doc; -} - -describe('ReactTestUtils', () => { - beforeEach(() => { - React = require('react'); - ReactDOMClient = require('react-dom/client'); - ReactDOMServer = require('react-dom/server'); - ReactTestUtils = require('react-dom/test-utils'); - act = require('internal-test-utils').act; - }); - - // @gate !disableDOMTestUtils - it('Simulate should have locally attached media events', () => { - expect(Object.keys(ReactTestUtils.Simulate).sort()).toMatchInlineSnapshot(` - [ - "abort", - "animationEnd", - "animationIteration", - "animationStart", - "auxClick", - "beforeInput", - "beforeToggle", - "blur", - "canPlay", - "canPlayThrough", - "cancel", - "change", - "click", - "close", - "compositionEnd", - "compositionStart", - "compositionUpdate", - "contextMenu", - "copy", - "cut", - "doubleClick", - "drag", - "dragEnd", - "dragEnter", - "dragExit", - "dragLeave", - "dragOver", - "dragStart", - "drop", - "durationChange", - "emptied", - "encrypted", - "ended", - "error", - "focus", - "gotPointerCapture", - "input", - "invalid", - "keyDown", - "keyPress", - "keyUp", - "load", - "loadStart", - "loadedData", - "loadedMetadata", - "lostPointerCapture", - "mouseDown", - "mouseEnter", - "mouseLeave", - "mouseMove", - "mouseOut", - "mouseOver", - "mouseUp", - "paste", - "pause", - "play", - "playing", - "pointerCancel", - "pointerDown", - "pointerEnter", - "pointerLeave", - "pointerMove", - "pointerOut", - "pointerOver", - "pointerUp", - "progress", - "rateChange", - "reset", - "resize", - "scroll", - "seeked", - "seeking", - "select", - "stalled", - "submit", - "suspend", - "timeUpdate", - "toggle", - "touchCancel", - "touchEnd", - "touchMove", - "touchStart", - "transitionCancel", - "transitionEnd", - "transitionRun", - "transitionStart", - "volumeChange", - "waiting", - "wheel", - ] - `); - }); - - // @gate !disableDOMTestUtils - it('gives Jest mocks a passthrough implementation with mockComponent()', async () => { - class MockedComponent extends React.Component { - render() { - throw new Error('Should not get here.'); - } - } - // This is close enough to what a Jest mock would give us. - MockedComponent.prototype.render = jest.fn(); - - // Patch it up so it returns its children. - expect(() => ReactTestUtils.mockComponent(MockedComponent)).toWarnDev( - 'ReactTestUtils.mockComponent() is deprecated. ' + - 'Use shallow rendering or jest.mock() instead.\n\n' + - 'See https://react.dev/link/test-utils-mock-component for more information.', - {withoutStack: true}, - ); - - // De-duplication check - ReactTestUtils.mockComponent(MockedComponent); - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(Hello); - }); - - expect(container.textContent).toBe('Hello'); - }); - - // @gate !disableDOMTestUtils - it('can scryRenderedComponentsWithType', async () => { - class Child extends React.Component { - render() { - return null; - } - } - class Wrapper extends React.Component { - render() { - return ( -
- -
- ); - } - } - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - let renderedComponent; - await act(() => { - root.render( (renderedComponent = current)} />); - }); - const scryResults = ReactTestUtils.scryRenderedComponentsWithType( - renderedComponent, - Child, - ); - expect(scryResults.length).toBe(1); - }); - - // @gate !disableDOMTestUtils - it('can scryRenderedDOMComponentsWithClass with TextComponent', async () => { - class Wrapper extends React.Component { - render() { - return ( -
- Hello Jim -
- ); - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - let renderedComponent; - await act(() => { - root.render( (renderedComponent = current)} />); - }); - const scryResults = ReactTestUtils.scryRenderedDOMComponentsWithClass( - renderedComponent, - 'NonExistentClass', - ); - expect(scryResults.length).toBe(0); - }); - - // @gate !disableDOMTestUtils - it('can scryRenderedDOMComponentsWithClass with className contains \\n', async () => { - class Wrapper extends React.Component { - render() { - return ( -
- Hello Jim -
- ); - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - let renderedComponent; - await act(() => { - root.render( (renderedComponent = current)} />); - }); - const scryResults = ReactTestUtils.scryRenderedDOMComponentsWithClass( - renderedComponent, - 'x', - ); - expect(scryResults.length).toBe(1); - }); - - // @gate !disableDOMTestUtils - it('can scryRenderedDOMComponentsWithClass with multiple classes', async () => { - class Wrapper extends React.Component { - render() { - return ( -
- Hello Jim -
- ); - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - let renderedComponent; - await act(() => { - root.render( (renderedComponent = current)} />); - }); - const scryResults1 = ReactTestUtils.scryRenderedDOMComponentsWithClass( - renderedComponent, - 'x y', - ); - expect(scryResults1.length).toBe(1); - - const scryResults2 = ReactTestUtils.scryRenderedDOMComponentsWithClass( - renderedComponent, - 'x z', - ); - expect(scryResults2.length).toBe(1); - - const scryResults3 = ReactTestUtils.scryRenderedDOMComponentsWithClass( - renderedComponent, - ['x', 'y'], - ); - expect(scryResults3.length).toBe(1); - - expect(scryResults1[0]).toBe(scryResults2[0]); - expect(scryResults1[0]).toBe(scryResults3[0]); - - const scryResults4 = ReactTestUtils.scryRenderedDOMComponentsWithClass( - renderedComponent, - ['x', 'a'], - ); - expect(scryResults4.length).toBe(0); - - const scryResults5 = ReactTestUtils.scryRenderedDOMComponentsWithClass( - renderedComponent, - ['x a'], - ); - expect(scryResults5.length).toBe(0); - }); - - // @gate !disableDOMTestUtils - it('traverses children in the correct order', async () => { - class Wrapper extends React.Component { - render() { - return
{this.props.children}
; - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render( - - {null} -
purple
-
, - ); - }); - let tree; - await act(() => { - root.render( - (tree = current)}> -
orange
-
purple
-
, - ); - }); - - const log = []; - ReactTestUtils.findAllInRenderedTree(tree, function (child) { - if (ReactTestUtils.isDOMComponent(child)) { - log.push(child.textContent); - } - }); - - // Should be document order, not mount order (which would be purple, orange) - expect(log).toEqual(['orangepurple', 'orange', 'purple']); - }); - - // @gate !disableDOMTestUtils - it('should support injected wrapper components as DOM components', async () => { - const injectedDOMComponents = [ - 'button', - 'form', - 'iframe', - 'img', - 'input', - 'option', - 'select', - 'textarea', - ]; - - // eslint-disable-next-line no-for-of-loops/no-for-of-loops - for (const type of injectedDOMComponents) { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - let testComponent; - await act(() => { - root.render( - React.createElement(type, { - ref: current => (testComponent = current), - }), - ); - }); - - expect(testComponent.tagName).toBe(type.toUpperCase()); - expect(ReactTestUtils.isDOMComponent(testComponent)).toBe(true); - } - - // Full-page components (html, head, body) can't be rendered into a div - // directly... - class Root extends React.Component { - htmlRef = React.createRef(); - headRef = React.createRef(); - bodyRef = React.createRef(); - - render() { - return ( - - - hello - - hello, world - - ); - } - } - - const markup = ReactDOMServer.renderToString(); - const testDocument = getTestDocument(markup); - let component; - await act(() => { - ReactDOMClient.hydrateRoot( - testDocument, - (component = current)} />, - ); - }); - - expect(component.htmlRef.current.tagName).toBe('HTML'); - expect(component.headRef.current.tagName).toBe('HEAD'); - expect(component.bodyRef.current.tagName).toBe('BODY'); - expect(ReactTestUtils.isDOMComponent(component.htmlRef.current)).toBe(true); - expect(ReactTestUtils.isDOMComponent(component.headRef.current)).toBe(true); - expect(ReactTestUtils.isDOMComponent(component.bodyRef.current)).toBe(true); - }); - - // @gate !disableDOMTestUtils - it('can scry with stateless components involved', async () => { - const Function = () => ( -
-
-
- ); - - class SomeComponent extends React.Component { - render() { - return ( -
- -
-
- ); - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - let inst; - await act(() => { - root.render( (inst = current)} />); - }); - - const hrs = ReactTestUtils.scryRenderedDOMComponentsWithTag(inst, 'hr'); - expect(hrs.length).toBe(2); - }); - - // @gate !disableDOMTestUtils - it('provides a clear error when passing invalid objects to scry', () => { - // This is probably too relaxed but it's existing behavior. - ReactTestUtils.findAllInRenderedTree(null, 'span'); - ReactTestUtils.findAllInRenderedTree(undefined, 'span'); - ReactTestUtils.findAllInRenderedTree('', 'span'); - ReactTestUtils.findAllInRenderedTree(0, 'span'); - ReactTestUtils.findAllInRenderedTree(false, 'span'); - - expect(() => { - ReactTestUtils.findAllInRenderedTree([], 'span'); - }).toThrow( - 'The first argument must be a React class instance. ' + - 'Instead received: an array.', - ); - expect(() => { - ReactTestUtils.scryRenderedDOMComponentsWithClass(10, 'button'); - }).toThrow( - 'The first argument must be a React class instance. ' + - 'Instead received: 10.', - ); - expect(() => { - ReactTestUtils.findRenderedDOMComponentWithClass('hello', 'button'); - }).toThrow( - 'The first argument must be a React class instance. ' + - 'Instead received: hello.', - ); - expect(() => { - ReactTestUtils.scryRenderedDOMComponentsWithTag( - {x: true, y: false}, - 'span', - ); - }).toThrow( - 'The first argument must be a React class instance. ' + - 'Instead received: object with keys {x, y}.', - ); - const div = document.createElement('div'); - expect(() => { - ReactTestUtils.findRenderedDOMComponentWithTag(div, 'span'); - }).toThrow( - 'The first argument must be a React class instance. ' + - 'Instead received: a DOM node.', - ); - expect(() => { - ReactTestUtils.scryRenderedComponentsWithType(true, 'span'); - }).toThrow( - 'The first argument must be a React class instance. ' + - 'Instead received: true.', - ); - expect(() => { - ReactTestUtils.findRenderedComponentWithType(true, 'span'); - }).toThrow( - 'The first argument must be a React class instance. ' + - 'Instead received: true.', - ); - }); - - describe('Simulate', () => { - // @gate !disableDOMTestUtils - it('should change the value of an input field', async () => { - const obj = { - handler: function (e) { - e.persist(); - }, - }; - spyOnDevAndProd(obj, 'handler'); - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - const node = container.firstChild; - - node.value = 'giraffe'; - ReactTestUtils.Simulate.change(node); - - expect(obj.handler).toHaveBeenCalledWith( - expect.objectContaining({target: node}), - ); - }); - - // @gate !disableDOMTestUtils - it('should change the value of an input field in a component', async () => { - class SomeComponent extends React.Component { - inputRef = React.createRef(); - render() { - return ( -
- -
- ); - } - } - - const obj = { - handler: function (e) { - e.persist(); - }, - }; - spyOnDevAndProd(obj, 'handler'); - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - let instance; - await act(() => { - root.render( - (instance = current)} - />, - ); - }); - - const node = instance.inputRef.current; - node.value = 'zebra'; - ReactTestUtils.Simulate.change(node); - - expect(obj.handler).toHaveBeenCalledWith( - expect.objectContaining({target: node}), - ); - }); - - // @gate !disableDOMTestUtils - it('should not warn when used with extra properties', async () => { - const CLIENT_X = 100; - - class Component extends React.Component { - childRef = React.createRef(); - handleClick = e => { - expect(e.clientX).toBe(CLIENT_X); - }; - - render() { - return
; - } - } - - const element = document.createElement('div'); - const root = ReactDOMClient.createRoot(element); - let instance; - await act(() => { - root.render( (instance = current)} />); - }); - - ReactTestUtils.Simulate.click(instance.childRef.current, { - clientX: CLIENT_X, - }); - }); - - // @gate !disableDOMTestUtils - it('should set the type of the event', async () => { - let event; - const stub = jest.fn().mockImplementation(e => { - e.persist(); - event = e; - }); - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - let node; - await act(() => { - root.render(
(node = current)} />); - }); - - ReactTestUtils.Simulate.keyDown(node); - - expect(event.type).toBe('keydown'); - expect(event.nativeEvent.type).toBe('keydown'); - }); - - // @gate !disableDOMTestUtils - it('should work with renderIntoDocument', async () => { - const onChange = jest.fn(); - - class MyComponent extends React.Component { - render() { - return ( -
- -
- ); - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - let instance; - await act(() => { - root.render( (instance = current)} />); - }); - - const input = ReactTestUtils.findRenderedDOMComponentWithTag( - instance, - 'input', - ); - input.value = 'giraffe'; - ReactTestUtils.Simulate.change(input); - - expect(onChange).toHaveBeenCalledWith( - expect.objectContaining({target: input}), - ); - }); - - // @gate !disableDOMTestUtils - it('should have mouse enter simulated by test utils', async () => { - const idCallOrder = []; - const recordID = function (id) { - idCallOrder.push(id); - }; - let CHILD; - function Child(props) { - return ( -
(CHILD = current)} - onMouseEnter={() => { - recordID(CHILD); - }} - /> - ); - } - - class ChildWrapper extends React.PureComponent { - render() { - return ; - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render( -
-
- -
-
, - ); - }); - await act(() => { - ReactTestUtils.Simulate.mouseEnter(CHILD); - }); - expect(idCallOrder).toEqual([CHILD]); - }); - }); - - // @gate !disableDOMTestUtils - // @gate !disableLegacyMode - it('should call setState callback with no arguments', async () => { - let mockArgs; - class Component extends React.Component { - componentDidMount() { - this.setState({}, (...args) => (mockArgs = args)); - } - render() { - return false; - } - } - - ReactTestUtils.renderIntoDocument(); - - expect(mockArgs.length).toEqual(0); - }); - - // @gate !disableDOMTestUtils - it('should find rendered component with type in document', async () => { - class MyComponent extends React.Component { - render() { - return true; - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - let instance; - await act(() => { - root.render( (instance = current)} />); - }); - - const renderedComponentType = ReactTestUtils.findRenderedComponentWithType( - instance, - MyComponent, - ); - - expect(renderedComponentType).toBe(instance); - }); - - // @gate __DEV__ - it('warns when using `act`', () => { - expect(() => { - ReactTestUtils.act(() => {}); - }).toErrorDev( - [ - '`ReactDOMTestUtils.act` is deprecated in favor of `React.act`. ' + - 'Import `act` from `react` instead of `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ], - {withoutStack: true}, - ); - }); -}); diff --git a/packages/react-dom/src/test-utils/ReactTestUtilsFB.js b/packages/react-dom/src/test-utils/ReactTestUtilsFB.js deleted file mode 100644 index 39ac99c3bc100..0000000000000 --- a/packages/react-dom/src/test-utils/ReactTestUtilsFB.js +++ /dev/null @@ -1,884 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @noflow - */ - -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; -import {findCurrentFiberUsingSlowPath} from 'react-reconciler/src/ReactFiberTreeReflection'; -import {get as getInstance} from 'shared/ReactInstanceMap'; -import { - ClassComponent, - FunctionComponent, - HostComponent, - HostHoistable, - HostSingleton, - HostText, -} from 'react-reconciler/src/ReactWorkTags'; -import {SyntheticEvent} from 'react-dom-bindings/src/events/SyntheticEvent'; -import {ELEMENT_NODE} from 'react-dom-bindings/src/client/HTMLNodeType'; -import {disableDOMTestUtils} from 'shared/ReactFeatureFlags'; -import assign from 'shared/assign'; -import isArray from 'shared/isArray'; - -// Keep in sync with ReactDOM.js: -const SecretInternals = - ReactDOM.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; -const EventInternals = SecretInternals.Events; -const getInstanceFromNode = EventInternals[0]; -const getNodeFromInstance = EventInternals[1]; -const getFiberCurrentPropsFromNode = EventInternals[2]; -const enqueueStateRestore = EventInternals[3]; -const restoreStateIfNeeded = EventInternals[4]; - -let didWarnAboutUsingAct = false; -function act(callback) { - if (didWarnAboutUsingAct === false) { - didWarnAboutUsingAct = true; - console.error( - '`ReactDOMTestUtils.act` is deprecated in favor of `React.act`. ' + - 'Import `act` from `react` instead of `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - return React.act(callback); -} - -function Event(suffix) {} - -let hasWarnedAboutDeprecatedMockComponent = false; - -/** - * @class ReactTestUtils - */ - -function findAllInRenderedFiberTreeInternal(fiber, test) { - if (!fiber) { - return []; - } - const currentParent = findCurrentFiberUsingSlowPath(fiber); - if (!currentParent) { - return []; - } - let node = currentParent; - const ret = []; - while (true) { - if ( - node.tag === HostComponent || - node.tag === HostText || - node.tag === ClassComponent || - node.tag === FunctionComponent || - node.tag === HostHoistable || - node.tag === HostSingleton - ) { - const publicInst = node.stateNode; - if (test(publicInst)) { - ret.push(publicInst); - } - } - if (node.child) { - node.child.return = node; - node = node.child; - continue; - } - if (node === currentParent) { - return ret; - } - while (!node.sibling) { - if (!node.return || node.return === currentParent) { - return ret; - } - node = node.return; - } - node.sibling.return = node.return; - node = node.sibling; - } -} - -function validateClassInstance(inst, methodName) { - if (!inst) { - // This is probably too relaxed but it's existing behavior. - return; - } - if (getInstance(inst)) { - // This is a public instance indeed. - return; - } - let received; - const stringified = String(inst); - if (isArray(inst)) { - received = 'an array'; - } else if (inst && inst.nodeType === ELEMENT_NODE && inst.tagName) { - received = 'a DOM node'; - } else if (stringified === '[object Object]') { - received = 'object with keys {' + Object.keys(inst).join(', ') + '}'; - } else { - received = stringified; - } - - throw new Error( - `The first argument must be a React class instance. ` + - `Instead received: ${received}.`, - ); -} - -/** - * Utilities for making it easy to test React components. - * - * See https://reactjs.org/docs/test-utils.html - * - * Todo: Support the entire DOM.scry query syntax. For now, these simple - * utilities will suffice for testing purposes. - * @lends ReactTestUtils - */ -function renderIntoDocument(element) { - if (disableDOMTestUtils) { - throw new Error( - '`renderIntoDocument` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - const div = document.createElement('div'); - // None of our tests actually require attaching the container to the - // DOM, and doing so creates a mess that we rely on test isolation to - // clean up, so we're going to stop honoring the name of this method - // (and probably rename it eventually) if no problems arise. - // document.documentElement.appendChild(div); - return ReactDOM.render(element, div); -} - -function isElement(element) { - if (disableDOMTestUtils) { - throw new Error( - '`isElement` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - return React.isValidElement(element); -} - -function isElementOfType(inst, convenienceConstructor) { - if (disableDOMTestUtils) { - throw new Error( - '`isElementOfType` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - return React.isValidElement(inst) && inst.type === convenienceConstructor; -} - -function isDOMComponent(inst) { - if (disableDOMTestUtils) { - throw new Error( - '`isDOMComponent` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - return !!(inst && inst.nodeType === ELEMENT_NODE && inst.tagName); -} - -function isDOMComponentElement(inst) { - if (disableDOMTestUtils) { - throw new Error( - '`isDOMComponentElement` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - return !!(inst && React.isValidElement(inst) && !!inst.tagName); -} - -function isCompositeComponent(inst) { - if (disableDOMTestUtils) { - throw new Error( - '`isCompositeComponent` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - if (isDOMComponent(inst)) { - // Accessing inst.setState warns; just return false as that'll be what - // this returns when we have DOM nodes as refs directly - return false; - } - return ( - inst != null && - typeof inst.render === 'function' && - typeof inst.setState === 'function' - ); -} - -function isCompositeComponentWithType(inst, type) { - if (disableDOMTestUtils) { - throw new Error( - '`isCompositeComponentWithType` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - if (!isCompositeComponent(inst)) { - return false; - } - const internalInstance = getInstance(inst); - const constructor = internalInstance.type; - return constructor === type; -} - -function findAllInRenderedTree(inst, test) { - if (disableDOMTestUtils) { - throw new Error( - '`findAllInRenderedTree` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - validateClassInstance(inst, 'findAllInRenderedTree'); - if (!inst) { - return []; - } - const internalInstance = getInstance(inst); - return findAllInRenderedFiberTreeInternal(internalInstance, test); -} - -/** - * Finds all instances of components in the rendered tree that are DOM - * components with the class name matching `className`. - * @return {array} an array of all the matches. - */ -function scryRenderedDOMComponentsWithClass(root, classNames) { - if (disableDOMTestUtils) { - throw new Error( - '`scryRenderedDOMComponentsWithClass` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - validateClassInstance(root, 'scryRenderedDOMComponentsWithClass'); - return findAllInRenderedTree(root, function (inst) { - if (isDOMComponent(inst)) { - let className = inst.className; - if (typeof className !== 'string') { - // SVG, probably. - className = inst.getAttribute('class') || ''; - } - const classList = className.split(/\s+/); - - if (!isArray(classNames)) { - if (classNames === undefined) { - throw new Error( - 'TestUtils.scryRenderedDOMComponentsWithClass expects a ' + - 'className as a second argument.', - ); - } - - classNames = classNames.split(/\s+/); - } - return classNames.every(function (name) { - return classList.indexOf(name) !== -1; - }); - } - return false; - }); -} - -/** - * Like scryRenderedDOMComponentsWithClass but expects there to be one result, - * and returns that one result, or throws exception if there is any other - * number of matches besides one. - * @return {!ReactDOMComponent} The one match. - */ -function findRenderedDOMComponentWithClass(root, className) { - if (disableDOMTestUtils) { - throw new Error( - '`findRenderedDOMComponentWithClass` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - validateClassInstance(root, 'findRenderedDOMComponentWithClass'); - const all = scryRenderedDOMComponentsWithClass(root, className); - if (all.length !== 1) { - throw new Error( - 'Did not find exactly one match (found: ' + - all.length + - ') ' + - 'for class:' + - className, - ); - } - return all[0]; -} - -/** - * Finds all instances of components in the rendered tree that are DOM - * components with the tag name matching `tagName`. - * @return {array} an array of all the matches. - */ -function scryRenderedDOMComponentsWithTag(root, tagName) { - if (disableDOMTestUtils) { - throw new Error( - '`scryRenderedDOMComponentsWithTag` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - validateClassInstance(root, 'scryRenderedDOMComponentsWithTag'); - return findAllInRenderedTree(root, function (inst) { - return ( - isDOMComponent(inst) && - inst.tagName.toUpperCase() === tagName.toUpperCase() - ); - }); -} - -/** - * Like scryRenderedDOMComponentsWithTag but expects there to be one result, - * and returns that one result, or throws exception if there is any other - * number of matches besides one. - * @return {!ReactDOMComponent} The one match. - */ -function findRenderedDOMComponentWithTag(root, tagName) { - if (disableDOMTestUtils) { - throw new Error( - '`findRenderedDOMComponentWithTag` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - validateClassInstance(root, 'findRenderedDOMComponentWithTag'); - const all = scryRenderedDOMComponentsWithTag(root, tagName); - if (all.length !== 1) { - throw new Error( - 'Did not find exactly one match (found: ' + - all.length + - ') ' + - 'for tag:' + - tagName, - ); - } - return all[0]; -} - -/** - * Finds all instances of components with type equal to `componentType`. - * @return {array} an array of all the matches. - */ -function scryRenderedComponentsWithType(root, componentType) { - if (disableDOMTestUtils) { - throw new Error( - '`scryRenderedComponentsWithType` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - validateClassInstance(root, 'scryRenderedComponentsWithType'); - return findAllInRenderedTree(root, function (inst) { - return isCompositeComponentWithType(inst, componentType); - }); -} - -/** - * Same as `scryRenderedComponentsWithType` but expects there to be one result - * and returns that one result, or throws exception if there is any other - * number of matches besides one. - * @return {!ReactComponent} The one match. - */ -function findRenderedComponentWithType(root, componentType) { - if (disableDOMTestUtils) { - throw new Error( - '`findRenderedComponentWithType` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - validateClassInstance(root, 'findRenderedComponentWithType'); - const all = scryRenderedComponentsWithType(root, componentType); - if (all.length !== 1) { - throw new Error( - 'Did not find exactly one match (found: ' + - all.length + - ') ' + - 'for componentType:' + - componentType, - ); - } - return all[0]; -} - -/** - * Pass a mocked component module to this method to augment it with - * useful methods that allow it to be used as a dummy React component. - * Instead of rendering as usual, the component will become a simple - *
containing any provided children. - * - * @param {object} module the mock function object exported from a - * module that defines the component to be mocked - * @param {?string} mockTagName optional dummy root tag name to return - * from render method (overrides - * module.mockTagName if provided) - * @return {object} the ReactTestUtils object (for chaining) - */ -function mockComponent(module, mockTagName) { - if (disableDOMTestUtils) { - throw new Error( - '`mockComponent` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - if (__DEV__) { - if (!hasWarnedAboutDeprecatedMockComponent) { - hasWarnedAboutDeprecatedMockComponent = true; - console.warn( - 'ReactTestUtils.mockComponent() is deprecated. ' + - 'Use shallow rendering or jest.mock() instead.\n\n' + - 'See https://react.dev/link/test-utils-mock-component for more information.', - ); - } - } - - mockTagName = mockTagName || module.mockTagName || 'div'; - - module.prototype.render.mockImplementation(function () { - return React.createElement(mockTagName, null, this.props.children); - }); - - return this; -} - -function nativeTouchData(x, y) { - if (disableDOMTestUtils) { - throw new Error( - '`nativeTouchData` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - return { - touches: [{pageX: x, pageY: y}], - }; -} - -// Start of inline: the below functions were inlined from -// EventPropagator.js, as they deviated from ReactDOM's newer -// implementations. - -let hasError: boolean = false; -let caughtError: mixed = null; - -/** - * Dispatch the event to the listener. - * @param {SyntheticEvent} event SyntheticEvent to handle - * @param {function} listener Application-level callback - * @param {*} inst Internal component instance - */ -function executeDispatch(event, listener, inst) { - event.currentTarget = getNodeFromInstance(inst); - try { - listener(event); - } catch (error) { - if (!hasError) { - hasError = true; - caughtError = error; - } - } - event.currentTarget = null; -} - -/** - * Standard/simple iteration through an event's collected dispatches. - */ -function executeDispatchesInOrder(event) { - const dispatchListeners = event._dispatchListeners; - const dispatchInstances = event._dispatchInstances; - if (isArray(dispatchListeners)) { - for (let i = 0; i < dispatchListeners.length; i++) { - if (event.isPropagationStopped()) { - break; - } - // Listeners and Instances are two parallel arrays that are always in sync. - executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); - } - } else if (dispatchListeners) { - executeDispatch(event, dispatchListeners, dispatchInstances); - } - event._dispatchListeners = null; - event._dispatchInstances = null; -} - -/** - * Dispatches an event and releases it back into the pool, unless persistent. - * - * @param {?object} event Synthetic event to be dispatched. - * @private - */ -function executeDispatchesAndRelease(event /* ReactSyntheticEvent */) { - if (event) { - executeDispatchesInOrder(event); - - if (!event.isPersistent()) { - event.constructor.release(event); - } - } -} - -function isInteractive(tag) { - return ( - tag === 'button' || - tag === 'input' || - tag === 'select' || - tag === 'textarea' - ); -} - -function getParent(inst) { - do { - inst = inst.return; - // TODO: If this is a HostRoot we might want to bail out. - // That is depending on if we want nested subtrees (layers) to bubble - // events to their parent. We could also go through parentNode on the - // host node but that wouldn't work for React Native and doesn't let us - // do the portal feature. - } while (inst && inst.tag !== HostComponent && inst.tag !== HostSingleton); - if (inst) { - return inst; - } - return null; -} - -/** - * Simulates the traversal of a two-phase, capture/bubble event dispatch. - */ -export function traverseTwoPhase(inst, fn, arg) { - const path = []; - while (inst) { - path.push(inst); - inst = getParent(inst); - } - let i; - for (i = path.length; i-- > 0; ) { - fn(path[i], 'captured', arg); - } - for (i = 0; i < path.length; i++) { - fn(path[i], 'bubbled', arg); - } -} - -function shouldPreventMouseEvent(name, type, props) { - switch (name) { - case 'onClick': - case 'onClickCapture': - case 'onDoubleClick': - case 'onDoubleClickCapture': - case 'onMouseDown': - case 'onMouseDownCapture': - case 'onMouseMove': - case 'onMouseMoveCapture': - case 'onMouseUp': - case 'onMouseUpCapture': - case 'onMouseEnter': - return !!(props.disabled && isInteractive(type)); - default: - return false; - } -} - -/** - * @param {object} inst The instance, which is the source of events. - * @param {string} registrationName Name of listener (e.g. `onClick`). - * @return {?function} The stored callback. - */ -function getListener(inst /* Fiber */, registrationName: string) { - // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not - // live here; needs to be moved to a better place soon - const stateNode = inst.stateNode; - if (!stateNode) { - // Work in progress (ex: onload events in incremental mode). - return null; - } - const props = getFiberCurrentPropsFromNode(stateNode); - if (!props) { - // Work in progress. - return null; - } - const listener = props[registrationName]; - if (shouldPreventMouseEvent(registrationName, inst.type, props)) { - return null; - } - - if (listener && typeof listener !== 'function') { - throw new Error( - `Expected \`${registrationName}\` listener to be a function, instead got a value of \`${typeof listener}\` type.`, - ); - } - - return listener; -} - -function listenerAtPhase(inst, event, propagationPhase: PropagationPhases) { - let registrationName = event._reactName; - if (propagationPhase === 'captured') { - registrationName += 'Capture'; - } - return getListener(inst, registrationName); -} - -function accumulateDispatches(inst, ignoredDirection, event) { - if (inst && event && event._reactName) { - const registrationName = event._reactName; - const listener = getListener(inst, registrationName); - if (listener) { - if (event._dispatchListeners == null) { - event._dispatchListeners = []; - } - if (event._dispatchInstances == null) { - event._dispatchInstances = []; - } - event._dispatchListeners.push(listener); - event._dispatchInstances.push(inst); - } - } -} - -function accumulateDirectionalDispatches(inst, phase, event) { - if (__DEV__) { - if (!inst) { - console.error('Dispatching inst must not be null'); - } - } - const listener = listenerAtPhase(inst, event, phase); - if (listener) { - if (event._dispatchListeners == null) { - event._dispatchListeners = []; - } - if (event._dispatchInstances == null) { - event._dispatchInstances = []; - } - event._dispatchListeners.push(listener); - event._dispatchInstances.push(inst); - } -} - -function accumulateDirectDispatchesSingle(event) { - if (event && event._reactName) { - accumulateDispatches(event._targetInst, null, event); - } -} - -function accumulateTwoPhaseDispatchesSingle(event) { - if (event && event._reactName) { - traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); - } -} - -// End of inline - -const Simulate = {}; - -const directDispatchEventTypes = new Set([ - 'mouseEnter', - 'mouseLeave', - 'pointerEnter', - 'pointerLeave', -]); - -/** - * Exports: - * - * - `Simulate.click(Element)` - * - `Simulate.mouseMove(Element)` - * - `Simulate.change(Element)` - * - ... (All keys from event plugin `eventTypes` objects) - */ -function makeSimulator(eventType) { - return function (domNode, eventData) { - if (disableDOMTestUtils) { - throw new Error( - '`Simulate` was removed from `react-dom/test-utils`. ' + - 'See https://react.dev/warnings/react-dom-test-utils for more info.', - ); - } - - if (React.isValidElement(domNode)) { - throw new Error( - 'TestUtils.Simulate expected a DOM node as the first argument but received ' + - 'a React element. Pass the DOM node you wish to simulate the event on instead. ' + - 'Note that TestUtils.Simulate will not work if you are using shallow rendering.', - ); - } - - if (isCompositeComponent(domNode)) { - throw new Error( - 'TestUtils.Simulate expected a DOM node as the first argument but received ' + - 'a component instance. Pass the DOM node you wish to simulate the event on instead.', - ); - } - - const reactName = 'on' + eventType[0].toUpperCase() + eventType.slice(1); - const fakeNativeEvent = new Event(); - fakeNativeEvent.target = domNode; - fakeNativeEvent.type = eventType.toLowerCase(); - - const targetInst = getInstanceFromNode(domNode); - const event = new SyntheticEvent( - reactName, - fakeNativeEvent.type, - targetInst, - fakeNativeEvent, - domNode, - ); - - // Since we aren't using pooling, always persist the event. This will make - // sure it's marked and won't warn when setting additional properties. - event.persist(); - assign(event, eventData); - - if (directDispatchEventTypes.has(eventType)) { - accumulateDirectDispatchesSingle(event); - } else { - accumulateTwoPhaseDispatchesSingle(event); - } - - ReactDOM.unstable_batchedUpdates(function () { - // Normally extractEvent enqueues a state restore, but we'll just always - // do that since we're by-passing it here. - enqueueStateRestore(domNode); - executeDispatchesAndRelease(event); - if (hasError) { - const error = caughtError; - hasError = false; - caughtError = null; - throw error; - } - }); - restoreStateIfNeeded(); - }; -} - -// A one-time snapshot with no plans to update. We'll probably want to deprecate Simulate API. -const simulatedEventTypes = [ - 'blur', - 'cancel', - 'click', - 'close', - 'contextMenu', - 'copy', - 'cut', - 'auxClick', - 'doubleClick', - 'dragEnd', - 'dragStart', - 'drop', - 'focus', - 'input', - 'invalid', - 'keyDown', - 'keyPress', - 'keyUp', - 'mouseDown', - 'mouseUp', - 'paste', - 'pause', - 'play', - 'pointerCancel', - 'pointerDown', - 'pointerUp', - 'rateChange', - 'reset', - 'resize', - 'seeked', - 'submit', - 'touchCancel', - 'touchEnd', - 'touchStart', - 'volumeChange', - 'drag', - 'dragEnter', - 'dragExit', - 'dragLeave', - 'dragOver', - 'mouseMove', - 'mouseOut', - 'mouseOver', - 'pointerMove', - 'pointerOut', - 'pointerOver', - 'scroll', - 'toggle', - 'touchMove', - 'wheel', - 'abort', - 'animationEnd', - 'animationIteration', - 'animationStart', - 'canPlay', - 'canPlayThrough', - 'durationChange', - 'emptied', - 'encrypted', - 'ended', - 'error', - 'gotPointerCapture', - 'load', - 'loadedData', - 'loadedMetadata', - 'loadStart', - 'lostPointerCapture', - 'playing', - 'progress', - 'seeking', - 'stalled', - 'suspend', - 'timeUpdate', - 'transitionRun', - 'transitionStart', - 'transitionCancel', - 'transitionEnd', - 'waiting', - 'mouseEnter', - 'mouseLeave', - 'pointerEnter', - 'pointerLeave', - 'change', - 'select', - 'beforeInput', - 'beforeToggle', - 'compositionEnd', - 'compositionStart', - 'compositionUpdate', -]; -function buildSimulators() { - simulatedEventTypes.forEach(eventType => { - Simulate[eventType] = makeSimulator(eventType); - }); -} -buildSimulators(); - -export { - renderIntoDocument, - isElement, - isElementOfType, - isDOMComponent, - isDOMComponentElement, - isCompositeComponent, - isCompositeComponentWithType, - findAllInRenderedTree, - scryRenderedDOMComponentsWithClass, - findRenderedDOMComponentWithClass, - scryRenderedDOMComponentsWithTag, - findRenderedDOMComponentWithTag, - scryRenderedComponentsWithType, - findRenderedComponentWithType, - mockComponent, - nativeTouchData, - Simulate, - act, -}; diff --git a/packages/react-dom/test-utils.fb.js b/packages/react-dom/test-utils.fb.js deleted file mode 100644 index dc43cbed3fcbd..0000000000000 --- a/packages/react-dom/test-utils.fb.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -export * from './src/test-utils/ReactTestUtilsFB'; diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 35a2e822e480c..adec53c109352 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -192,8 +192,6 @@ export const enableReactTestRendererWarning = true; // before removing them in stable in the next Major export const disableLegacyMode = true; -export const disableDOMTestUtils = true; - // Make equivalent to instead of export const enableRenderableContext = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 7ea580bd70c5a..f5387abb03c41 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -98,8 +98,6 @@ export const disableStringRefs = true; export const enableReactTestRendererWarning = false; export const disableLegacyMode = false; -export const disableDOMTestUtils = false; - export const enableOwnerStacks = false; // Flow magic to verify the exports of this file match the original version. diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 7e16ee25b4578..f6820d3bf5803 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -22,7 +22,6 @@ export const enableRefAsProp = __TODO_NEXT_RN_MAJOR__; export const disableStringRefs = __TODO_NEXT_RN_MAJOR__; export const enableFastJSX = __TODO_NEXT_RN_MAJOR__; export const disableLegacyMode = __TODO_NEXT_RN_MAJOR__; -export const disableDOMTestUtils = __TODO_NEXT_RN_MAJOR__; export const useModernStrictMode = __TODO_NEXT_RN_MAJOR__; export const enableReactTestRendererWarning = __TODO_NEXT_RN_MAJOR__; export const enableAsyncActions = __TODO_NEXT_RN_MAJOR__; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 4504d08fecca0..24d94adaf82ec 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -92,7 +92,6 @@ export const disableStringRefs = true; export const enableFastJSX = true; export const disableLegacyMode = true; export const disableLegacyContext = true; -export const disableDOMTestUtils = true; export const enableRenderableContext = true; export const enableReactTestRendererWarning = true; export const disableDefaultPropsExceptForClasses = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 41aea40e765d2..731aa42147579 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -85,7 +85,6 @@ export const enableFastJSX = true; export const enableReactTestRendererWarning = false; export const disableLegacyMode = false; -export const disableDOMTestUtils = false; export const disableDefaultPropsExceptForClasses = false; export const enableAddPropertiesFastPath = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 0aac888de99ec..9f5aa656c8bc1 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -85,7 +85,6 @@ export const enableFastJSX = false; export const enableReactTestRendererWarning = false; export const disableLegacyMode = false; -export const disableDOMTestUtils = false; export const disableDefaultPropsExceptForClasses = false; export const enableAddPropertiesFastPath = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index f135724f99944..de8fdc2c0a186 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -120,8 +120,6 @@ export const disableStringRefs = false; export const disableLegacyMode = __EXPERIMENTAL__; -export const disableDOMTestUtils = false; - export const enableOwnerStacks = false; // Flow magic to verify the exports of this file match the original version. diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 09ffb11723348..66e59124ca2d5 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -231,7 +231,7 @@ const bundles = [ /******* Test Utils *******/ { moduleType: RENDERER_UTILS, - bundleTypes: [FB_WWW_DEV, NODE_DEV, NODE_PROD], + bundleTypes: [NODE_DEV, NODE_PROD], entry: 'react-dom/test-utils', global: 'ReactTestUtils', minifyWithProdErrorCodes: false,