main
js 203 lines 8.45 KB
Raw
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 * @emails react-core
8 */
9
10 'use strict';
11
12 let React;
13 let ReactDOM;
14 let ReactIs;
15 let SuspenseList;
16
17 describe('ReactIs', () => {
18 beforeEach(() => {
19 jest.resetModules();
20
21 React = require('react');
22 ReactDOM = require('react-dom');
23 ReactIs = require('react-is');
24
25 if (gate(flags => flags.enableSuspenseList)) {
26 SuspenseList = React.unstable_SuspenseList;
27 }
28 });
29
30 it('should return undefined for unknown/invalid types', () => {
31 expect(ReactIs.typeOf('abc')).toBe(undefined);
32 expect(ReactIs.typeOf(true)).toBe(undefined);
33 expect(ReactIs.typeOf(123)).toBe(undefined);
34 expect(ReactIs.typeOf({})).toBe(undefined);
35 expect(ReactIs.typeOf(null)).toBe(undefined);
36 expect(ReactIs.typeOf(undefined)).toBe(undefined);
37 expect(ReactIs.typeOf(NaN)).toBe(undefined);
38 expect(ReactIs.typeOf(Symbol('def'))).toBe(undefined);
39 });
40
41 it('identifies valid element types', () => {
42 class Component extends React.Component {
43 render() {
44 return React.createElement('div');
45 }
46 }
47 class PureComponent extends React.PureComponent {
48 render() {
49 return React.createElement('div');
50 }
51 }
52
53 const FunctionComponent = () => React.createElement('div');
54 const ForwardRefComponent = React.forwardRef((props, ref) =>
55 React.createElement(Component, {forwardedRef: ref, ...props}),
56 );
57 const LazyComponent = React.lazy(() => Component);
58 const MemoComponent = React.memo(Component);
59 const Context = React.createContext(false);
60
61 expect(ReactIs.isValidElementType('div')).toEqual(true);
62 expect(ReactIs.isValidElementType(Component)).toEqual(true);
63 expect(ReactIs.isValidElementType(PureComponent)).toEqual(true);
64 expect(ReactIs.isValidElementType(FunctionComponent)).toEqual(true);
65 expect(ReactIs.isValidElementType(ForwardRefComponent)).toEqual(true);
66 expect(ReactIs.isValidElementType(LazyComponent)).toEqual(true);
67 expect(ReactIs.isValidElementType(MemoComponent)).toEqual(true);
68 expect(ReactIs.isValidElementType(Context.Provider)).toEqual(true);
69 expect(ReactIs.isValidElementType(Context.Consumer)).toEqual(true);
70 expect(ReactIs.isValidElementType(React.Fragment)).toEqual(true);
71 expect(ReactIs.isValidElementType(React.StrictMode)).toEqual(true);
72 expect(ReactIs.isValidElementType(React.Suspense)).toEqual(true);
73
74 expect(ReactIs.isValidElementType(true)).toEqual(false);
75 expect(ReactIs.isValidElementType(123)).toEqual(false);
76 expect(ReactIs.isValidElementType({})).toEqual(false);
77 expect(ReactIs.isValidElementType(null)).toEqual(false);
78 expect(ReactIs.isValidElementType(undefined)).toEqual(false);
79 expect(ReactIs.isValidElementType({type: 'div', props: {}})).toEqual(false);
80 });
81
82 it('should identify context consumers', () => {
83 const Context = React.createContext(false);
84 expect(ReactIs.isValidElementType(Context.Consumer)).toBe(true);
85 expect(ReactIs.typeOf(<Context.Consumer />)).toBe(ReactIs.ContextConsumer);
86 expect(ReactIs.isContextConsumer(<Context.Consumer />)).toBe(true);
87 expect(ReactIs.isContextConsumer(<Context.Provider />)).toBe(false);
88 expect(ReactIs.isContextConsumer(<div />)).toBe(false);
89 });
90
91 it('should identify context providers', () => {
92 const Context = React.createContext(false);
93 expect(ReactIs.isValidElementType(Context.Provider)).toBe(true);
94 expect(ReactIs.typeOf(<Context.Provider />)).toBe(ReactIs.ContextProvider);
95 expect(ReactIs.isContextProvider(<Context.Provider />)).toBe(true);
96 expect(ReactIs.isContextProvider(<Context.Consumer />)).toBe(false);
97 expect(ReactIs.isContextProvider(<div />)).toBe(false);
98 });
99
100 it('should identify elements', () => {
101 expect(ReactIs.typeOf(<div />)).toBe(ReactIs.Element);
102 expect(ReactIs.isElement(<div />)).toBe(true);
103 expect(ReactIs.isElement('div')).toBe(false);
104 expect(ReactIs.isElement(true)).toBe(false);
105 expect(ReactIs.isElement(123)).toBe(false);
106 expect(ReactIs.isElement(null)).toBe(false);
107 expect(ReactIs.isElement(undefined)).toBe(false);
108 expect(ReactIs.isElement({})).toBe(false);
109
110 // It should also identify more specific types as elements
111 const Context = React.createContext(false);
112 expect(ReactIs.isElement(<Context.Provider />)).toBe(true);
113 expect(ReactIs.isElement(<Context.Consumer />)).toBe(true);
114 expect(ReactIs.isElement(<React.Fragment />)).toBe(true);
115 expect(ReactIs.isElement(<React.StrictMode />)).toBe(true);
116 expect(ReactIs.isElement(<React.Suspense />)).toBe(true);
117 });
118
119 it('should identify ref forwarding component', () => {
120 const RefForwardingComponent = React.forwardRef((props, ref) => null);
121 expect(ReactIs.isValidElementType(RefForwardingComponent)).toBe(true);
122 expect(ReactIs.typeOf(<RefForwardingComponent />)).toBe(ReactIs.ForwardRef);
123 expect(ReactIs.isForwardRef(<RefForwardingComponent />)).toBe(true);
124 expect(ReactIs.isForwardRef({type: ReactIs.StrictMode})).toBe(false);
125 expect(ReactIs.isForwardRef(<div />)).toBe(false);
126 });
127
128 it('should identify fragments', () => {
129 expect(ReactIs.isValidElementType(React.Fragment)).toBe(true);
130 expect(ReactIs.typeOf(<React.Fragment />)).toBe(ReactIs.Fragment);
131 expect(ReactIs.isFragment(<React.Fragment />)).toBe(true);
132 expect(ReactIs.isFragment({type: ReactIs.Fragment})).toBe(false);
133 expect(ReactIs.isFragment('React.Fragment')).toBe(false);
134 expect(ReactIs.isFragment(<div />)).toBe(false);
135 expect(ReactIs.isFragment([])).toBe(false);
136 });
137
138 it('should identify portals', () => {
139 const div = document.createElement('div');
140 const portal = ReactDOM.createPortal(<div />, div);
141 expect(ReactIs.isValidElementType(portal)).toBe(false);
142 expect(ReactIs.typeOf(portal)).toBe(ReactIs.Portal);
143 expect(ReactIs.isPortal(portal)).toBe(true);
144 expect(ReactIs.isPortal(div)).toBe(false);
145 });
146
147 it('should identify memo', () => {
148 const Component = () => React.createElement('div');
149 const Memoized = React.memo(Component);
150 expect(ReactIs.isValidElementType(Memoized)).toBe(true);
151 expect(ReactIs.typeOf(<Memoized />)).toBe(ReactIs.Memo);
152 expect(ReactIs.isMemo(<Memoized />)).toBe(true);
153 expect(ReactIs.isMemo(<Component />)).toBe(false);
154 });
155
156 it('should identify lazy', () => {
157 const Component = () => React.createElement('div');
158 const LazyComponent = React.lazy(() => Component);
159 expect(ReactIs.isValidElementType(LazyComponent)).toBe(true);
160 expect(ReactIs.typeOf(<LazyComponent />)).toBe(ReactIs.Lazy);
161 expect(ReactIs.isLazy(<LazyComponent />)).toBe(true);
162 expect(ReactIs.isLazy(<Component />)).toBe(false);
163 });
164
165 it('should identify strict mode', () => {
166 expect(ReactIs.isValidElementType(React.StrictMode)).toBe(true);
167 expect(ReactIs.typeOf(<React.StrictMode />)).toBe(ReactIs.StrictMode);
168 expect(ReactIs.isStrictMode(<React.StrictMode />)).toBe(true);
169 expect(ReactIs.isStrictMode({type: ReactIs.StrictMode})).toBe(false);
170 expect(ReactIs.isStrictMode(<div />)).toBe(false);
171 });
172
173 it('should identify suspense', () => {
174 expect(ReactIs.isValidElementType(React.Suspense)).toBe(true);
175 expect(ReactIs.typeOf(<React.Suspense />)).toBe(ReactIs.Suspense);
176 expect(ReactIs.isSuspense(<React.Suspense />)).toBe(true);
177 expect(ReactIs.isSuspense({type: ReactIs.Suspense})).toBe(false);
178 expect(ReactIs.isSuspense('React.Suspense')).toBe(false);
179 expect(ReactIs.isSuspense(<div />)).toBe(false);
180 });
181
182 // @gate enableSuspenseList
183 it('should identify suspense list', () => {
184 expect(ReactIs.isValidElementType(SuspenseList)).toBe(true);
185 expect(ReactIs.typeOf(<SuspenseList />)).toBe(ReactIs.SuspenseList);
186 expect(ReactIs.isSuspenseList(<SuspenseList />)).toBe(true);
187 expect(ReactIs.isSuspenseList({type: ReactIs.SuspenseList})).toBe(false);
188 expect(ReactIs.isSuspenseList('React.SuspenseList')).toBe(false);
189 expect(ReactIs.isSuspenseList(<div />)).toBe(false);
190 });
191
192 it('should identify profile root', () => {
193 expect(ReactIs.isValidElementType(React.Profiler)).toBe(true);
194 expect(
195 ReactIs.typeOf(<React.Profiler id="foo" onRender={jest.fn()} />),
196 ).toBe(ReactIs.Profiler);
197 expect(
198 ReactIs.isProfiler(<React.Profiler id="foo" onRender={jest.fn()} />),
199 ).toBe(true);
200 expect(ReactIs.isProfiler({type: ReactIs.Profiler})).toBe(false);
201 expect(ReactIs.isProfiler(<div />)).toBe(false);
202 });
203 });