/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ import type Store from 'react-devtools-shared/src/devtools/store'; describe('commit tree', () => { let React; let ReactDOMClient; let Scheduler; let legacyRender; let store: Store; let utils; beforeEach(() => { utils = require('./utils'); utils.beforeEachProfiling(); legacyRender = utils.legacyRender; store = global.store; store.collapseNodesByDefault = false; store.recordChangeDescriptions = true; React = require('react'); ReactDOMClient = require('react-dom/client'); Scheduler = require('scheduler'); }); // @reactVersion >= 16.9 it('should be able to rebuild the store tree for each commit', () => { const Parent = ({count}) => { Scheduler.unstable_advanceTime(10); return new Array(count) .fill(true) .map((_, index) => ); }; const Child = React.memo(function Child() { Scheduler.unstable_advanceTime(2); return null; }); const container = document.createElement('div'); utils.act(() => store.profilerStore.startProfiling()); utils.act(() => legacyRender(, container)); expect(store).toMatchInlineSnapshot(` [root] ▾ [Memo] `); utils.act(() => legacyRender(, container)); expect(store).toMatchInlineSnapshot(` [root] ▾ [Memo] [Memo] [Memo] `); utils.act(() => legacyRender(, container)); expect(store).toMatchInlineSnapshot(` [root] ▾ [Memo] [Memo] `); utils.act(() => legacyRender(, container)); expect(store).toMatchInlineSnapshot(` [root] `); utils.act(() => store.profilerStore.stopProfiling()); const rootID = store.roots[0]; const commitTrees = []; for (let commitIndex = 0; commitIndex < 4; commitIndex++) { commitTrees.push( store.profilerStore.profilingCache.getCommitTree({ commitIndex, rootID, }), ); } expect(commitTrees[0].nodes.size).toBe(3); // + + expect(commitTrees[1].nodes.size).toBe(5); // + + x 3 expect(commitTrees[2].nodes.size).toBe(4); // + + x 2 expect(commitTrees[3].nodes.size).toBe(2); // + }); describe('Lazy', () => { async function fakeImport(result) { return {default: result}; } const LazyInnerComponent = () => null; const App = ({renderChildren}) => { if (renderChildren) { return ( ); } else { return null; } }; let LazyComponent; beforeEach(() => { LazyComponent = React.lazy(() => fakeImport(LazyInnerComponent)); }); // @reactVersion >= 16.9 it('should support Lazy components (legacy render)', async () => { const container = document.createElement('div'); utils.act(() => store.profilerStore.startProfiling()); utils.act(() => legacyRender(, container)); await Promise.resolve(); expect(store).toMatchInlineSnapshot(` [root] ▾ `); utils.act(() => legacyRender(, container)); expect(store).toMatchInlineSnapshot(` [root] ▾ `); utils.act(() => legacyRender(, container)); expect(store).toMatchInlineSnapshot(` [root] `); utils.act(() => store.profilerStore.stopProfiling()); const rootID = store.roots[0]; const commitTrees = []; for (let commitIndex = 0; commitIndex < 3; commitIndex++) { commitTrees.push( store.profilerStore.profilingCache.getCommitTree({ commitIndex, rootID, }), ); } expect(commitTrees[0].nodes.size).toBe(3); // + + expect(commitTrees[1].nodes.size).toBe(4); // + + + expect(commitTrees[2].nodes.size).toBe(2); // + }); // @reactVersion >= 18.0 it('should support Lazy components (createRoot)', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); utils.act(() => store.profilerStore.startProfiling()); utils.act(() => root.render()); await Promise.resolve(); expect(store).toMatchInlineSnapshot(` [root] ▾ `); utils.act(() => root.render()); expect(store).toMatchInlineSnapshot(` [root] ▾ `); utils.act(() => root.render()); expect(store).toMatchInlineSnapshot(` [root] `); utils.act(() => store.profilerStore.stopProfiling()); const rootID = store.roots[0]; const commitTrees = []; for (let commitIndex = 0; commitIndex < 3; commitIndex++) { commitTrees.push( store.profilerStore.profilingCache.getCommitTree({ commitIndex, rootID, }), ); } expect(commitTrees[0].nodes.size).toBe(3); // + + expect(commitTrees[1].nodes.size).toBe(4); // + + + expect(commitTrees[2].nodes.size).toBe(2); // + }); // @reactVersion >= 16.9 it('should support Lazy components that are unmounted before resolving (legacy render)', async () => { const container = document.createElement('div'); utils.act(() => store.profilerStore.startProfiling()); utils.act(() => legacyRender(, container)); expect(store).toMatchInlineSnapshot(` [root] ▾ `); utils.act(() => legacyRender(, container)); expect(store).toMatchInlineSnapshot(` [root] `); utils.act(() => store.profilerStore.stopProfiling()); const rootID = store.roots[0]; const commitTrees = []; for (let commitIndex = 0; commitIndex < 2; commitIndex++) { commitTrees.push( store.profilerStore.profilingCache.getCommitTree({ commitIndex, rootID, }), ); } expect(commitTrees[0].nodes.size).toBe(3); // + + expect(commitTrees[1].nodes.size).toBe(2); // + }); // @reactVersion >= 18.0 it('should support Lazy components that are unmounted before resolving (createRoot)', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); utils.act(() => store.profilerStore.startProfiling()); utils.act(() => root.render()); expect(store).toMatchInlineSnapshot(` [root] ▾ `); utils.act(() => root.render()); expect(store).toMatchInlineSnapshot(` [root] `); utils.act(() => store.profilerStore.stopProfiling()); const rootID = store.roots[0]; const commitTrees = []; for (let commitIndex = 0; commitIndex < 2; commitIndex++) { commitTrees.push( store.profilerStore.profilingCache.getCommitTree({ commitIndex, rootID, }), ); } expect(commitTrees[0].nodes.size).toBe(3); // + + expect(commitTrees[1].nodes.size).toBe(2); // + }); }); });