Repository: facebook/react
Pull request: [DevTools] Regression Test Jest Config

Some older React versions have different module import names and are missing certain features. This PR mocks modules that don't exist and maps modules in older versions to the ones that are required in tests. Specifically:
* In React v16.5, `scheduler` is named `schedule`
* In pre concurrent React, there is no `act`
* Prior to React v18.0, `react-dom/client` doesn't exist
* In DevTools, we expect to use `scheduler/tracing-profiling` instead of `scheduler/tracing`

Changed files:
filename: scripts/jest/config.build-devtools.js
patch: @@ -3,6 +3,7 @@
 const {readdirSync, statSync} = require('fs');
 const {join} = require('path');
 const baseConfig = require('./config.base');
+const devtoolsRegressionConfig = require('./devtools/config.build-devtools-regression');
 
 const NODE_MODULES_DIR =
   process.env.RELEASE_CHANNEL === 'stable' ? 'oss-stable' : 'oss-experimental';
@@ -49,7 +50,10 @@ moduleNameMapper['^react-reconciler/([^/]+)$'] =
 
 module.exports = Object.assign({}, baseConfig, {
   // Redirect imports to the compiled bundles
-  moduleNameMapper,
+  moduleNameMapper: {
+    ...moduleNameMapper,
+    ...devtoolsRegressionConfig.moduleNameMapper,
+  },
   // Don't run bundle tests on -test.internal.* files
   testPathIgnorePatterns: ['/node_modules/', '-test.internal.js$'],
   // Exclude the build output from transforms
@@ -88,6 +92,7 @@ module.exports = Object.assign({}, baseConfig, {
   ],
   setupFiles: [
     ...baseConfig.setupFiles,
+    ...devtoolsRegressionConfig.setupFiles,
     require.resolve('./setupTests.build.js'),
     require.resolve('./devtools/setupEnv.js'),
   ],

filename: scripts/jest/devtools/config.build-devtools-regression.js
patch: @@ -0,0 +1,41 @@
+'use strict';
+
+const semver = require('semver');
+
+const NODE_MODULES_DIR =
+  process.env.RELEASE_CHANNEL === 'stable' ? 'oss-stable' : 'oss-experimental';
+
+const REACT_VERSION = process.env.REACT_VERSION;
+
+const moduleNameMapper = {};
+const setupFiles = [];
+
+// We only want to add these if we are in a regression test, IE if there
+// is a REACT_VERSION specified
+if (REACT_VERSION) {
+  // React version 16.5 has a schedule package instead of a scheduler
+  // package, so we need to rename them accordingly
+  if (semver.satisfies(REACT_VERSION, '16.5')) {
+    moduleNameMapper[
+      `^schedule$`
+    ] = `<rootDir>/build/${NODE_MODULES_DIR}/schedule`;
+    moduleNameMapper[
+      '^schedule/tracing$'
+    ] = `<rootDir>/build/${NODE_MODULES_DIR}/schedule/tracing-profiling`;
+  }
+
+  // react-dom/client is only in v18.0.0 and up, so we
+  // map it to react-dom instead
+  if (semver.satisfies(REACT_VERSION, '<18.0')) {
+    moduleNameMapper[
+      '^react-dom/client$'
+    ] = `<rootDir>/build/${NODE_MODULES_DIR}/react-dom`;
+  }
+
+  setupFiles.push(require.resolve('./setupTests.build-devtools-regression'));
+}
+
+module.exports = {
+  moduleNameMapper,
+  setupFiles,
+};

filename: scripts/jest/devtools/setupTests.build-devtools-regression.js
patch: @@ -0,0 +1,30 @@
+'use strict';
+
+// Regression tests use a React DOM profiling, so we need
+// to replace these tests with scheduler/tracing-profiling
+jest.mock('scheduler/tracing', () => {
+  return jest.requireActual('scheduler/tracing-profiling');
+});
+
+// act doesn't exist in older versions of React, but
+// DevTools tests sometimes import and depend on act to run.
+// If act doesn't exist for a particular version of React, we will
+// mock it with a function. This should work in most tests
+// that we want to call with older versions of React.
+// TODO (luna) Refactor act in DevTools test utils to not depend
+// on act in react-dom or react-test-renderer so we don't need to do this
+jest.mock('react-test-renderer', () => {
+  const reactTestRenderer = jest.requireActual('react-test-renderer');
+  if (!reactTestRenderer.act) {
+    reactTestRenderer.act = fn => fn();
+  }
+  return reactTestRenderer;
+});
+
+jest.mock('react-dom/test-utils', () => {
+  const testUtils = jest.requireActual('react-dom/test-utils');
+  if (!testUtils.act) {
+    testUtils.act = fn => fn();
+  }
+  return testUtils;
+});