@samitouri / QOS-React-1 / commits / 596827f6a7

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'));