diff --git a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js index dbb2c1bee1467..90075ec7ea066 100644 --- a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js +++ b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js @@ -310,7 +310,8 @@ describe('ProfilingCache', () => { }); // @reactVersion >= 16.9 - it('should record changed props/state/context/hooks', () => { + // @reactVersion <= 18.2 + it('should record changed props/state/context/hooks for React version [16.9; 18.2] with legacy context', () => { let instance = null; const ModernContext = React.createContext(0); @@ -411,21 +412,6 @@ describe('ProfilingCache', () => { }, } `); - - if (gate(flags => !flags.disableLegacyContext)) { - expect(changeDescriptions[1].get(6).context).toEqual(['count']); - expect(changeDescriptions[1].get(7).props).toEqual(['count']); - expect(changeDescriptions[2].get(6).context).toEqual([]); - expect(changeDescriptions[3].get(6).context).toEqual([]); - expect(changeDescriptions[4].get(6).context).toEqual([]); - - changeDescriptions[1].get(6).context = null; - changeDescriptions[1].get(7).props = []; - changeDescriptions[2].get(6).context = null; - changeDescriptions[3].get(6).context = null; - changeDescriptions[4].get(6).context = null; - } - expect(changeDescriptions[1]).toMatchInlineSnapshot(` Map { 5 => { @@ -451,11 +437,15 @@ describe('ProfilingCache', () => { "didHooksChange": false, "hooks": [], "isFirstMount": false, - "props": [], + "props": [ + "count", + ], "state": null, }, 6 => { - "context": null, + "context": [ + "count", + ], "didHooksChange": false, "hooks": null, "isFirstMount": false, @@ -501,7 +491,7 @@ describe('ProfilingCache', () => { "state": null, }, 6 => { - "context": null, + "context": [], "didHooksChange": false, "hooks": null, "isFirstMount": false, @@ -547,7 +537,7 @@ describe('ProfilingCache', () => { "state": null, }, 6 => { - "context": null, + "context": [], "didHooksChange": false, "hooks": null, "isFirstMount": false, @@ -594,7 +584,7 @@ describe('ProfilingCache', () => { "state": null, }, 6 => { - "context": null, + "context": [], "didHooksChange": false, "hooks": null, "isFirstMount": false, @@ -630,6 +620,381 @@ describe('ProfilingCache', () => { } }); + // @reactVersion > 18.2 + // @gate !disableLegacyContext + it('should record changed props/state/context/hooks for React version (18.2; ∞) with legacy context enabled', () => { + let instance = null; + + const ModernContext = React.createContext(0); + + class LegacyContextProvider extends React.Component { + static childContextTypes = { + count: PropTypes.number, + }; + state = {count: 0}; + getChildContext() { + return this.state; + } + render() { + instance = this; + return ( + + + + + + + ); + } + } + + const FunctionComponentWithHooks = ({count}) => { + React.useMemo(() => count, [count]); + return null; + }; + + class ModernContextConsumer extends React.Component { + static contextType = ModernContext; + render() { + return ; + } + } + + class LegacyContextConsumer extends React.Component { + static contextTypes = { + count: PropTypes.number, + }; + render() { + return ; + } + } + + utils.act(() => store.profilerStore.startProfiling()); + utils.act(() => render()); + expect(instance).not.toBeNull(); + utils.act(() => (instance: any).setState({count: 1})); + utils.act(() => render()); + utils.act(() => render()); + utils.act(() => render()); + utils.act(() => store.profilerStore.stopProfiling()); + + const rootID = store.roots[0]; + + let changeDescriptions = store.profilerStore + .getDataForRoot(rootID) + .commitData.map(commitData => commitData.changeDescriptions); + expect(changeDescriptions).toHaveLength(5); + expect(changeDescriptions[0]).toEqual( + new Map([ + [ + 2, + { + context: null, + didHooksChange: false, + isFirstMount: true, + props: null, + state: null, + }, + ], + [ + 4, + { + context: null, + didHooksChange: false, + isFirstMount: true, + props: null, + state: null, + }, + ], + [ + 5, + { + context: null, + didHooksChange: false, + isFirstMount: true, + props: null, + state: null, + }, + ], + [ + 6, + { + context: null, + didHooksChange: false, + isFirstMount: true, + props: null, + state: null, + }, + ], + [ + 7, + { + context: null, + didHooksChange: false, + isFirstMount: true, + props: null, + state: null, + }, + ], + ]), + ); + + expect(changeDescriptions[1]).toEqual( + new Map([ + [ + 5, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: ['count'], + state: null, + }, + ], + [ + 4, + { + context: true, + didHooksChange: false, + hooks: null, + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 7, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: ['count'], + state: null, + }, + ], + [ + 6, + { + context: ['count'], + didHooksChange: false, + hooks: null, + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 2, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: [], + state: ['count'], + }, + ], + ]), + ); + + expect(changeDescriptions[2]).toEqual( + new Map([ + [ + 5, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 4, + { + context: false, + didHooksChange: false, + hooks: null, + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 7, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 6, + { + context: [], + didHooksChange: false, + hooks: null, + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 2, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: ['foo'], + state: [], + }, + ], + ]), + ); + + expect(changeDescriptions[3]).toEqual( + new Map([ + [ + 5, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 4, + { + context: false, + didHooksChange: false, + hooks: null, + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 7, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 6, + { + context: [], + didHooksChange: false, + hooks: null, + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 2, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: ['foo', 'bar'], + state: [], + }, + ], + ]), + ); + + expect(changeDescriptions[4]).toEqual( + new Map([ + [ + 5, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 4, + { + context: false, + didHooksChange: false, + hooks: null, + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 7, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 6, + { + context: [], + didHooksChange: false, + hooks: null, + isFirstMount: false, + props: [], + state: null, + }, + ], + [ + 2, + { + context: null, + didHooksChange: false, + hooks: [], + isFirstMount: false, + props: ['bar'], + state: [], + }, + ], + ]), + ); + + utils.exportImportHelper(bridge, store); + + const prevChangeDescriptions = [...changeDescriptions]; + + changeDescriptions = store.profilerStore + .getDataForRoot(rootID) + .commitData.map(commitData => commitData.changeDescriptions); + expect(changeDescriptions).toHaveLength(5); + + for (let commitIndex = 0; commitIndex < 5; commitIndex++) { + expect(changeDescriptions[commitIndex]).toEqual( + prevChangeDescriptions[commitIndex], + ); + } + }); + // @reactVersion >= 18.0 it('should properly detect changed hooks', () => { const Context = React.createContext(0);