Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests[react-devtools]: added tests for Compiler integration #31241

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/devtools_regression_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
});
});
19 changes: 18 additions & 1 deletion scripts/ci/download_devtools_regression_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -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`);
}

Expand All @@ -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`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems confusing and maybe unnecessary to overrwrite react/compiler-runtime.js, but I see why it's useful to

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to overrwrite react/compiler-runtime.js

react/compiler-runtime.js is only shipped in React 19, and this check is gated for React [18.2, 19), so we don't override anything, just copying a script to replicate same react package structure

);
}
}

async function main() {
Expand Down
Loading