/** * 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 ReactDOM; let ReactIs; let SuspenseList; describe('ReactIs', () => { beforeEach(() => { jest.resetModules(); React = require('react'); ReactDOM = require('react-dom'); ReactIs = require('react-is'); if (gate(flags => flags.enableSuspenseList)) { SuspenseList = React.unstable_SuspenseList; } }); it('should return undefined for unknown/invalid types', () => { expect(ReactIs.typeOf('abc')).toBe(undefined); expect(ReactIs.typeOf(true)).toBe(undefined); expect(ReactIs.typeOf(123)).toBe(undefined); expect(ReactIs.typeOf({})).toBe(undefined); expect(ReactIs.typeOf(null)).toBe(undefined); expect(ReactIs.typeOf(undefined)).toBe(undefined); expect(ReactIs.typeOf(NaN)).toBe(undefined); expect(ReactIs.typeOf(Symbol('def'))).toBe(undefined); }); it('identifies valid element types', () => { class Component extends React.Component { render() { return React.createElement('div'); } } class PureComponent extends React.PureComponent { render() { return React.createElement('div'); } } const FunctionComponent = () => React.createElement('div'); const ForwardRefComponent = React.forwardRef((props, ref) => React.createElement(Component, {forwardedRef: ref, ...props}), ); const LazyComponent = React.lazy(() => Component); const MemoComponent = React.memo(Component); const Context = React.createContext(false); expect(ReactIs.isValidElementType('div')).toEqual(true); expect(ReactIs.isValidElementType(Component)).toEqual(true); expect(ReactIs.isValidElementType(PureComponent)).toEqual(true); expect(ReactIs.isValidElementType(FunctionComponent)).toEqual(true); expect(ReactIs.isValidElementType(ForwardRefComponent)).toEqual(true); expect(ReactIs.isValidElementType(LazyComponent)).toEqual(true); expect(ReactIs.isValidElementType(MemoComponent)).toEqual(true); expect(ReactIs.isValidElementType(Context.Provider)).toEqual(true); expect(ReactIs.isValidElementType(Context.Consumer)).toEqual(true); expect(ReactIs.isValidElementType(React.Fragment)).toEqual(true); expect(ReactIs.isValidElementType(React.StrictMode)).toEqual(true); expect(ReactIs.isValidElementType(React.Suspense)).toEqual(true); expect(ReactIs.isValidElementType(true)).toEqual(false); expect(ReactIs.isValidElementType(123)).toEqual(false); expect(ReactIs.isValidElementType({})).toEqual(false); expect(ReactIs.isValidElementType(null)).toEqual(false); expect(ReactIs.isValidElementType(undefined)).toEqual(false); expect(ReactIs.isValidElementType({type: 'div', props: {}})).toEqual(false); }); it('should identify context consumers', () => { const Context = React.createContext(false); expect(ReactIs.isValidElementType(Context.Consumer)).toBe(true); expect(ReactIs.typeOf()).toBe(ReactIs.ContextConsumer); expect(ReactIs.isContextConsumer()).toBe(true); expect(ReactIs.isContextConsumer()).toBe(false); expect(ReactIs.isContextConsumer(
)).toBe(false); }); it('should identify context providers', () => { const Context = React.createContext(false); expect(ReactIs.isValidElementType(Context.Provider)).toBe(true); expect(ReactIs.typeOf()).toBe(ReactIs.ContextProvider); expect(ReactIs.isContextProvider()).toBe(true); expect(ReactIs.isContextProvider()).toBe(false); expect(ReactIs.isContextProvider(
)).toBe(false); }); it('should identify elements', () => { expect(ReactIs.typeOf(
)).toBe(ReactIs.Element); expect(ReactIs.isElement(
)).toBe(true); expect(ReactIs.isElement('div')).toBe(false); expect(ReactIs.isElement(true)).toBe(false); expect(ReactIs.isElement(123)).toBe(false); expect(ReactIs.isElement(null)).toBe(false); expect(ReactIs.isElement(undefined)).toBe(false); expect(ReactIs.isElement({})).toBe(false); // It should also identify more specific types as elements const Context = React.createContext(false); expect(ReactIs.isElement()).toBe(true); expect(ReactIs.isElement()).toBe(true); expect(ReactIs.isElement()).toBe(true); expect(ReactIs.isElement()).toBe(true); expect(ReactIs.isElement()).toBe(true); }); it('should identify ref forwarding component', () => { const RefForwardingComponent = React.forwardRef((props, ref) => null); expect(ReactIs.isValidElementType(RefForwardingComponent)).toBe(true); expect(ReactIs.typeOf()).toBe(ReactIs.ForwardRef); expect(ReactIs.isForwardRef()).toBe(true); expect(ReactIs.isForwardRef({type: ReactIs.StrictMode})).toBe(false); expect(ReactIs.isForwardRef(
)).toBe(false); }); it('should identify fragments', () => { expect(ReactIs.isValidElementType(React.Fragment)).toBe(true); expect(ReactIs.typeOf()).toBe(ReactIs.Fragment); expect(ReactIs.isFragment()).toBe(true); expect(ReactIs.isFragment({type: ReactIs.Fragment})).toBe(false); expect(ReactIs.isFragment('React.Fragment')).toBe(false); expect(ReactIs.isFragment(
)).toBe(false); expect(ReactIs.isFragment([])).toBe(false); }); it('should identify portals', () => { const div = document.createElement('div'); const portal = ReactDOM.createPortal(
, div); expect(ReactIs.isValidElementType(portal)).toBe(false); expect(ReactIs.typeOf(portal)).toBe(ReactIs.Portal); expect(ReactIs.isPortal(portal)).toBe(true); expect(ReactIs.isPortal(div)).toBe(false); }); it('should identify memo', () => { const Component = () => React.createElement('div'); const Memoized = React.memo(Component); expect(ReactIs.isValidElementType(Memoized)).toBe(true); expect(ReactIs.typeOf()).toBe(ReactIs.Memo); expect(ReactIs.isMemo()).toBe(true); expect(ReactIs.isMemo()).toBe(false); }); it('should identify lazy', () => { const Component = () => React.createElement('div'); const LazyComponent = React.lazy(() => Component); expect(ReactIs.isValidElementType(LazyComponent)).toBe(true); expect(ReactIs.typeOf()).toBe(ReactIs.Lazy); expect(ReactIs.isLazy()).toBe(true); expect(ReactIs.isLazy()).toBe(false); }); it('should identify strict mode', () => { expect(ReactIs.isValidElementType(React.StrictMode)).toBe(true); expect(ReactIs.typeOf()).toBe(ReactIs.StrictMode); expect(ReactIs.isStrictMode()).toBe(true); expect(ReactIs.isStrictMode({type: ReactIs.StrictMode})).toBe(false); expect(ReactIs.isStrictMode(
)).toBe(false); }); it('should identify suspense', () => { expect(ReactIs.isValidElementType(React.Suspense)).toBe(true); expect(ReactIs.typeOf()).toBe(ReactIs.Suspense); expect(ReactIs.isSuspense()).toBe(true); expect(ReactIs.isSuspense({type: ReactIs.Suspense})).toBe(false); expect(ReactIs.isSuspense('React.Suspense')).toBe(false); expect(ReactIs.isSuspense(
)).toBe(false); }); // @gate enableSuspenseList it('should identify suspense list', () => { expect(ReactIs.isValidElementType(SuspenseList)).toBe(true); expect(ReactIs.typeOf()).toBe(ReactIs.SuspenseList); expect(ReactIs.isSuspenseList()).toBe(true); expect(ReactIs.isSuspenseList({type: ReactIs.SuspenseList})).toBe(false); expect(ReactIs.isSuspenseList('React.SuspenseList')).toBe(false); expect(ReactIs.isSuspenseList(
)).toBe(false); }); it('should identify profile root', () => { expect(ReactIs.isValidElementType(React.Profiler)).toBe(true); expect( ReactIs.typeOf(), ).toBe(ReactIs.Profiler); expect( ReactIs.isProfiler(), ).toBe(true); expect(ReactIs.isProfiler({type: ReactIs.Profiler})).toBe(false); expect(ReactIs.isProfiler(
)).toBe(false); }); });