chore: add versioned render implementation for DevTools tests (#28210)
Adding getter-functions for renderer implementations, which can be used for jest tests. If we are testing against React with version < 18, we are going to use legacy rendering, otherwise the concurrent one.
Ruslan Lesiutin committed
Feb 5, 2024 at 15:53 UTC
596827f6a72f6c4df0181e941c524fcbd0048914
1 file changed
+118
packages/react-devtools-shared/src/__tests__/utils.js
+118
@@ -15,6 +15,7 @@ import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
15
import type Store from 'react-devtools-shared/src/devtools/store';
16
import type {ProfilingDataFrontend} from 'react-devtools-shared/src/devtools/views/Profiler/types';
17
import type {ElementType} from 'react-devtools-shared/src/frontend/types';
18
+import type {Node as ReactNode} from 'react';
19
20
import {ReactVersion} from '../../../../ReactVersions';
21
@@ -99,6 +100,123 @@ export async function actAsync(
100
}
101
}
102
103
+type RenderImplementation = {
104
+ render: (elements: ?ReactNode) => () => void,
105
+ unmount: () => void,
106
+ createContainer: () => void,
107
+ getContainer: () => ?HTMLElement,
108
+};
109
+
110
+export function getLegacyRenderImplementation(): RenderImplementation {
111
+ let ReactDOM;
112
+ let container;
113
+ const containersToRemove = [];
114
+
115
+ beforeEach(() => {
116
+ ReactDOM = require('react-dom');
117
+
118
+ createContainer();
119
+ });
120
+
121
+ afterEach(() => {
122
+ containersToRemove.forEach(c => document.body.removeChild(c));
123
+ containersToRemove.splice(0, containersToRemove.length);
124
+
125
+ ReactDOM = null;
126
+ container = null;
127
+ });
128
+
129
+ function render(elements) {
130
+ withErrorsOrWarningsIgnored(
131
+ ['ReactDOM.render is no longer supported in React 18'],
132
+ () => {
133
+ ReactDOM.render(elements, container);
134
+ },
135
+ );
136
+
137
+ return unmount;
138
+ }
139
+
140
+ function unmount() {
141
+ ReactDOM.unmountComponentAtNode(container);
142
+ }
143
+
144
+ function createContainer() {
145
+ container = document.createElement('div');
146
+ document.body.appendChild(container);
147
+
148
+ containersToRemove.push(container);
149
+ }
150
+
151
+ function getContainer() {
152
+ return container;
153
+ }
154
+
155
+ return {
156
+ render,
157
+ unmount,
158
+ createContainer,
159
+ getContainer,
160
+ };
161
+}
162
+
163
+export function getModernRenderImplementation(): RenderImplementation {
164
+ let ReactDOMClient;
165
+ let container;
166
+ let root;
167
+ const containersToRemove = [];
168
+
169
+ beforeEach(() => {
170
+ ReactDOMClient = require('react-dom/client');
171
+
172
+ createContainer();
173
+ });
174
+
175
+ afterEach(() => {
176
+ containersToRemove.forEach(c => document.body.removeChild(c));
177
+ containersToRemove.splice(0, containersToRemove.length);
178
+
179
+ ReactDOMClient = null;
180
+ container = null;
181
+ root = null;
182
+ });
183
+
184
+ function render(elements) {
185
+ root.render(elements);
186
+
187
+ return unmount;
188
+ }
189
+
190
+ function unmount() {
191
+ root.unmount();
192
+ }
193
+
194
+ function createContainer() {
195
+ container = document.createElement('div');
196
+ document.body.appendChild(container);
197
+
198
+ root = ReactDOMClient.createRoot(container);
199
+
200
+ containersToRemove.push(container);
201
+ }
202
+
203
+ function getContainer() {
204
+ return container;
205
+ }
206
+
207
+ return {
208
+ render,
209
+ unmount,
210
+ createContainer,
211
+ getContainer,
212
+ };
213
+}
214
+
215
+export const getVersionedRenderImplementation: () => RenderImplementation =
216
+ semver.lt(requestedReactVersion, '18.0.0')
217
+ ? getLegacyRenderImplementation
218
+ : getModernRenderImplementation;
219
+
220
export function beforeEachProfiling(): void {
221
// Mock React's timing information so that test runs are predictable.
222
jest.mock('scheduler', () => jest.requireActual('scheduler/unstable_mock'));