Skip to content

Commit

Permalink
Warn about legacy context when legacy context is not disabled
Browse files Browse the repository at this point in the history
For environments that still have legacy contexts available, this adds a warning to make the remaining call sites easier to locate and encourage upgrades.
  • Loading branch information
kassens committed Jul 10, 2024
1 parent 39e69dc commit 59752f7
Show file tree
Hide file tree
Showing 17 changed files with 261 additions and 76 deletions.
10 changes: 8 additions & 2 deletions packages/react-dom/src/__tests__/ReactDOMFiber-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ let React;
let ReactDOM;
let PropTypes;
let ReactDOMClient;
let root;
let Scheduler;

let act;
let assertConsoleErrorDev;
let assertLog;
let root;

describe('ReactDOMFiber', () => {
let container;
Expand All @@ -29,7 +31,7 @@ describe('ReactDOMFiber', () => {
ReactDOMClient = require('react-dom/client');
Scheduler = require('scheduler');
act = require('internal-test-utils').act;
assertLog = require('internal-test-utils').assertLog;
({assertConsoleErrorDev, assertLog} = require('internal-test-utils'));

container = document.createElement('div');
document.body.appendChild(container);
Expand Down Expand Up @@ -732,6 +734,10 @@ describe('ReactDOMFiber', () => {
await act(async () => {
root.render(<Parent />);
});
assertConsoleErrorDev([
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'Component uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
]);
expect(container.innerHTML).toBe('');
expect(portalContainer.innerHTML).toBe('<div>bar</div>');
});
Expand Down
20 changes: 14 additions & 6 deletions packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ let ReactDOMFizzServer;
let ReactDOMFizzStatic;
let Suspense;
let SuspenseList;

let assertConsoleErrorDev;
let useSyncExternalStore;
let useSyncExternalStoreWithSelector;
let use;
Expand Down Expand Up @@ -116,12 +118,14 @@ describe('ReactDOMFizzServer', () => {
useActionState = React.useActionState;
}

const InternalTestUtils = require('internal-test-utils');
waitForAll = InternalTestUtils.waitForAll;
waitFor = InternalTestUtils.waitFor;
waitForPaint = InternalTestUtils.waitForPaint;
assertLog = InternalTestUtils.assertLog;
clientAct = InternalTestUtils.act;
({
assertConsoleErrorDev,
assertLog,
act: clientAct,
waitFor,
waitForAll,
waitForPaint,
} = require('internal-test-utils'));

if (gate(flags => flags.source)) {
// The `with-selector` module composes the main `use-sync-external-store`
Expand Down Expand Up @@ -1950,6 +1954,10 @@ describe('ReactDOMFizzServer', () => {
);
pipe(writable);
});
assertConsoleErrorDev([
'TestProvider uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'TestConsumer uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
]);
expect(getVisibleChildren(container)).toEqual(
<div>
Loading: <b>A</b>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ describe('ReactDOMServerIntegration', () => {
<PurpleContext>
<ClassChildWithContext />
</PurpleContext>,
2,
);
expect(e.textContent).toBe('purple');
});
Expand All @@ -94,6 +95,7 @@ describe('ReactDOMServerIntegration', () => {
<PurpleContext>
<FunctionChildWithContext />
</PurpleContext>,
2,
);
expect(e.textContent).toBe('purple');
});
Expand All @@ -110,6 +112,7 @@ describe('ReactDOMServerIntegration', () => {
<PurpleContext>
<ClassChildWithoutContext />
</PurpleContext>,
1,
);
expect(e.textContent).toBe('');
});
Expand All @@ -124,6 +127,7 @@ describe('ReactDOMServerIntegration', () => {
<PurpleContext>
<FunctionChildWithoutContext />
</PurpleContext>,
1,
);
expect(e.textContent).toBe('');
});
Expand All @@ -141,6 +145,7 @@ describe('ReactDOMServerIntegration', () => {
<PurpleContext>
<ClassChildWithWrongContext />
</PurpleContext>,
2,
);
expect(e.textContent).toBe('');
});
Expand All @@ -158,6 +163,7 @@ describe('ReactDOMServerIntegration', () => {
<PurpleContext>
<FunctionChildWithWrongContext />
</PurpleContext>,
2,
);
expect(e.textContent).toBe('');
});
Expand All @@ -174,6 +180,7 @@ describe('ReactDOMServerIntegration', () => {
<PurpleContext>
<Child />
</PurpleContext>,
2,
);
expect(e.textContent).toBe('purple');
});
Expand All @@ -190,6 +197,7 @@ describe('ReactDOMServerIntegration', () => {
<Grandchild />
</RedContext>
</PurpleContext>,
2,
);
expect(e.textContent).toBe('red');
});
Expand Down Expand Up @@ -228,7 +236,7 @@ describe('ReactDOMServerIntegration', () => {
text2: PropTypes.string,
};

const e = await render(<Parent />);
const e = await render(<Parent />, 3);
expect(e.querySelector('#first').textContent).toBe('purple');
expect(e.querySelector('#second').textContent).toBe('red');
});
Expand All @@ -254,7 +262,7 @@ describe('ReactDOMServerIntegration', () => {
};
Child.contextTypes = {text: PropTypes.string};

const e = await render(<WillMountContext />);
const e = await render(<WillMountContext />, 2);
expect(e.textContent).toBe('foo');
},
);
Expand All @@ -278,7 +286,8 @@ describe('ReactDOMServerIntegration', () => {
}
const e = await render(
<ForgetfulParent />,
render === clientRenderOnBadMarkup ? 2 : 1,
// Some warning is not de-duped and logged again on the client retry render.
render === clientRenderOnBadMarkup ? 3 : 2,
);
expect(e.textContent).toBe('nope');
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe('ReactErrorBoundaries', () => {
let RetryErrorBoundary;
let Normal;
let assertLog;
let assertConsoleErrorDev;

beforeEach(() => {
jest.useFakeTimers();
Expand All @@ -47,8 +48,7 @@ describe('ReactErrorBoundaries', () => {
act = require('internal-test-utils').act;
Scheduler = require('scheduler');

const InternalTestUtils = require('internal-test-utils');
assertLog = InternalTestUtils.assertLog;
({assertLog, assertConsoleErrorDev} = require('internal-test-utils'));

BrokenConstructor = class extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -895,6 +895,9 @@ describe('ReactErrorBoundaries', () => {
</ErrorBoundary>,
);
});
assertConsoleErrorDev([
'BrokenComponentWillMountWithContext uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
]);
expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
});

Expand Down
12 changes: 11 additions & 1 deletion packages/react-dom/src/__tests__/ReactFunctionComponent-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ let PropTypes;
let React;
let ReactDOMClient;
let act;
let assertConsoleErrorDev;

function FunctionComponent(props) {
return <div>{props.name}</div>;
Expand All @@ -24,7 +25,7 @@ describe('ReactFunctionComponent', () => {
PropTypes = require('prop-types');
React = require('react');
ReactDOMClient = require('react-dom/client');
act = require('internal-test-utils').act;
({act, assertConsoleErrorDev} = require('internal-test-utils'));
});

it('should render stateless component', async () => {
Expand Down Expand Up @@ -109,6 +110,11 @@ describe('ReactFunctionComponent', () => {
root.render(<GrandParent test="test" />);
});

assertConsoleErrorDev([
'GrandParent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
]);

expect(el.textContent).toBe('test');

await act(() => {
Expand Down Expand Up @@ -472,6 +478,10 @@ describe('ReactFunctionComponent', () => {
await act(() => {
root.render(<Parent />);
});
assertConsoleErrorDev([
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'Child uses the legacy contextTypes API which will be removed soon. Use React.createContext() with React.useContext() instead.',
]);
expect(el.textContent).toBe('en');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ let ReactDOM;
let findDOMNode;
let ReactDOMClient;
let PropTypes;

let act;
let assertConsoleErrorDev;

describe('ReactLegacyCompositeComponent', () => {
beforeEach(() => {
Expand All @@ -26,7 +28,7 @@ describe('ReactLegacyCompositeComponent', () => {
ReactDOM.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE
.findDOMNode;
PropTypes = require('prop-types');
act = require('internal-test-utils').act;
({act, assertConsoleErrorDev} = require('internal-test-utils'));
});

// @gate !disableLegacyMode
Expand Down Expand Up @@ -119,6 +121,10 @@ describe('ReactLegacyCompositeComponent', () => {
await act(() => {
root.render(<Parent ref={current => (component = current)} />);
});
assertConsoleErrorDev([
'Child uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'Grandchild uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
]);
expect(findDOMNode(component).innerHTML).toBe('bar');
});

Expand Down Expand Up @@ -183,6 +189,11 @@ describe('ReactLegacyCompositeComponent', () => {
expect(parentInstance.state.flag).toBe(false);
expect(childInstance.context).toEqual({foo: 'bar', flag: false});

assertConsoleErrorDev([
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
]);

await act(() => {
parentInstance.setState({flag: true});
});
Expand Down Expand Up @@ -242,6 +253,11 @@ describe('ReactLegacyCompositeComponent', () => {
root.render(<Wrapper ref={current => (wrapper = current)} />);
});

assertConsoleErrorDev([
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
]);

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

Expand Down Expand Up @@ -317,6 +333,13 @@ describe('ReactLegacyCompositeComponent', () => {
root.render(<Parent />);
});

assertConsoleErrorDev([
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'Child uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
'Grandchild uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
]);

expect(childInstance.context).toEqual({foo: 'bar', depth: 0});
expect(grandchildInstance.context).toEqual({foo: 'bar', depth: 1});
});
Expand Down Expand Up @@ -369,13 +392,20 @@ describe('ReactLegacyCompositeComponent', () => {
await act(() => {
root.render(<Parent ref={current => (parentInstance = current)} />);
});
assertConsoleErrorDev([
'Parent uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
]);

expect(childInstance).toBeNull();

expect(parentInstance.state.flag).toBe(false);
await act(() => {
parentInstance.setState({flag: true});
});
assertConsoleErrorDev([
'Child uses the legacy contextTypes API which will soon be removed. Use React.createContext() with static contextType instead.',
]);

expect(parentInstance.state.flag).toBe(true);

expect(childInstance.context).toEqual({foo: 'bar', depth: 0});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,9 @@ describe('ReactLegacyErrorBoundaries', () => {
</ErrorBoundary>,
container,
);
assertConsoleErrorDev([
'BrokenComponentWillMountWithContext uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
]);
expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,27 +227,31 @@ test('handles events on text nodes', () => {
}

const log = [];
ReactNative.render(
<ContextHack>
<Text>
<Text
onTouchEnd={() => log.push('string touchend')}
onTouchEndCapture={() => log.push('string touchend capture')}
onTouchStart={() => log.push('string touchstart')}
onTouchStartCapture={() => log.push('string touchstart capture')}>
Text Content
</Text>
<Text
onTouchEnd={() => log.push('number touchend')}
onTouchEndCapture={() => log.push('number touchend capture')}
onTouchStart={() => log.push('number touchstart')}
onTouchStartCapture={() => log.push('number touchstart capture')}>
{123}
expect(() => {
ReactNative.render(
<ContextHack>
<Text>
<Text
onTouchEnd={() => log.push('string touchend')}
onTouchEndCapture={() => log.push('string touchend capture')}
onTouchStart={() => log.push('string touchstart')}
onTouchStartCapture={() => log.push('string touchstart capture')}>
Text Content
</Text>
<Text
onTouchEnd={() => log.push('number touchend')}
onTouchEndCapture={() => log.push('number touchend capture')}
onTouchStart={() => log.push('number touchstart')}
onTouchStartCapture={() => log.push('number touchstart capture')}>
{123}
</Text>
</Text>
</Text>
</ContextHack>,
1,
);
</ContextHack>,
1,
);
}).toErrorDev([
'ContextHack uses the legacy childContextTypes API which will soon be removed. Use React.createContext() instead.',
]);

expect(UIManager.createView).toHaveBeenCalledTimes(5);

Expand Down
Loading

0 comments on commit 59752f7

Please sign in to comment.