-
Notifications
You must be signed in to change notification settings - Fork 51.2k
[DevTools] hotkey to start/stop profiling #35160
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
Changes from 11 commits
9e916c2
138fb2c
144b936
344d8a5
a793da8
fa8526a
fde4bff
0205bd0
d4f533a
9e756af
3f397de
de7e0c2
5180a8f
b405364
3424b9a
6c0d2b7
daf937c
3a2759a
bde0b30
f62931b
501fe42
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -584,4 +584,101 @@ describe('ProfilerContext', () => { | |
| await utils.actAsync(() => context.selectFiber(childID, 'Child')); | ||
| expect(inspectedElementID).toBe(parentID); | ||
| }); | ||
|
|
||
| it('should toggle profiling when the keyboard shortcut is pressed', async () => { | ||
| // Use real timers for this test to avoid conflicts with Timeline's setInterval | ||
| jest.useRealTimers(); | ||
|
|
||
| // Conetext providers | ||
| const Profiler = | ||
| require('react-devtools-shared/src/devtools/views/Profiler/Profiler').default; | ||
| const { | ||
| TimelineContextController, | ||
| } = require('react-devtools-timeline/src/TimelineContext'); | ||
| const { | ||
| SettingsContextController, | ||
| } = require('react-devtools-shared/src/devtools/views/Settings/SettingsContext'); | ||
| const { | ||
| ModalDialogContextController, | ||
| } = require('react-devtools-shared/src/devtools/views/ModalDialog'); | ||
|
|
||
| // need a dom component for profiling to be enabled | ||
| const Component = () => null; | ||
| utils.act(() => render(<Component />)); | ||
|
|
||
| const profilerContainer = document.createElement('div'); | ||
| document.body.appendChild(profilerContainer); | ||
|
|
||
| // Create a root for the profiler | ||
| const profilerRoot = ReactDOMClient.createRoot(profilerContainer); | ||
|
|
||
| try { | ||
| // Render the profiler - use React.act to ensure render completes | ||
| React.act(() => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you use |
||
| profilerRoot.render( | ||
| <Contexts> | ||
| <SettingsContextController browserTheme="light"> | ||
| <ModalDialogContextController> | ||
| <TimelineContextController> | ||
| <Profiler /> | ||
| </TimelineContextController> | ||
| </ModalDialogContextController> | ||
| </SettingsContextController> | ||
| </Contexts>, | ||
| ); | ||
| }); | ||
|
|
||
| // Wait for any async effects to complete | ||
| await new Promise(resolve => setTimeout(resolve, 100)); | ||
|
|
||
| // Verify that the profiler is not profiling. | ||
| expect(store.profilerStore.isProfilingBasedOnUserInput).toBe(false); | ||
|
|
||
| // Trigger the keyboard shortcut. | ||
| const ownerWindow = profilerContainer.ownerDocument.defaultView; | ||
| const isMac = | ||
| typeof navigator !== 'undefined' && | ||
| navigator.platform.toUpperCase().indexOf('MAC') >= 0; | ||
|
|
||
| const keyEvent = new KeyboardEvent('keydown', { | ||
| key: 'e', | ||
| metaKey: isMac, | ||
| ctrlKey: !isMac, | ||
| bubbles: true, | ||
| }); | ||
|
|
||
| // Helper to wait for profiling state to change | ||
| const waitForProfilingState = async (expectedState, timeoutMs = 1000) => { | ||
| const startTime = Date.now(); | ||
| while ( | ||
| store.profilerStore.isProfilingBasedOnUserInput !== expectedState | ||
| ) { | ||
| if (Date.now() - startTime > timeoutMs) { | ||
| throw new Error( | ||
| `Timeout waiting for profiling to be ${expectedState}. ` + | ||
| `Current state: ${store.profilerStore.isProfilingBasedOnUserInput}`, | ||
| ); | ||
| } | ||
| await new Promise(resolve => setTimeout(resolve, 10)); | ||
| } | ||
| }; | ||
|
|
||
| // Dispatch keyboard event to toggle profiling on | ||
| ownerWindow.dispatchEvent(keyEvent); | ||
| await waitForProfilingState(true); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it have to be async, though? Does it fail if you check it synchronously? If it fails, can you try emitting the event as part of |
||
|
|
||
| expect(store.profilerStore.isProfilingBasedOnUserInput).toBe(true); | ||
|
|
||
| // Dispatch keyboard event to toggle profiling off | ||
| ownerWindow.dispatchEvent(keyEvent); | ||
| await waitForProfilingState(false); | ||
|
|
||
| expect(store.profilerStore.isProfilingBasedOnUserInput).toBe(false); | ||
|
|
||
| document.body.removeChild(profilerContainer); | ||
| } finally { | ||
| // Restore fake timers for other tests | ||
| jest.useFakeTimers(); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you actually need this?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically no because in the setupTest file the before each sets it to use fake timers. I guess the argument would be not being dependent on if that changes?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You probably don't need fake timers here, because there is no logic that is tied to timers: intervals, timeouts, etc. So if it passes with these lines removed, just remove it. If not, lets investigate why this is required.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. before when I used fake timers I was getting a time out after 5 seconds from the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've got it to now use the fake timers and have turned recursively flush off to avoid the timeout |
||
| }); | ||
| }); | ||
Uh oh!
There was an error while loading. Please reload this page.