Upgrade tests to use react/jsx-runtime (#28252)

Instead of createElement.

We should have done this when we initially released jsx-runtime but
better late than never. The general principle is that our tests should
be written using the most up-to-date idioms that we recommend for users,
except when explicitly testing an edge case or legacy behavior, like for
backwards compatibility.

Most of the diff is related to tweaking test output and isn't very
interesting.

I did have to workaround an issue related to component stacks. The
component stack logic depends on shared state that lives in the React
module. The problem is that most of our tests reset the React module
state and re-require a fresh instance of React, React DOM, etc. However,
the JSX runtime is not re-required because it's injected by the compiler
as a static import. This means its copy of the shared state is no longer
the same as the one used by React, causing any warning logged by the JSX
runtime to not include a component stack. (This same issue also breaks
string refs, but since we're removing those soon I'm not so concerned
about that.) The solution I went with for now is to mock the JSX runtime
with a proxy that re-requires the module on every function invocation. I
don't love this but it will have to do for now. What we should really do
is migrate our tests away from manually resetting the module state and
use import syntax instead.
This commit is contained in:
Andrew Clark
2024-02-05 23:07:41 -05:00
committed by GitHub
parent 2bc7d336ae
commit 952aa74f8e
18 changed files with 290 additions and 72 deletions

View File

@@ -3,7 +3,6 @@
module.exports = { module.exports = {
plugins: [ plugins: [
'@babel/plugin-syntax-jsx', '@babel/plugin-syntax-jsx',
'@babel/plugin-transform-react-jsx',
'@babel/plugin-transform-flow-strip-types', '@babel/plugin-transform-flow-strip-types',
['@babel/plugin-proposal-class-properties', {loose: true}], ['@babel/plugin-proposal-class-properties', {loose: true}],
'syntax-trailing-function-commas', 'syntax-trailing-function-commas',

View File

@@ -14,7 +14,7 @@
"@babel/plugin-proposal-object-rest-spread": "^7.11.0", "@babel/plugin-proposal-object-rest-spread": "^7.11.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/plugin-syntax-jsx": "^7.10.4", "@babel/plugin-syntax-jsx": "^7.23.3",
"@babel/plugin-syntax-typescript": "^7.14.5", "@babel/plugin-syntax-typescript": "^7.14.5",
"@babel/plugin-transform-arrow-functions": "^7.10.4", "@babel/plugin-transform-arrow-functions": "^7.10.4",
"@babel/plugin-transform-block-scoped-functions": "^7.10.4", "@babel/plugin-transform-block-scoped-functions": "^7.10.4",
@@ -27,12 +27,13 @@
"@babel/plugin-transform-modules-commonjs": "^7.10.4", "@babel/plugin-transform-modules-commonjs": "^7.10.4",
"@babel/plugin-transform-object-super": "^7.10.4", "@babel/plugin-transform-object-super": "^7.10.4",
"@babel/plugin-transform-parameters": "^7.10.5", "@babel/plugin-transform-parameters": "^7.10.5",
"@babel/plugin-transform-react-jsx-source": "^7.10.5", "@babel/plugin-transform-react-jsx": "^7.23.4",
"@babel/plugin-transform-react-jsx-development": "^7.22.5",
"@babel/plugin-transform-shorthand-properties": "^7.10.4", "@babel/plugin-transform-shorthand-properties": "^7.10.4",
"@babel/plugin-transform-spread": "^7.11.0", "@babel/plugin-transform-spread": "^7.11.0",
"@babel/plugin-transform-template-literals": "^7.10.5", "@babel/plugin-transform-template-literals": "^7.10.5",
"@babel/preset-flow": "^7.10.4", "@babel/preset-flow": "^7.10.4",
"@babel/preset-react": "^7.10.4", "@babel/preset-react": "^7.23.3",
"@babel/traverse": "^7.11.0", "@babel/traverse": "^7.11.0",
"@rollup/plugin-babel": "^6.0.3", "@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-commonjs": "^24.0.1",

View File

@@ -471,7 +471,7 @@ describe('ReactComponent', () => {
root.render(<X />); root.render(<X />);
}); });
}).toErrorDev( }).toErrorDev(
'React.createElement: type is invalid -- expected a string (for built-in components) ' + 'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined.', 'or a class/function (for composite components) but got: undefined.',
), ),
).rejects.toThrowError( ).rejects.toThrowError(
@@ -492,7 +492,7 @@ describe('ReactComponent', () => {
root.render(<Y />); root.render(<Y />);
}); });
}).toErrorDev( }).toErrorDev(
'React.createElement: type is invalid -- expected a string (for built-in components) ' + 'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: null.', 'or a class/function (for composite components) but got: null.',
), ),
).rejects.toThrowError( ).rejects.toThrowError(
@@ -528,7 +528,7 @@ describe('ReactComponent', () => {
root.render(<Foo />); root.render(<Foo />);
}); });
}).toErrorDev( }).toErrorDev(
'React.createElement: type is invalid -- expected a string (for built-in components) ' + 'React.jsx: type is invalid -- expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: undefined.', 'or a class/function (for composite components) but got: undefined.',
), ),
).rejects.toThrowError( ).rejects.toThrowError(

View File

@@ -1007,7 +1007,7 @@ describe('ReactDOMServerIntegration', () => {
expect(() => { expect(() => {
EmptyComponent = <EmptyComponent />; EmptyComponent = <EmptyComponent />;
}).toErrorDev( }).toErrorDev(
'Warning: React.createElement: type is invalid -- expected a string ' + 'Warning: React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' + '(for built-in components) or a class/function (for composite ' +
'components) but got: object. You likely forgot to export your ' + 'components) but got: object. You likely forgot to export your ' +
"component from the file it's defined in, or you might have mixed up " + "component from the file it's defined in, or you might have mixed up " +
@@ -1031,7 +1031,7 @@ describe('ReactDOMServerIntegration', () => {
expect(() => { expect(() => {
NullComponent = <NullComponent />; NullComponent = <NullComponent />;
}).toErrorDev( }).toErrorDev(
'Warning: React.createElement: type is invalid -- expected a string ' + 'Warning: React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' + '(for built-in components) or a class/function (for composite ' +
'components) but got: null.', 'components) but got: null.',
{withoutStack: true}, {withoutStack: true},
@@ -1049,7 +1049,7 @@ describe('ReactDOMServerIntegration', () => {
expect(() => { expect(() => {
UndefinedComponent = <UndefinedComponent />; UndefinedComponent = <UndefinedComponent />;
}).toErrorDev( }).toErrorDev(
'Warning: React.createElement: type is invalid -- expected a string ' + 'Warning: React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' + '(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' + 'components) but got: undefined. You likely forgot to export your ' +
"component from the file it's defined in, or you might have mixed up " + "component from the file it's defined in, or you might have mixed up " +

View File

@@ -95,7 +95,10 @@ describe('ReactDeprecationWarnings', () => {
} }
class Component extends React.Component { class Component extends React.Component {
render() { render() {
return <RefComponent ref="refComponent" __self={this} />; return React.createElement(RefComponent, {
ref: 'refComponent',
__self: this,
});
} }
} }
expect(() => { expect(() => {
@@ -114,7 +117,10 @@ describe('ReactDeprecationWarnings', () => {
} }
class Component extends React.Component { class Component extends React.Component {
render() { render() {
return <RefComponent ref="refComponent" __self={{}} />; return React.createElement(RefComponent, {
ref: 'refComponent',
__self: {},
});
} }
} }

View File

@@ -1244,9 +1244,9 @@ describe('ReactIncrementalErrorHandling', () => {
</ErrorBoundary>, </ErrorBoundary>,
); );
await expect(async () => await waitForAll([])).toErrorDev([ await expect(async () => await waitForAll([])).toErrorDev([
'Warning: React.createElement: type is invalid -- expected a string', 'Warning: React.jsx: type is invalid -- expected a string',
// React retries once on error // React retries once on error
'Warning: React.createElement: type is invalid -- expected a string', 'Warning: React.jsx: type is invalid -- expected a string',
]); ]);
expect(ReactNoop).toMatchRenderedOutput( expect(ReactNoop).toMatchRenderedOutput(
<span <span
@@ -1295,9 +1295,9 @@ describe('ReactIncrementalErrorHandling', () => {
</ErrorBoundary>, </ErrorBoundary>,
); );
await expect(async () => await waitForAll([])).toErrorDev([ await expect(async () => await waitForAll([])).toErrorDev([
'Warning: React.createElement: type is invalid -- expected a string', 'Warning: React.jsx: type is invalid -- expected a string',
// React retries once on error // React retries once on error
'Warning: React.createElement: type is invalid -- expected a string', 'Warning: React.jsx: type is invalid -- expected a string',
]); ]);
expect(ReactNoop).toMatchRenderedOutput( expect(ReactNoop).toMatchRenderedOutput(
<span <span
@@ -1317,7 +1317,7 @@ describe('ReactIncrementalErrorHandling', () => {
it('recovers from uncaught reconciler errors', async () => { it('recovers from uncaught reconciler errors', async () => {
const InvalidType = undefined; const InvalidType = undefined;
expect(() => ReactNoop.render(<InvalidType />)).toErrorDev( expect(() => ReactNoop.render(<InvalidType />)).toErrorDev(
'Warning: React.createElement: type is invalid -- expected a string', 'Warning: React.jsx: type is invalid -- expected a string',
{withoutStack: true}, {withoutStack: true},
); );
await waitForThrow( await waitForThrow(

View File

@@ -86,13 +86,22 @@ describe('ReactFreshIntegration', () => {
// eslint-disable-next-line no-new-func // eslint-disable-next-line no-new-func
new Function( new Function(
'global', 'global',
'require',
'React', 'React',
'Scheduler', 'Scheduler',
'exports', 'exports',
'$RefreshReg$', '$RefreshReg$',
'$RefreshSig$', '$RefreshSig$',
compiled, compiled,
)(global, React, Scheduler, exportsObj, $RefreshReg$, $RefreshSig$); )(
global,
require,
React,
Scheduler,
exportsObj,
$RefreshReg$,
$RefreshSig$,
);
// Module systems will register exports as a fallback. // Module systems will register exports as a fallback.
// This is useful for cases when e.g. a class is exported, // This is useful for cases when e.g. a class is exported,
// and we don't want to propagate the update beyond this module. // and we don't want to propagate the update beyond this module.

View File

@@ -288,8 +288,7 @@ describe('ReactTestRenderer', () => {
expect(() => ReactTestRenderer.create(<Foo />)).toErrorDev( expect(() => ReactTestRenderer.create(<Foo />)).toErrorDev(
'Warning: Function components cannot be given refs. Attempts ' + 'Warning: Function components cannot be given refs. Attempts ' +
'to access this ref will fail. ' + 'to access this ref will fail. ' +
'Did you mean to use React.forwardRef()?\n\n' + 'Did you mean to use React.forwardRef()?\n' +
'Check the render method of `Foo`.\n' +
' in Bar (at **)\n' + ' in Bar (at **)\n' +
' in Foo (at **)', ' in Foo (at **)',
); );

View File

@@ -14,7 +14,9 @@ let act;
let React; let React;
let ReactDOMClient; let ReactDOMClient;
describe('ReactElement', () => { // NOTE: This module tests the old, "classic" JSX runtime, React.createElement.
// Do not use JSX syntax in this module; call React.createElement directly.
describe('ReactCreateElement', () => {
let ComponentClass; let ComponentClass;
beforeEach(() => { beforeEach(() => {
@@ -24,8 +26,6 @@ describe('ReactElement', () => {
React = require('react'); React = require('react');
ReactDOMClient = require('react-dom/client'); ReactDOMClient = require('react-dom/client');
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
ComponentClass = class extends React.Component { ComponentClass = class extends React.Component {
render() { render() {
return React.createElement('div'); return React.createElement('div');
@@ -48,24 +48,24 @@ describe('ReactElement', () => {
it('should warn when `key` is being accessed on composite element', async () => { it('should warn when `key` is being accessed on composite element', async () => {
class Child extends React.Component { class Child extends React.Component {
render() { render() {
return <div>{this.props.key}</div>; return React.createElement('div', null, this.props.key);
} }
} }
class Parent extends React.Component { class Parent extends React.Component {
render() { render() {
return ( return React.createElement(
<div> 'div',
<Child key="0" /> null,
<Child key="1" /> React.createElement(Child, {key: '0'}),
<Child key="2" /> React.createElement(Child, {key: '1'}),
</div> React.createElement(Child, {key: '2'}),
); );
} }
} }
const root = ReactDOMClient.createRoot(document.createElement('div')); const root = ReactDOMClient.createRoot(document.createElement('div'));
await expect(async () => { await expect(async () => {
await act(() => { await act(() => {
root.render(<Parent />); root.render(React.createElement(Parent));
}); });
}).toErrorDev( }).toErrorDev(
'Child: `key` is not a prop. Trying to access it will result ' + 'Child: `key` is not a prop. Trying to access it will result ' +
@@ -76,7 +76,7 @@ describe('ReactElement', () => {
}); });
it('should warn when `key` is being accessed on a host element', () => { it('should warn when `key` is being accessed on a host element', () => {
const element = <div key="3" />; const element = React.createElement('div', {key: '3'});
expect(() => void element.props.key).toErrorDev( expect(() => void element.props.key).toErrorDev(
'div: `key` is not a prop. Trying to access it will result ' + 'div: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' + 'in `undefined` being returned. If you need to access the same ' +
@@ -89,15 +89,15 @@ describe('ReactElement', () => {
it('should warn when `ref` is being accessed', async () => { it('should warn when `ref` is being accessed', async () => {
class Child extends React.Component { class Child extends React.Component {
render() { render() {
return <div> {this.props.ref} </div>; return React.createElement('div', null, this.props.ref);
} }
} }
class Parent extends React.Component { class Parent extends React.Component {
render() { render() {
return ( return React.createElement(
<div> 'div',
<Child ref={React.createRef()} /> null,
</div> React.createElement(Child, {ref: React.createRef()}),
); );
} }
} }
@@ -105,7 +105,7 @@ describe('ReactElement', () => {
await expect(async () => { await expect(async () => {
await act(() => { await act(() => {
root.render(<Parent />); root.render(React.createElement(Parent));
}); });
}).toErrorDev( }).toErrorDev(
'Child: `ref` is not a prop. Trying to access it will result ' + 'Child: `ref` is not a prop. Trying to access it will result ' +
@@ -277,8 +277,6 @@ describe('ReactElement', () => {
expect(element.props.children).toEqual([1, 2, 3]); expect(element.props.children).toEqual([1, 2, 3]);
}); });
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
it('allows static methods to be called using the type property', () => { it('allows static methods to be called using the type property', () => {
class StaticMethodComponentClass extends React.Component { class StaticMethodComponentClass extends React.Component {
render() { render() {
@@ -291,16 +289,12 @@ describe('ReactElement', () => {
expect(element.type.someStaticMethod()).toBe('someReturnValue'); expect(element.type.someStaticMethod()).toBe('someReturnValue');
}); });
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
it('is indistinguishable from a plain object', () => { it('is indistinguishable from a plain object', () => {
const element = React.createElement('div', {className: 'foo'}); const element = React.createElement('div', {className: 'foo'});
const object = {}; const object = {};
expect(element.constructor).toBe(object.constructor); expect(element.constructor).toBe(object.constructor);
}); });
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
it('should use default prop value when removing a prop', async () => { it('should use default prop value when removing a prop', async () => {
class Component extends React.Component { class Component extends React.Component {
render() { render() {
@@ -325,8 +319,6 @@ describe('ReactElement', () => {
expect(instance.props.fruit).toBe('persimmon'); expect(instance.props.fruit).toBe('persimmon');
}); });
// NOTE: We're explicitly not using JSX here. This is intended to test
// classic JS without JSX.
it('should normalize props with default values', async () => { it('should normalize props with default values', async () => {
let instance; let instance;
class Component extends React.Component { class Component extends React.Component {
@@ -354,7 +346,7 @@ describe('ReactElement', () => {
it('throws when changing a prop (in dev) after element creation', async () => { it('throws when changing a prop (in dev) after element creation', async () => {
class Outer extends React.Component { class Outer extends React.Component {
render() { render() {
const el = <div className="moo" />; const el = React.createElement('div', {className: 'moo'});
if (__DEV__) { if (__DEV__) {
expect(function () { expect(function () {
@@ -374,7 +366,7 @@ describe('ReactElement', () => {
const root = ReactDOMClient.createRoot(container); const root = ReactDOMClient.createRoot(container);
await act(() => { await act(() => {
root.render(<Outer color="orange" />); root.render(React.createElement(Outer, {color: 'orange'}));
}); });
if (__DEV__) { if (__DEV__) {
expect(container.firstChild.className).toBe('moo'); expect(container.firstChild.className).toBe('moo');
@@ -387,7 +379,7 @@ describe('ReactElement', () => {
const container = document.createElement('div'); const container = document.createElement('div');
class Outer extends React.Component { class Outer extends React.Component {
render() { render() {
const el = <div>{this.props.sound}</div>; const el = React.createElement('div', null, this.props.sound);
if (__DEV__) { if (__DEV__) {
expect(function () { expect(function () {
@@ -405,7 +397,7 @@ describe('ReactElement', () => {
Outer.defaultProps = {sound: 'meow'}; Outer.defaultProps = {sound: 'meow'};
const root = ReactDOMClient.createRoot(container); const root = ReactDOMClient.createRoot(container);
await act(() => { await act(() => {
root.render(<Outer />); root.render(React.createElement(Outer));
}); });
expect(container.firstChild.textContent).toBe('meow'); expect(container.firstChild.textContent).toBe('meow');
if (__DEV__) { if (__DEV__) {
@@ -422,12 +414,12 @@ describe('ReactElement', () => {
test = this; test = this;
} }
render() { render() {
return <div />; return React.createElement('div');
} }
} }
const root = ReactDOMClient.createRoot(document.createElement('div')); const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => { await act(() => {
root.render(<Test value={+undefined} />); root.render(React.createElement(Test, {value: +undefined}));
}); });
expect(test.props.value).toBeNaN(); expect(test.props.value).toBeNaN();
}); });

View File

@@ -10,7 +10,10 @@
'use strict'; 'use strict';
// NOTE: We're explicitly not using JSX in this file. This is intended to test // NOTE: We're explicitly not using JSX in this file. This is intended to test
// classic JS without JSX. // classic React.createElement without JSX.
// TODO: ^ the above note is a bit stale because there are tests in this file
// that do use JSX syntax. We should port them to React.createElement, and also
// confirm there's a corresponding test that uses JSX syntax.
let PropTypes; let PropTypes;
let React; let React;
@@ -548,7 +551,7 @@ describe('ReactElementValidator', () => {
expect(() => { expect(() => {
void (<Foo>{[<div />]}</Foo>); void (<Foo>{[<div />]}</Foo>);
}).toErrorDev( }).toErrorDev(
'Warning: React.createElement: type is invalid -- expected a string ' + 'Warning: React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' + '(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' + 'components) but got: undefined. You likely forgot to export your ' +
"component from the file it's defined in, or you might have mixed up " + "component from the file it's defined in, or you might have mixed up " +

View File

@@ -220,7 +220,7 @@ describe('ReactJSXElementValidator', () => {
const True = true; const True = true;
const Div = 'div'; const Div = 'div';
expect(() => void (<Undefined />)).toErrorDev( expect(() => void (<Undefined />)).toErrorDev(
'Warning: React.createElement: type is invalid -- expected a string ' + 'Warning: React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' + '(for built-in components) or a class/function (for composite ' +
'components) but got: undefined. You likely forgot to export your ' + 'components) but got: undefined. You likely forgot to export your ' +
"component from the file it's defined in, or you might have mixed up " + "component from the file it's defined in, or you might have mixed up " +
@@ -229,14 +229,14 @@ describe('ReactJSXElementValidator', () => {
{withoutStack: true}, {withoutStack: true},
); );
expect(() => void (<Null />)).toErrorDev( expect(() => void (<Null />)).toErrorDev(
'Warning: React.createElement: type is invalid -- expected a string ' + 'Warning: React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' + '(for built-in components) or a class/function (for composite ' +
'components) but got: null.' + 'components) but got: null.' +
'\n\nCheck your code at **.', '\n\nCheck your code at **.',
{withoutStack: true}, {withoutStack: true},
); );
expect(() => void (<True />)).toErrorDev( expect(() => void (<True />)).toErrorDev(
'Warning: React.createElement: type is invalid -- expected a string ' + 'Warning: React.jsx: type is invalid -- expected a string ' +
'(for built-in components) or a class/function (for composite ' + '(for built-in components) or a class/function (for composite ' +
'components) but got: boolean.' + 'components) but got: boolean.' +
'\n\nCheck your code at **.', '\n\nCheck your code at **.',

View File

@@ -17,11 +17,10 @@ let JSXRuntime;
let JSXDEVRuntime; let JSXDEVRuntime;
let act; let act;
// NOTE: We're explicitly not using JSX here. This is intended to test // NOTE: Prefer to call the JSXRuntime directly in these tests so we can be
// a new React.jsx api which does not have a JSX transformer yet. // certain that we are testing the runtime behavior, as opposed to the Babel
// A lot of these tests are pulled from ReactElement-test because // transform that we use in our tests configuration.
// this api is meant to be backwards compatible. describe('ReactJSXRuntime', () => {
describe('ReactElement.jsx', () => {
beforeEach(() => { beforeEach(() => {
jest.resetModules(); jest.resetModules();

View File

@@ -14,7 +14,15 @@ let ReactDOMClient;
let ReactTestUtils; let ReactTestUtils;
let act; let act;
describe('ReactJSXElement', () => { // TODO: Historically this module was used to confirm that the JSX transform
// produces the correct output. However, most users (and indeed our own test
// suite) use a tool like Babel or TypeScript to transform JSX; unlike the
// runtime, the transform is not part of React itself. So this is really just an
// integration suite for the Babel transform. We might consider deleting it. We
// should prefer to test the JSX runtime directly, in ReactCreateElement-test
// and ReactJsxRuntime-test. In the meantime, there's lots of overlap between
// those modules and this one.
describe('ReactJSXTransformIntegration', () => {
let Component; let Component;
beforeEach(() => { beforeEach(() => {
@@ -32,6 +40,19 @@ describe('ReactJSXElement', () => {
}; };
}); });
it('sanity check: test environment is configured to compile JSX to the jsx() runtime', async () => {
function App() {
return <div />;
}
const source = App.toString();
if (__DEV__) {
expect(source).toContain('jsxDEV(');
} else {
expect(source).toContain('jsx(');
}
expect(source).not.toContain('React.createElement');
});
it('returns a complete element according to spec', () => { it('returns a complete element according to spec', () => {
const element = <Component />; const element = <Component />;
expect(element.type).toBe(Component); expect(element.type).toBe(Component);

View File

@@ -12,15 +12,18 @@
let React; let React;
let ReactDOMClient; let ReactDOMClient;
let act; let act;
let jsxDEV;
describe('Component stack trace displaying', () => { describe('Component stack trace displaying', () => {
beforeEach(() => { beforeEach(() => {
React = require('react'); React = require('react');
ReactDOMClient = require('react-dom'); ReactDOMClient = require('react-dom/client');
act = require('internal-test-utils').act; act = require('internal-test-utils').act;
jsxDEV = require('react/jsx-dev-runtime').jsxDEV;
}); });
// @gate !enableComponentStackLocations || !__DEV__ // @gate !enableComponentStackLocations
// @gate __DEV__
it('should provide filenames in stack traces', async () => { it('should provide filenames in stack traces', async () => {
class Component extends React.Component { class Component extends React.Component {
render() { render() {
@@ -98,7 +101,18 @@ describe('Component stack trace displaying', () => {
Component.displayName = 'Component ' + i; Component.displayName = 'Component ' + i;
await act(() => { await act(() => {
root.render(<Component __source={{fileName, lineNumber: i}} />); root.render(
// Intentionally inlining a manual jsxDEV() instead of relying on the
// compiler so that we can pass a custom source location.
jsxDEV(
Component,
{},
undefined,
false,
{fileName, lineNumber: i},
this,
),
);
}); });
i++; i++;

View File

@@ -57,3 +57,41 @@ global._test_react_version_focus = (range, testName, callback) => {
global._test_ignore_for_react_version = (testName, callback) => { global._test_ignore_for_react_version = (testName, callback) => {
test.skip(testName, callback); test.skip(testName, callback);
}; };
// Most of our tests call jest.resetModules in a beforeEach and the
// re-require all the React modules. However, the JSX runtime is injected by
// the compiler, so those bindings don't get updated. This causes warnings
// logged by the JSX runtime to not have a component stack, because component
// stack relies on the the secret internals object that lives on the React
// module, which because of the resetModules call is longer the same one.
//
// To workaround this issue, we use a proxy that re-requires the latest
// JSX Runtime from the require cache on every function invocation.
//
// Longer term we should migrate all our tests away from using require() and
// resetModules, and use import syntax instead so this kind of thing doesn't
// happen.
lazyRequireFunctionExports('react/jsx-dev-runtime');
// TODO: We shouldn't need to do this in the production runtime, but until
// we remove string refs they also depend on the shared state object. Remove
// once we remove string refs.
lazyRequireFunctionExports('react/jsx-runtime');
function lazyRequireFunctionExports(moduleName) {
jest.mock(moduleName, () => {
return new Proxy(jest.requireActual(moduleName), {
get(originalModule, prop) {
// If this export is a function, return a wrapper function that lazily
// requires the implementation from the current module cache.
if (typeof originalModule[prop] === 'function') {
return function () {
return jest.requireActual(moduleName)[prop].apply(this, arguments);
};
} else {
return originalModule[prop];
}
},
});
});
}

View File

@@ -34,12 +34,6 @@ const babelOptions = {
// For Node environment only. For builds, Rollup takes care of ESM. // For Node environment only. For builds, Rollup takes care of ESM.
require.resolve('@babel/plugin-transform-modules-commonjs'), require.resolve('@babel/plugin-transform-modules-commonjs'),
// Keep stacks detailed in tests.
// Don't put this in .babelrc so that we don't embed filenames
// into ReactART builds that include JSX.
// TODO: I have not verified that this actually works.
require.resolve('@babel/plugin-transform-react-jsx-source'),
pathToTransformInfiniteLoops, pathToTransformInfiniteLoops,
pathToTransformTestGatePragma, pathToTransformTestGatePragma,
@@ -86,6 +80,16 @@ module.exports = {
if (isTestFile && isInDevToolsPackages) { if (isTestFile && isInDevToolsPackages) {
plugins.push(pathToTransformReactVersionPragma); plugins.push(pathToTransformReactVersionPragma);
} }
plugins.push([
process.env.NODE_ENV === 'development'
? require.resolve('@babel/plugin-transform-react-jsx-development')
: require.resolve('@babel/plugin-transform-react-jsx'),
// The "automatic" runtime corresponds to react/jsx-runtime. "classic"
// would be React.createElement.
{runtime: 'automatic'},
]);
let sourceAst = hermesParser.parse(src, {babel: true}); let sourceAst = hermesParser.parse(src, {babel: true});
return { return {
code: babel.transformFromAstSync( code: babel.transformFromAstSync(

View File

@@ -313,3 +313,41 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
return fn(flags); return fn(flags);
}; };
} }
// Most of our tests call jest.resetModules in a beforeEach and the
// re-require all the React modules. However, the JSX runtime is injected by
// the compiler, so those bindings don't get updated. This causes warnings
// logged by the JSX runtime to not have a component stack, because component
// stack relies on the the secret internals object that lives on the React
// module, which because of the resetModules call is longer the same one.
//
// To workaround this issue, we use a proxy that re-requires the latest
// JSX Runtime from the require cache on every function invocation.
//
// Longer term we should migrate all our tests away from using require() and
// resetModules, and use import syntax instead so this kind of thing doesn't
// happen.
lazyRequireFunctionExports('react/jsx-dev-runtime');
// TODO: We shouldn't need to do this in the production runtime, but until
// we remove string refs they also depend on the shared state object. Remove
// once we remove string refs.
lazyRequireFunctionExports('react/jsx-runtime');
function lazyRequireFunctionExports(moduleName) {
jest.mock(moduleName, () => {
return new Proxy(jest.requireActual(moduleName), {
get(originalModule, prop) {
// If this export is a function, return a wrapper function that lazily
// requires the implementation from the current module cache.
if (typeof originalModule[prop] === 'function') {
return function () {
return jest.requireActual(moduleName)[prop].apply(this, arguments);
};
} else {
return originalModule[prop];
}
},
});
});
}

View File

@@ -220,6 +220,13 @@
dependencies: dependencies:
"@babel/types" "^7.18.6" "@babel/types" "^7.18.6"
"@babel/helper-annotate-as-pure@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882"
integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": "@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4":
version "7.10.4" version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3"
@@ -465,6 +472,13 @@
dependencies: dependencies:
"@babel/types" "^7.18.6" "@babel/types" "^7.18.6"
"@babel/helper-module-imports@^7.22.15":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0"
integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==
dependencies:
"@babel/types" "^7.22.15"
"@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.11.0": "@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.11.0":
version "7.11.0" version "7.11.0"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359"
@@ -547,6 +561,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629"
integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==
"@babel/helper-plugin-utils@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==
"@babel/helper-regex@^7.10.4": "@babel/helper-regex@^7.10.4":
version "7.10.5" version "7.10.5"
resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0"
@@ -673,6 +692,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
"@babel/helper-string-parser@^7.23.4":
version "7.23.4"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83"
integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==
"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.14.0": "@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.14.0":
version "7.14.0" version "7.14.0"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288"
@@ -688,6 +712,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
"@babel/helper-validator-identifier@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
"@babel/helper-validator-option@^7.14.5": "@babel/helper-validator-option@^7.14.5":
version "7.14.5" version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
@@ -698,6 +727,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
"@babel/helper-validator-option@^7.22.15":
version "7.23.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307"
integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==
"@babel/helper-wrap-function@^7.10.4": "@babel/helper-wrap-function@^7.10.4":
version "7.10.4" version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87"
@@ -1089,6 +1123,13 @@
dependencies: dependencies:
"@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4"
"@babel/plugin-syntax-jsx@^7.23.3":
version "7.23.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473"
integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3":
version "7.10.4" version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
@@ -1509,6 +1550,13 @@
dependencies: dependencies:
"@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4"
"@babel/plugin-transform-react-display-name@^7.23.3":
version "7.23.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz#70529f034dd1e561045ad3c8152a267f0d7b6200"
integrity sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-transform-react-jsx-development@^7.10.4": "@babel/plugin-transform-react-jsx-development@^7.10.4":
version "7.10.4" version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.10.4.tgz#6ec90f244394604623880e15ebc3c34c356258ba" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.10.4.tgz#6ec90f244394604623880e15ebc3c34c356258ba"
@@ -1518,6 +1566,13 @@
"@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4"
"@babel/plugin-syntax-jsx" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4"
"@babel/plugin-transform-react-jsx-development@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz#e716b6edbef972a92165cd69d92f1255f7e73e87"
integrity sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==
dependencies:
"@babel/plugin-transform-react-jsx" "^7.22.5"
"@babel/plugin-transform-react-jsx-self@^7.10.4": "@babel/plugin-transform-react-jsx-self@^7.10.4":
version "7.10.4" version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.10.4.tgz#cd301a5fed8988c182ed0b9d55e9bd6db0bd9369" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.10.4.tgz#cd301a5fed8988c182ed0b9d55e9bd6db0bd9369"
@@ -1555,6 +1610,17 @@
"@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4"
"@babel/plugin-syntax-jsx" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4"
"@babel/plugin-transform-react-jsx@^7.22.15", "@babel/plugin-transform-react-jsx@^7.22.5", "@babel/plugin-transform-react-jsx@^7.23.4":
version "7.23.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz#393f99185110cea87184ea47bcb4a7b0c2e39312"
integrity sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==
dependencies:
"@babel/helper-annotate-as-pure" "^7.22.5"
"@babel/helper-module-imports" "^7.22.15"
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-syntax-jsx" "^7.23.3"
"@babel/types" "^7.23.4"
"@babel/plugin-transform-react-pure-annotations@^7.10.4": "@babel/plugin-transform-react-pure-annotations@^7.10.4":
version "7.10.4" version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.10.4.tgz#3eefbb73db94afbc075f097523e445354a1c6501" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.10.4.tgz#3eefbb73db94afbc075f097523e445354a1c6501"
@@ -1563,6 +1629,14 @@
"@babel/helper-annotate-as-pure" "^7.10.4" "@babel/helper-annotate-as-pure" "^7.10.4"
"@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4"
"@babel/plugin-transform-react-pure-annotations@^7.23.3":
version "7.23.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz#fabedbdb8ee40edf5da96f3ecfc6958e3783b93c"
integrity sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==
dependencies:
"@babel/helper-annotate-as-pure" "^7.22.5"
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-transform-regenerator@^7.10.4": "@babel/plugin-transform-regenerator@^7.10.4":
version "7.10.4" version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63"
@@ -1775,6 +1849,18 @@
"@babel/plugin-transform-react-jsx-source" "^7.10.4" "@babel/plugin-transform-react-jsx-source" "^7.10.4"
"@babel/plugin-transform-react-pure-annotations" "^7.10.4" "@babel/plugin-transform-react-pure-annotations" "^7.10.4"
"@babel/preset-react@^7.23.3":
version "7.23.3"
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.23.3.tgz#f73ca07e7590f977db07eb54dbe46538cc015709"
integrity sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/helper-validator-option" "^7.22.15"
"@babel/plugin-transform-react-display-name" "^7.23.3"
"@babel/plugin-transform-react-jsx" "^7.22.15"
"@babel/plugin-transform-react-jsx-development" "^7.22.5"
"@babel/plugin-transform-react-pure-annotations" "^7.23.3"
"@babel/preset-typescript@^7.14.5": "@babel/preset-typescript@^7.14.5":
version "7.16.0" version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.0.tgz#b0b4f105b855fb3d631ec036cdc9d1ffd1fa5eac" resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.0.tgz#b0b4f105b855fb3d631ec036cdc9d1ffd1fa5eac"
@@ -1979,6 +2065,15 @@
"@babel/helper-validator-identifier" "^7.19.1" "@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.4":
version "7.23.9"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.9.tgz#1dd7b59a9a2b5c87f8b41e52770b5ecbf492e002"
integrity sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==
dependencies:
"@babel/helper-string-parser" "^7.23.4"
"@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"
"@bcoe/v8-coverage@^0.2.3": "@bcoe/v8-coverage@^0.2.3":
version "0.2.3" version "0.2.3"
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"