main
js 129 lines 4.11 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @emails react-core
8 */
9
10 'use strict';
11
12 let React;
13 let ReactDOMClient;
14 let ReactFeatureFlags;
15 let act;
16 let container;
17 let assertConsoleErrorDev;
18
19 function loadModules({
20 enableProfilerTimer = true,
21 enableProfilerCommitHooks = true,
22 enableProfilerNestedUpdatePhase = true,
23 } = {}) {
24 ReactFeatureFlags = require('shared/ReactFeatureFlags');
25
26 ReactFeatureFlags.enableProfilerTimer = enableProfilerTimer;
27 ReactFeatureFlags.enableProfilerCommitHooks = enableProfilerCommitHooks;
28 ReactFeatureFlags.enableProfilerNestedUpdatePhase =
29 enableProfilerNestedUpdatePhase;
30
31 React = require('react');
32 ReactDOMClient = require('react-dom/client');
33 const InternalTestUtils = require('internal-test-utils');
34 act = InternalTestUtils.act;
35 assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
36 }
37
38 describe('Profiler', () => {
39 beforeEach(() => {
40 container = document.createElement('div');
41 });
42
43 describe('works in profiling and non-profiling bundles', () => {
44 [true, false].forEach(enableProfilerTimer => {
45 describe(`enableProfilerTimer:${
46 enableProfilerTimer ? 'enabled' : 'disabled'
47 }`, () => {
48 beforeEach(() => {
49 jest.resetModules();
50
51 loadModules({enableProfilerTimer});
52 });
53
54 // This will throw in production too,
55 // But the test is only interested in verifying the DEV error message.
56 if (__DEV__ && enableProfilerTimer) {
57 it('should warn if required params are missing', async () => {
58 const root = ReactDOMClient.createRoot(container);
59 await act(() => {
60 root.render(<React.Profiler />);
61 });
62 assertConsoleErrorDev([
63 'Profiler must specify an "id" of type `string` as a prop. Received the type `undefined` instead.',
64 ]);
65 });
66 }
67
68 it('should support an empty Profiler (with no children)', async () => {
69 const root = ReactDOMClient.createRoot(container);
70 // As root
71 await act(() => {
72 root.render(<React.Profiler id="label" onRender={jest.fn()} />);
73 });
74 expect(container.innerHTML).toMatchSnapshot();
75
76 // As non-root
77 await act(() => {
78 root.render(
79 <div>
80 <React.Profiler id="label" onRender={jest.fn()} />
81 </div>,
82 );
83 });
84 expect(container.innerHTML).toMatchSnapshot();
85 });
86
87 it('should render children', async () => {
88 const FunctionComponent = ({label}) => <span>{label}</span>;
89 const root = ReactDOMClient.createRoot(container);
90 await act(() => {
91 root.render(
92 <div>
93 <span>outside span</span>
94 <React.Profiler id="label" onRender={jest.fn()}>
95 <span>inside span</span>
96 <FunctionComponent label="function component" />
97 </React.Profiler>
98 </div>,
99 );
100 });
101 expect(container.innerHTML).toMatchSnapshot();
102 });
103
104 it('should support nested Profilers', async () => {
105 const FunctionComponent = ({label}) => <div>{label}</div>;
106 class ClassComponent extends React.Component {
107 render() {
108 return <span>{this.props.label}</span>;
109 }
110 }
111 const root = ReactDOMClient.createRoot(container);
112 await act(() => {
113 root.render(
114 <React.Profiler id="outer" onRender={jest.fn()}>
115 <FunctionComponent label="outer function component" />
116 <React.Profiler id="inner" onRender={jest.fn()}>
117 <ClassComponent label="inner class component" />
118 <span>inner span</span>
119 </React.Profiler>
120 </React.Profiler>,
121 );
122 });
123
124 expect(container.innerHTML).toMatchSnapshot();
125 });
126 });
127 });
128 });
129 });