Skip to content

Commit 26a3968

Browse files
committed
fix: compatibility with react 19 in snapshots
1 parent fd3d6cf commit 26a3968

File tree

5 files changed

+173
-15
lines changed

5 files changed

+173
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
### Fixes
44

55
- `[expect]` Fix `bigint` error ([#15702](https://github.com/jestjs/jest/pull/15702))
6+
- `[pretty-format]` Fix support for React 19 ([#15729](https://github.com/jestjs/jest/pull/15729))
67

78
## 30.0.4
89

packages/pretty-format/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,10 @@
2222
"author": "James Kyle <[email protected]>",
2323
"dependencies": {
2424
"@jest/schemas": "workspace:*",
25-
"ansi-styles": "^5.2.0",
26-
"react-is": "^18.3.1"
25+
"ansi-styles": "^5.2.0"
2726
},
2827
"devDependencies": {
2928
"@types/react": "^18.3.23",
30-
"@types/react-is": "^18.3.1",
3129
"@types/react-test-renderer": "^18.3.1",
3230
"immutable": "^5.1.2",
3331
"jest-util": "workspace:*",

packages/pretty-format/src/plugins/ReactElement.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import * as ReactIs from 'react-is';
98
import type {Config, NewPlugin, Printer, Refs} from '../types';
9+
import * as ReactIs from './lib/ReactIs';
1010
import {
1111
printChildren,
1212
printElement,
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2+
// This file is mostly copy-pasted from the original react-is library,
3+
// with some modifications to support React versions < 19.
4+
// https://github.com/facebook/react/blob/main/packages/react-is/src/ReactIs.js
5+
6+
// Customizations:
7+
// - Added support for REACT_LEGACY_ELEMENT_TYPE wherever REACT_ELEMENT_TYPE is used.
8+
// - Added support for REACT_PROVIDER_TYPE wherever REACT_CONTEXT_TYPE is used.
9+
// - Added support for REACT_SERVER_CONTEXT_TYPE in typeOf function with the same logic as REACT_CONTEXT_TYPE.
10+
// - Added support for REACT_OFFSCREEN_TYPE in isValidElementType function.
11+
// - TypeScript type `mixed` replaced with `any`.
12+
13+
// Types collected from https://github.com/facebook/react/blob/main/packages/shared/ReactSymbols.js
14+
const REACT_LEGACY_ELEMENT_TYPE: symbol = Symbol.for('react.element');
15+
const REACT_ELEMENT_TYPE: symbol = Symbol.for('react.transitional.element');
16+
const REACT_PORTAL_TYPE: symbol = Symbol.for('react.portal');
17+
const REACT_FRAGMENT_TYPE: symbol = Symbol.for('react.fragment');
18+
const REACT_STRICT_MODE_TYPE: symbol = Symbol.for('react.strict_mode');
19+
const REACT_PROFILER_TYPE: symbol = Symbol.for('react.profiler');
20+
const REACT_CONSUMER_TYPE: symbol = Symbol.for('react.consumer');
21+
const REACT_CONTEXT_TYPE: symbol = Symbol.for('react.context');
22+
const REACT_FORWARD_REF_TYPE: symbol = Symbol.for('react.forward_ref');
23+
const REACT_SUSPENSE_TYPE: symbol = Symbol.for('react.suspense');
24+
const REACT_SUSPENSE_LIST_TYPE: symbol = Symbol.for('react.suspense_list');
25+
const REACT_MEMO_TYPE: symbol = Symbol.for('react.memo');
26+
const REACT_LAZY_TYPE: symbol = Symbol.for('react.lazy');
27+
const REACT_VIEW_TRANSITION_TYPE: symbol = Symbol.for('react.view_transition');
28+
const REACT_CLIENT_REFERENCE: symbol = Symbol.for('react.client.reference');
29+
30+
// Legacy types not present in React 19+
31+
const REACT_PROVIDER_TYPE: symbol = Symbol.for('react.provider');
32+
const REACT_SERVER_CONTEXT_TYPE: symbol = Symbol.for('react.server_context');
33+
const REACT_OFFSCREEN_TYPE: symbol = Symbol.for('react.offscreen');
34+
35+
// Below is a copy of ReactIs.js with customizations listed above.
36+
37+
export function typeOf(object: any): any {
38+
if (typeof object === 'object' && object !== null) {
39+
const $$typeof = object.$$typeof;
40+
switch ($$typeof) {
41+
case REACT_LEGACY_ELEMENT_TYPE:
42+
case REACT_ELEMENT_TYPE:
43+
const type = object.type;
44+
45+
switch (type) {
46+
case REACT_FRAGMENT_TYPE:
47+
case REACT_PROFILER_TYPE:
48+
case REACT_STRICT_MODE_TYPE:
49+
case REACT_SUSPENSE_TYPE:
50+
case REACT_SUSPENSE_LIST_TYPE:
51+
case REACT_VIEW_TRANSITION_TYPE:
52+
return type;
53+
default:
54+
const $$typeofType = type && type.$$typeof;
55+
56+
switch ($$typeofType) {
57+
case REACT_PROVIDER_TYPE:
58+
case REACT_CONTEXT_TYPE:
59+
case REACT_SERVER_CONTEXT_TYPE:
60+
case REACT_FORWARD_REF_TYPE:
61+
case REACT_LAZY_TYPE:
62+
case REACT_MEMO_TYPE:
63+
return $$typeofType;
64+
case REACT_CONSUMER_TYPE:
65+
return $$typeofType;
66+
// Fall through
67+
default:
68+
return $$typeof;
69+
}
70+
}
71+
case REACT_PORTAL_TYPE:
72+
return $$typeof;
73+
}
74+
}
75+
76+
return undefined;
77+
}
78+
79+
export const ContextConsumer: symbol = REACT_CONSUMER_TYPE;
80+
export const ContextProvider: symbol = REACT_CONTEXT_TYPE;
81+
export const Element = REACT_ELEMENT_TYPE;
82+
export const ForwardRef = REACT_FORWARD_REF_TYPE;
83+
export const Fragment = REACT_FRAGMENT_TYPE;
84+
export const Lazy = REACT_LAZY_TYPE;
85+
export const Memo = REACT_MEMO_TYPE;
86+
export const Portal = REACT_PORTAL_TYPE;
87+
export const Profiler = REACT_PROFILER_TYPE;
88+
export const StrictMode = REACT_STRICT_MODE_TYPE;
89+
export const Suspense = REACT_SUSPENSE_TYPE;
90+
export const SuspenseList = REACT_SUSPENSE_LIST_TYPE;
91+
92+
export function isValidElementType(type: any): boolean {
93+
if (typeof type === 'string' || typeof type === 'function') {
94+
return true;
95+
}
96+
97+
// Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill).
98+
if (
99+
type === REACT_FRAGMENT_TYPE ||
100+
type === REACT_PROFILER_TYPE ||
101+
type === REACT_STRICT_MODE_TYPE ||
102+
type === REACT_SUSPENSE_TYPE ||
103+
type === REACT_SUSPENSE_LIST_TYPE ||
104+
type === REACT_OFFSCREEN_TYPE
105+
) {
106+
return true;
107+
}
108+
109+
if (typeof type === 'object' && type !== null) {
110+
if (
111+
type.$$typeof === REACT_LAZY_TYPE ||
112+
type.$$typeof === REACT_MEMO_TYPE ||
113+
type.$$typeof === REACT_PROVIDER_TYPE ||
114+
type.$$typeof === REACT_CONTEXT_TYPE ||
115+
type.$$typeof === REACT_CONSUMER_TYPE ||
116+
type.$$typeof === REACT_FORWARD_REF_TYPE ||
117+
// This needs to include all possible module reference object
118+
// types supported by any Flight configuration anywhere since
119+
// we don't know which Flight build this will end up being used
120+
// with.
121+
type.$$typeof === REACT_CLIENT_REFERENCE ||
122+
type.getModuleId !== undefined
123+
) {
124+
return true;
125+
}
126+
}
127+
128+
return false;
129+
}
130+
131+
export function isContextConsumer(object: any): boolean {
132+
return typeOf(object) === REACT_CONSUMER_TYPE;
133+
}
134+
export function isContextProvider(object: any): boolean {
135+
return [REACT_CONTEXT_TYPE, REACT_PROVIDER_TYPE].includes(typeOf(object));
136+
}
137+
export function isElement(object: any): boolean {
138+
return (
139+
typeof object === 'object' &&
140+
object !== null &&
141+
[REACT_ELEMENT_TYPE, REACT_LEGACY_ELEMENT_TYPE].includes(object.$$typeof)
142+
);
143+
}
144+
export function isForwardRef(object: any): boolean {
145+
return typeOf(object) === REACT_FORWARD_REF_TYPE;
146+
}
147+
export function isFragment(object: any): boolean {
148+
return typeOf(object) === REACT_FRAGMENT_TYPE;
149+
}
150+
export function isLazy(object: any): boolean {
151+
return typeOf(object) === REACT_LAZY_TYPE;
152+
}
153+
export function isMemo(object: any): boolean {
154+
return typeOf(object) === REACT_MEMO_TYPE;
155+
}
156+
export function isPortal(object: any): boolean {
157+
return typeOf(object) === REACT_PORTAL_TYPE;
158+
}
159+
export function isProfiler(object: any): boolean {
160+
return typeOf(object) === REACT_PROFILER_TYPE;
161+
}
162+
export function isStrictMode(object: any): boolean {
163+
return typeOf(object) === REACT_STRICT_MODE_TYPE;
164+
}
165+
export function isSuspense(object: any): boolean {
166+
return typeOf(object) === REACT_SUSPENSE_TYPE;
167+
}
168+
export function isSuspenseList(object: any): boolean {
169+
return typeOf(object) === REACT_SUSPENSE_LIST_TYPE;
170+
}

yarn.lock

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6390,15 +6390,6 @@ __metadata:
63906390
languageName: node
63916391
linkType: hard
63926392

6393-
"@types/react-is@npm:^18.3.1":
6394-
version: 18.3.1
6395-
resolution: "@types/react-is@npm:18.3.1"
6396-
dependencies:
6397-
"@types/react": "npm:^18"
6398-
checksum: 10/ccb79d6e196a5232cde8ccb255ec97e062801a3dafeff3816130fb5ad6b9a87f7c0806ab35bc00890a229773228ef217d0390839b68c705d3add2f798b5fcf82
6399-
languageName: node
6400-
linkType: hard
6401-
64026393
"@types/react-router-config@npm:*, @types/react-router-config@npm:^5.0.7":
64036394
version: 5.0.11
64046395
resolution: "@types/react-router-config@npm:5.0.11"
@@ -18234,14 +18225,12 @@ __metadata:
1823418225
dependencies:
1823518226
"@jest/schemas": "workspace:*"
1823618227
"@types/react": "npm:^18.3.23"
18237-
"@types/react-is": "npm:^18.3.1"
1823818228
"@types/react-test-renderer": "npm:^18.3.1"
1823918229
ansi-styles: "npm:^5.2.0"
1824018230
immutable: "npm:^5.1.2"
1824118231
jest-util: "workspace:*"
1824218232
react: "npm:18.3.1"
1824318233
react-dom: "npm:18.3.1"
18244-
react-is: "npm:^18.3.1"
1824518234
react-test-renderer: "npm:18.3.1"
1824618235
languageName: unknown
1824718236
linkType: soft

0 commit comments

Comments
 (0)