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

Remove usage of /test-utils in ReactLegacyCompositeComponent #28201

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
110 changes: 79 additions & 31 deletions packages/react-dom/src/__tests__/ReactLegacyCompositeComponent-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@

let React;
let ReactDOM;
let ReactTestUtils;
let ReactDOMClient;
let PropTypes;
let act;

describe('ReactLegacyCompositeComponent', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactDOM = require('react-dom');
ReactTestUtils = require('react-dom/test-utils');
ReactDOMClient = require('react-dom/client');
PropTypes = require('prop-types');
act = require('internal-test-utils').act;
});

it('should warn about `setState` in render in legacy mode', () => {
Expand Down Expand Up @@ -70,7 +72,7 @@ describe('ReactLegacyCompositeComponent', () => {
});

// @gate !disableLegacyContext
it('should pass context to children when not owner', () => {
it('should pass context to children when not owner', async () => {
class Parent extends React.Component {
render() {
return (
Expand Down Expand Up @@ -106,13 +108,17 @@ describe('ReactLegacyCompositeComponent', () => {
return <div>{this.context.foo}</div>;
}
}

const component = ReactTestUtils.renderIntoDocument(<Parent />);
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
let component;
await act(() => {
root.render(<Parent ref={current => (component = current)} />);
});
expect(ReactDOM.findDOMNode(component).innerHTML).toBe('bar');
});

// @gate !disableLegacyContext
it('should pass context when re-rendered for static child', () => {
it('should pass context when re-rendered for static child', async () => {
let parentInstance = null;
let childInstance = null;

Expand Down Expand Up @@ -156,24 +162,31 @@ describe('ReactLegacyCompositeComponent', () => {
}
}

parentInstance = ReactTestUtils.renderIntoDocument(
<Parent>
<Middle>
<Child />
</Middle>
</Parent>,
);
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);

await act(() => {
root.render(
<Parent ref={current => (parentInstance = current)}>
<Middle>
<Child />
</Middle>
</Parent>,
);
});

expect(parentInstance.state.flag).toBe(false);
expect(childInstance.context).toEqual({foo: 'bar', flag: false});

parentInstance.setState({flag: true});
await act(() => {
parentInstance.setState({flag: true});
});
expect(parentInstance.state.flag).toBe(true);
expect(childInstance.context).toEqual({foo: 'bar', flag: true});
});

// @gate !disableLegacyContext
it('should pass context when re-rendered for static child within a composite component', () => {
it('should pass context when re-rendered for static child within a composite component', async () => {
class Parent extends React.Component {
static childContextTypes = {
flag: PropTypes.bool,
Expand Down Expand Up @@ -217,20 +230,27 @@ describe('ReactLegacyCompositeComponent', () => {
}
}

const wrapper = ReactTestUtils.renderIntoDocument(<Wrapper />);
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
let wrapper;
await act(() => {
root.render(<Wrapper ref={current => (wrapper = current)} />);
});

expect(wrapper.parentRef.current.state.flag).toEqual(true);
expect(wrapper.childRef.current.context).toEqual({flag: true});

// We update <Parent /> while <Child /> is still a static prop relative to this update
wrapper.parentRef.current.setState({flag: false});
await act(() => {
wrapper.parentRef.current.setState({flag: false});
});

expect(wrapper.parentRef.current.state.flag).toEqual(false);
expect(wrapper.childRef.current.context).toEqual({flag: false});
});

// @gate !disableLegacyContext
it('should pass context transitively', () => {
it('should pass context transitively', async () => {
let childInstance = null;
let grandchildInstance = null;

Expand Down Expand Up @@ -286,13 +306,18 @@ describe('ReactLegacyCompositeComponent', () => {
}
}

ReactTestUtils.renderIntoDocument(<Parent />);
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await act(() => {
root.render(<Parent />);
});

expect(childInstance.context).toEqual({foo: 'bar', depth: 0});
expect(grandchildInstance.context).toEqual({foo: 'bar', depth: 1});
});

// @gate !disableLegacyContext
it('should pass context when re-rendered', () => {
it('should pass context when re-rendered', async () => {
let parentInstance = null;
let childInstance = null;

Expand Down Expand Up @@ -334,11 +359,16 @@ describe('ReactLegacyCompositeComponent', () => {
}
}

parentInstance = ReactTestUtils.renderIntoDocument(<Parent />);
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
await act(() => {
root.render(<Parent ref={current => (parentInstance = current)} />);
});

expect(childInstance).toBeNull();

expect(parentInstance.state.flag).toBe(false);
ReactDOM.unstable_batchedUpdates(function () {
await act(() => {
parentInstance.setState({flag: true});
});
expect(parentInstance.state.flag).toBe(true);
Expand Down Expand Up @@ -699,23 +729,31 @@ describe('ReactLegacyCompositeComponent', () => {
);
});

it('should replace state in legacy mode', () => {
it('should replace state in legacy mode', async () => {
class Moo extends React.Component {
state = {x: 1};
render() {
return <div />;
}
}

const moo = ReactTestUtils.renderIntoDocument(<Moo />);
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
let moo;
await act(() => {
root.render(<Moo ref={current => (moo = current)} />);
});

// No longer a public API, but we can test that it works internally by
// reaching into the updater.
moo.updater.enqueueReplaceState(moo, {y: 2});
await act(() => {
moo.updater.enqueueReplaceState(moo, {y: 2});
});
expect('x' in moo.state).toBe(false);
expect(moo.state.y).toBe(2);
});

it('should support objects with prototypes as state in legacy mode', () => {
it('should support objects with prototypes as state in legacy mode', async () => {
const NotActuallyImmutable = function (str) {
this.str = str;
};
Expand All @@ -732,32 +770,42 @@ describe('ReactLegacyCompositeComponent', () => {
}
}

const moo = ReactTestUtils.renderIntoDocument(<Moo />);
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
let moo;
await act(() => {
root.render(<Moo ref={current => (moo = current)} />);
});

expect(moo.state.str).toBe('first');
expect(moo.state.amIImmutable()).toBe(true);

const secondState = new NotActuallyImmutable('second');
moo._replaceState(secondState);
await act(() => {
moo._replaceState(secondState);
});
expect(moo.state.str).toBe('second');
expect(moo.state.amIImmutable()).toBe(true);
expect(moo.state).toBe(secondState);

moo.setState({str: 'third'});
await act(() => {
moo.setState({str: 'third'});
});
expect(moo.state.str).toBe('third');
// Here we lose the prototype.
expect(moo.state.amIImmutable).toBe(undefined);

// When more than one state update is enqueued, we have the same behavior
const fifthState = new NotActuallyImmutable('fifth');
ReactDOM.unstable_batchedUpdates(function () {
await act(() => {
moo.setState({str: 'fourth'});
moo._replaceState(fifthState);
});
expect(moo.state).toBe(fifthState);

// When more than one state update is enqueued, we have the same behavior
const sixthState = new NotActuallyImmutable('sixth');
ReactDOM.unstable_batchedUpdates(function () {
await act(() => {
moo._replaceState(sixthState);
moo.setState({str: 'seventh'});
});
Expand Down