Repository: facebook/react
Pull request: tests[react-devtools]: added tests for Compiler integration

Adds tests for Compiler integration.

This includes:
- Tests against Compiler from source.
- Versioned (18.2 - <19) tests against Compiler from npm.

For tests against React 18.2, I had to download `react-compiler-runtime` from npm and put it to `react/compiler-runtime.js`.


Changed files:
filename: .github/workflows/devtools_regression_tests.yml
patch: @@ -103,6 +103,7 @@ jobs:
           - "16.8" # hooks
           - "17.0"
           - "18.0"
+          - "18.2" # compiler polyfill
     continue-on-error: true
     steps:
       - uses: actions/checkout@v4

filename: packages/react-devtools-shared/src/__tests__/compiler-integration-test.js
patch: @@ -0,0 +1,101 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow
+ */
+
+import {getVersionedRenderImplementation} from './utils';
+
+describe('CompilerIntegration', () => {
+  global.IS_REACT_ACT_ENVIRONMENT = true;
+  let React;
+  let act;
+  let useMemoCache;
+
+  beforeEach(() => {
+    React = require('react');
+    require('react-dom');
+    require('react-dom/client');
+    useMemoCache = require('react/compiler-runtime').c;
+
+    const utils = require('./utils');
+    act = utils.act;
+  });
+
+  afterEach(() => {
+    jest.restoreAllMocks();
+  });
+
+  const {render} = getVersionedRenderImplementation();
+
+  // @reactVersion >= 18.2
+  it('By default, component display names should not have Forget prefix', () => {
+    const hook = global.__REACT_DEVTOOLS_GLOBAL_HOOK__;
+    const reactDOMFiberRendererInterface = hook.rendererInterfaces.get(1);
+    expect(reactDOMFiberRendererInterface).not.toBeFalsy();
+
+    const Foo = () => {
+      // eslint-disable-next-line no-unused-vars
+      const [val, setVal] = React.useState(null);
+
+      return (
+        <div>
+          <Bar />
+        </div>
+      );
+    };
+    const Bar = () => <div>Hi!</div>;
+
+    act(() => render(<Foo />));
+
+    expect(
+      reactDOMFiberRendererInterface
+        .getDisplayNameForElementID(2)
+        .indexOf('Forget'),
+    ).toBe(-1);
+    expect(
+      reactDOMFiberRendererInterface
+        .getDisplayNameForElementID(3)
+        .indexOf('Forget'),
+    ).toBe(-1);
+  });
+
+  // For React 18.2, this will install uMC polyfill from react-compiler-runtime available on npm.
+  // @reactVersion >= 18.2
+  it('If useMemoCache used, the corresponding displayName for a component should have Forget prefix', () => {
+    const hook = global.__REACT_DEVTOOLS_GLOBAL_HOOK__;
+    const reactDOMFiberRendererInterface = hook.rendererInterfaces.get(1);
+    expect(reactDOMFiberRendererInterface).not.toBeFalsy();
+
+    const Foo = () => {
+      // eslint-disable-next-line no-unused-vars
+      const $ = useMemoCache(1);
+      // eslint-disable-next-line no-unused-vars
+      const [val, setVal] = React.useState(null);
+
+      return (
+        <div>
+          <Bar />
+        </div>
+      );
+    };
+    const Bar = () => <div>Hi!</div>;
+
+    act(() => render(<Foo />));
+
+    // useMemoCache is only used by Foo component
+    expect(
+      reactDOMFiberRendererInterface
+        .getDisplayNameForElementID(2)
+        .indexOf('Forget'),
+    ).toBe(0);
+    expect(
+      reactDOMFiberRendererInterface
+        .getDisplayNameForElementID(3)
+        .indexOf('Forget'),
+    ).toBe(-1);
+  });
+});

filename: scripts/ci/download_devtools_regression_build.js
patch: @@ -82,11 +82,12 @@ async function downloadRegressionBuild() {
   );
   await exec(`mv ${movePackageString} ${buildPath}`);
 
+  const reactVersion = semver.coerce(version).version;
   // For React versions earlier than 18.0.0, we explicitly scheduler v0.20.1, which
   // is the first version that has unstable_mock, which DevTools tests need, but also
   // has Scheduler.unstable_trace, which, although we don't use in DevTools tests
   // is imported by older React versions and will break if it's not there
-  if (semver.lte(semver.coerce(version).version, '18.0.0')) {
+  if (semver.lte(reactVersion, '18.0.0')) {
     await exec(`npm install --prefix ${REGRESSION_FOLDER} scheduler@0.20.1`);
   }
 
@@ -108,6 +109,22 @@ async function downloadRegressionBuild() {
       )} ${buildPath}`
     );
   }
+
+  if (semver.gte(reactVersion, '18.2.0') && semver.lt(reactVersion, '19')) {
+    console.log(chalk.white(`Downloading react-compiler-runtime\n`));
+    await exec(
+      `npm install --prefix ${REGRESSION_FOLDER} react-compiler-runtime`
+    );
+
+    console.log(
+      chalk.white(
+        `Moving react-compiler-runtime to react/compiler-runtime.js\n`
+      )
+    );
+    await exec(
+      `mv ${REGRESSION_FOLDER}/node_modules/react-compiler-runtime/dist/index.js ${buildPath}/react/compiler-runtime.js`
+    );
+  }
 }
 
 async function main() {