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

Convert createReactClassIntegration-test to createRoot #27914

Merged
merged 1 commit into from
Jan 9, 2024
Merged
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
164 changes: 108 additions & 56 deletions packages/react/src/__tests__/createReactClassIntegration-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@

'use strict';

let act;

let PropTypes;
let React;
let ReactDOM;
let ReactDOMClient;
let ReactTestUtils;
let createReactClass;

describe('create-react-class-integration', () => {
beforeEach(() => {
jest.resetModules();
({act} = require('internal-test-utils'));
PropTypes = require('prop-types');
React = require('react');
ReactDOM = require('react-dom');
ReactDOMClient = require('react-dom/client');
ReactTestUtils = require('react-dom/test-utils');
createReactClass = require('create-react-class/factory')(
React.Component,
Expand Down Expand Up @@ -292,7 +295,7 @@ describe('create-react-class-integration', () => {
});

// @gate !disableLegacyContext
it('renders based on context getInitialState', () => {
it('renders based on context getInitialState', async () => {
const Foo = createReactClass({
contextTypes: {
className: PropTypes.string,
Expand All @@ -318,7 +321,10 @@ describe('create-react-class-integration', () => {
});

const container = document.createElement('div');
ReactDOM.render(<Outer />, container);
const root = ReactDOMClient.createRoot(container);
await act(() => {
root.render(<Outer />);
});
expect(container.firstChild.className).toBe('foo');
});

Expand Down Expand Up @@ -388,7 +394,7 @@ describe('create-react-class-integration', () => {
expect(ops).toEqual(['Render: 0', 'Render: 1', 'Callback: 1']);
});

it('getDerivedStateFromProps updates state when props change', () => {
it('getDerivedStateFromProps updates state when props change', async () => {
const Component = createReactClass({
getInitialState() {
return {
Expand All @@ -404,23 +410,26 @@ describe('create-react-class-integration', () => {
});

const container = document.createElement('div');
const instance = ReactDOM.render(
<div>
<Component incrementBy={0} />
</div>,
container,
);
expect(instance.textContent).toEqual('count:1');
ReactDOM.render(
<div>
<Component incrementBy={2} />
</div>,
container,
);
expect(instance.textContent).toEqual('count:3');
const root = ReactDOMClient.createRoot(container);
await act(() => {
root.render(
<div>
<Component incrementBy={0} />
</div>,
);
});
expect(container.firstChild.textContent).toEqual('count:1');
await act(() => {
root.render(
<div>
<Component incrementBy={2} />
</div>,
);
});
expect(container.firstChild.textContent).toEqual('count:3');
});

it('should support the new static getDerivedStateFromProps method', () => {
it('should support the new static getDerivedStateFromProps method', async () => {
let instance;
const Component = createReactClass({
statics: {
Expand All @@ -438,11 +447,14 @@ describe('create-react-class-integration', () => {
return null;
},
});
ReactDOM.render(<Component />, document.createElement('div'));
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => {
root.render(<Component />);
});
expect(instance.state.foo).toBe('bar');
});

it('warns if getDerivedStateFromProps is not static', () => {
it('warns if getDerivedStateFromProps is not static', async () => {
const Foo = createReactClass({
displayName: 'Foo',
getDerivedStateFromProps() {
Expand All @@ -452,15 +464,18 @@ describe('create-react-class-integration', () => {
return <div />;
},
});
expect(() =>
ReactDOM.render(<Foo foo="foo" />, document.createElement('div')),
).toErrorDev(
await expect(async () => {
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => {
root.render(<Foo foo="foo" />);
});
}).toErrorDev(
'Foo: getDerivedStateFromProps() is defined as an instance method ' +
'and will be ignored. Instead, declare it as a static method.',
);
});

it('warns if getDerivedStateFromError is not static', () => {
it('warns if getDerivedStateFromError is not static', async () => {
const Foo = createReactClass({
displayName: 'Foo',
getDerivedStateFromError() {
Expand All @@ -470,15 +485,18 @@ describe('create-react-class-integration', () => {
return <div />;
},
});
expect(() =>
ReactDOM.render(<Foo foo="foo" />, document.createElement('div')),
).toErrorDev(
await expect(async () => {
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => {
root.render(<Foo foo="foo" />);
});
}).toErrorDev(
'Foo: getDerivedStateFromError() is defined as an instance method ' +
'and will be ignored. Instead, declare it as a static method.',
);
});

it('warns if getSnapshotBeforeUpdate is static', () => {
it('warns if getSnapshotBeforeUpdate is static', async () => {
const Foo = createReactClass({
displayName: 'Foo',
statics: {
Expand All @@ -490,15 +508,18 @@ describe('create-react-class-integration', () => {
return <div />;
},
});
expect(() =>
ReactDOM.render(<Foo foo="foo" />, document.createElement('div')),
).toErrorDev(
await expect(async () => {
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => {
root.render(<Foo foo="foo" />);
});
}).toErrorDev(
'Foo: getSnapshotBeforeUpdate() is defined as a static method ' +
'and will be ignored. Instead, declare it as an instance method.',
);
});

it('should warn if state is not properly initialized before getDerivedStateFromProps', () => {
it('should warn if state is not properly initialized before getDerivedStateFromProps', async () => {
const Component = createReactClass({
displayName: 'Component',
statics: {
Expand All @@ -510,17 +531,20 @@ describe('create-react-class-integration', () => {
return null;
},
});
expect(() =>
ReactDOM.render(<Component />, document.createElement('div')),
).toErrorDev(
await expect(async () => {
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => {
root.render(<Component />);
});
}).toErrorDev(
'`Component` uses `getDerivedStateFromProps` but its initial state is ' +
'null. This is not recommended. Instead, define the initial state by ' +
'assigning an object to `this.state` in the constructor of `Component`. ' +
'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.',
);
});

it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new static gDSFP is present', () => {
it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new static gDSFP is present', async () => {
const Component = createReactClass({
statics: {
getDerivedStateFromProps: function () {
Expand All @@ -544,9 +568,12 @@ describe('create-react-class-integration', () => {
},
});

expect(() => {
expect(() => {
ReactDOM.render(<Component />, document.createElement('div'));
await expect(async () => {
await expect(async () => {
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => {
root.render(<Component />);
});
}).toErrorDev(
'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
'Component uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' +
Expand All @@ -564,10 +591,13 @@ describe('create-react-class-integration', () => {
],
{withoutStack: true},
);
ReactDOM.render(<Component foo={1} />, document.createElement('div'));
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => {
root.render(<Component foo={1} />);
});
});

it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present', () => {
it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present', async () => {
const Component = createReactClass({
getSnapshotBeforeUpdate: function () {
return null;
Expand All @@ -587,9 +617,12 @@ describe('create-react-class-integration', () => {
},
});

expect(() => {
expect(() => {
ReactDOM.render(<Component />, document.createElement('div'));
await expect(async () => {
await expect(async () => {
const root = ReactDOMClient.createRoot(document.createElement('div'));
await act(() => {
root.render(<Component />);
});
}).toErrorDev(
'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
'Component uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' +
Expand All @@ -607,10 +640,13 @@ describe('create-react-class-integration', () => {
],
{withoutStack: true},
);
ReactDOM.render(<Component foo={1} />, document.createElement('div'));
await act(() => {
const root2 = ReactDOMClient.createRoot(document.createElement('div'));
root2.render(<Component foo={1} />);
});
});

it('should invoke both deprecated and new lifecycles if both are present', () => {
it('should invoke both deprecated and new lifecycles if both are present', async () => {
const log = [];

const Component = createReactClass({
Expand Down Expand Up @@ -641,8 +677,13 @@ describe('create-react-class-integration', () => {
},
});

const div = document.createElement('div');
expect(() => ReactDOM.render(<Component foo="bar" />, div)).toWarnDev(
const root = ReactDOMClient.createRoot(document.createElement('div'));

await expect(async () => {
await act(() => {
root.render(<Component foo="bar" />);
});
}).toWarnDev(
[
'componentWillMount has been renamed',
'componentWillReceiveProps has been renamed',
Expand All @@ -654,7 +695,9 @@ describe('create-react-class-integration', () => {

log.length = 0;

ReactDOM.render(<Component foo="baz" />, div);
await act(() => {
root.render(<Component foo="baz" />);
});
expect(log).toEqual([
'componentWillReceiveProps',
'UNSAFE_componentWillReceiveProps',
Expand All @@ -663,7 +706,7 @@ describe('create-react-class-integration', () => {
]);
});

it('isMounted works', () => {
it('isMounted works', async () => {
const ops = [];
let instance;
const Component = createReactClass({
Expand Down Expand Up @@ -716,19 +759,28 @@ describe('create-react-class-integration', () => {
},
});

const container = document.createElement('div');
const root = ReactDOMClient.createRoot(document.createElement('div'));

expect(() => ReactDOM.render(<Component />, container)).toErrorDev(
await expect(async () => {
await act(() => {
root.render(<Component />);
});
}).toErrorDev(
'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
'clean up subscriptions and pending requests in componentWillUnmount ' +
'to prevent memory leaks.',
{withoutStack: true},
);

// Dedupe
ReactDOM.render(<Component />, container);

ReactDOM.unmountComponentAtNode(container);
await act(() => {
root.render(<Component />);
});

await act(() => {
root.unmount();
});
instance.log('after unmount');
expect(ops).toEqual([
'getInitialState: false',
Expand Down