Skip to content
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

Add POC "React Renders" panel #8915

Merged
merged 8 commits into from
Mar 11, 2023
Merged

Conversation

markerikson
Copy link
Collaborator

This PR:

  • Adds a new experimental "React Renders" panel to the debugger sidebar, which shows a list of all userland lines that called a React setState (or even a Redux dispatch, which ends up queueing a re-render). The implementation:
    • Specifically looks for react-dom.development.js
    • Specifically looks for the React-internal function scheduleUpdateOnFiber, which is a central point that all queued React updates funnel through
    • Finds all times that scheduleUpdate got hit
    • For every hit, it gets the stack trace, filters out anything in node_modules, and finds the oldest stack frame in what is presumably user code, which should be the code that triggered the state update and queued the render
    • Also identifies all times that React finished committing a render
  • Shows list items for each setState call with the filename and function, as well as list items for each committed render

image

This is still very much a POC, and I've only tested it with react-dom.development in React 18.2.

But the principle seems pretty solid, and it's worked perfectly in the two recordings (a Redux CSB and a Replay UI recording) I've tested it on.

@vercel
Copy link

vercel bot commented Mar 10, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated
devtools ✅ Ready (Inspect) Visit Preview 💬 Add your feedback Mar 11, 2023 at 4:34AM (UTC)

@qa-wolf
Copy link

qa-wolf bot commented Mar 10, 2023

@replay-io
Copy link

replay-io bot commented Mar 10, 2023

E2E Tests

58 replays were recorded for 7a85bc0.

image 17 Failed
    cypress-01: Test basic cypress reporter functionality
          ```
          expect(received).toHaveCount(expected) // deep equality
          
          Expected: 1
          Received: undefined
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/c6f9ab53-1335-40c1-b0c9-b8a5c6b18f56>breakpoints-01: Test basic breakpoint functionality</a></summary>
        <ol type="1">
          
          ```
          locator.waitFor: Timeout 15000ms exceeded.
          =========================== logs ===========================
          waiting for selector "[data-test-id="ViewToggle-Viewer"]" to be visible
          ============================================================
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/f4a89826-673b-42d6-aca1-7b8bcc585b8b>breakpoints-02: Test unhandled divergence while evaluating at a breakpoint</a></summary>
        <ol type="1">
          
          ```
          locator.waitFor: Timeout 15000ms exceeded.
          =========================== logs ===========================
          waiting for selector "[data-test-id="ViewToggle-Viewer"]" to be visible
          ============================================================
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/d05f816f-3a29-4345-9095-ef319710dbfe>breakpoints-03: Test stepping forward through breakpoints when rewound before the first one</a></summary>
        <ol type="1">
          
          ```
          locator.waitFor: Timeout 15000ms exceeded.
          =========================== logs ===========================
          waiting for selector "[data-test-id="ViewToggle-Viewer"]" to be visible
          ============================================================
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/241b1e9a-7bbb-45a4-8dee-27017bdd2948>console-expressions-01: should cache input eager eval and terminal expressions per instance</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: 5
          Received: 2
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/8a2130d5-07e7-42f0-a085-7fe441d81a7b>inspector-06: Test that styles for elements can be viewed</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/b2d7a8db-6d82-4414-9765-fafb2dc34edc>inspector-07: Test that styles for elements can be viewed</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/08e07beb-2639-4b66-b165-c2389e691e41>logpoints-01: log-points appear in the correct order and allow time warping</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBeGreaterThan(expected)
          
          Expected: > 0
          Received:   0
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/32d0026c-8361-46ff-a85f-733acb285443>logpoints-02: conditional log-points</a></summary>
        <ol type="1">
          
          ```
          locator.waitFor: Timeout 15000ms exceeded.
          =========================== logs ===========================
          waiting for selector "[data-test-id="ViewToggle-Viewer"]" to be visible
          ============================================================
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/bd0a6ebe-5e1f-4434-9784-f8c08860003f>logpoints-07: should use the correct scope in auto-complete</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/e5405475-35ce-41b6-a06f-427dcbf4f4bb>object_preview-01: expressions in the console after time warping</a></summary>
        <ol type="1">
          
          ```
          locator.waitFor: Timeout 15000ms exceeded.
          =========================== logs ===========================
          waiting for selector "[data-test-id="ViewToggle-Viewer"]" to be visible
          ============================================================
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/f407b6b3-7416-4945-b0ca-13fe7aec3a88>react_devtools: Test React DevTools.</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/b14407e5-a4cf-4402-9b7d-9be50013ec74>stepping-01: Test basic step-over/back functionality</a></summary>
        <ol type="1">
          
          ```
          locator.waitFor: Timeout 15000ms exceeded.
          =========================== logs ===========================
          waiting for selector "[data-test-id="ViewToggle-Viewer"]" to be visible
          ============================================================
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/0f48cbcc-cc02-460f-b247-492cd40f5c29>stepping-02: Test fixes for some simple stepping bugs</a></summary>
        <ol type="1">
          
          ```
          locator.waitFor: Timeout 15000ms exceeded.
          =========================== logs ===========================
          waiting for selector "[data-test-id="ViewToggle-Viewer"]" to be visible
          ============================================================
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/ffee9af1-60d5-44f7-9378-e28fe2f6afe0>stepping-03: Stepping past the beginning or end of a frame should act like a step-out</a></summary>
        <ol type="1">
          
          ```
          locator.waitFor: Timeout 15000ms exceeded.
          =========================== logs ===========================
          waiting for selector "[data-test-id="ViewToggle-Viewer"]" to be visible
          ============================================================
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/4b6e42d6-e022-4673-bc44-0e539a5580a4>stepping-04: Test stepping in a frame other than the top frame</a></summary>
        <ol type="1">
          
          ```
          locator.waitFor: Timeout 15000ms exceeded.
          =========================== logs ===========================
          waiting for selector "[data-test-id="ViewToggle-Viewer"]" to be visible
          ============================================================
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/471ae298-005b-4972-b0fa-3cb294abbdbc>stepping-06: Test stepping in async frames and async call stacks</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: true
          Received: false
          ```
        </ol>
      </details>
      
image 41 Passed
  • breakpoints-05: Test interaction of breakpoints with debugger statements
  • breakpoints-06: Test log point in a sourcemapped file
  • breakpoints-07: rewind and seek using command bar and console messages
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <li><a href=https://app.replay.io/recording/9efa39ba-2441-48a2-bdc4-6e5e6e589382>breakpoints-08: should be temporarily disabled</a></li>
      <details>
        <summary><a href=https://app.replay.io/recording/fa1152e9-b5cd-47d6-86f7-420a14493345>console_async: support console evaluations in async frames</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <li><a href=https://app.replay.io/recording/8f51bbd4-3138-438a-956c-3057993f4de3>console_dock_node: Should show the correct docking behavior for recordings without video</a></li>
      <li><a href=https://app.replay.io/recording/d6e44c29-a3e3-4f0b-a78b-1898b4492e61>console_dock: Should show the correct docking behavior for recordings with video</a></li>
      <li><a href=https://app.replay.io/recording/19af1acf-155c-4906-b6d3-ed0151cca0e4>console_errors: Test that errors and warnings from various sources are shown in the console</a></li>
      <li><a href=https://app.replay.io/recording/bf3a3e69-118c-4fef-92ec-30d4cb230e80>console_eval: support console evaluations</a></li>
      <details>
        <summary><a href=https://app.replay.io/recording/c102cd3f-3048-4fbf-8862-4832e434a8c8>console_warp-01: should support warping to console messages</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/7b1e404d-682a-4bf6-8006-f451e715247d>console_warp-02: support pausing, warping, stepping and evaluating console messages</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <li><a href=https://app.replay.io/recording/a511a0a3-7aa3-47e9-a44d-4cfd19d6919b>focus_mode-01: should filter messages as regions based on the active focus mode</a></li>
      <details>
        <summary><a href=https://app.replay.io/recording/c1fa6d46-5827-47b4-afc5-1f8ba528be6b>highlighter: element highlighter works everywhere</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/4cc2b4db-9e79-4d70-9a85-b452b6dc9d97>inspector-01: Test that scopes are rerendered</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/ef615ab1-83bc-4f7d-9681-e2122c161f3a>inspector-02: element picker and iframe behavior</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/4dbd9442-fd35-415b-91de-9989c9907bed>inspector-03: Test that styles for elements can be viewed</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/4132166b-e657-4d11-bb98-7792b0190ed3>inspector-04: Test that styles for elements can be viewed</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <li><a href=https://app.replay.io/recording/097b685b-8402-4b15-a557-a2c1d6968203>inspector-05: Test that styles for elements can be viewed</a></li>
      <li><a href=https://app.replay.io/recording/7dedad4f-4c61-487b-8b08-96179d131ba9>logpoints-03: should display event properties in the console</a></li>
      <details>
        <summary><a href=https://app.replay.io/recording/2c03723b-8e9f-4b5e-9faf-2d1f6a04a334>logpoints-04: should display exceptions in the console</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/ff38b623-d4a0-4eef-b13a-43bb7b993013>logpoints-05: should auto-complete based on log point location</a></summary>
        <ol type="1">
          
          ```
          expect(received).toContain(expected) // indexOf
          
          Expected value: "arrayGlobal"
          Received array: []
          ```
        </ol>
      </details>
      <li><a href=https://app.replay.io/recording/3eea986e-f894-4c36-b91a-bfe6b96c23d2>logpoints-06: should be temporarily disabled</a></li>
      <li><a href=https://app.replay.io/recording/26c75dc3-78cb-470f-bb36-ca149d2b38f7>logpoints-08: should support jumping directly to a hit point via the capsule input</a></li>
      <details>
        <summary><a href=https://app.replay.io/recording/34d86988-5c03-4b0b-926e-339dfde0794d>node_console-01: Basic node console behavior</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/73d83b25-1f0c-43aa-bb04-76d5f9b0ed22>node_console-02: uncaught exceptions should show up</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/596636e8-e9b5-40aa-8757-f151ce70b845>node_logpoint-01: Basic node logpoints</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/94a04fb1-b2c9-4709-a6ba-de4400fcd4e6>node_logpoint-02: Node exception logpoints</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: true
          Received: false
          ```
        </ol>
      </details>
      <li><a href=https://app.replay.io/recording/a84ed9a0-714c-4202-9e5a-0e5d0aa2e257>node_object_preview: Showing console objects in node</a></li>
      <details>
        <summary><a href=https://app.replay.io/recording/04dec16f-8691-416e-9f90-f2a65eada539>node_spawn: Basic subprocess spawning</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/7f5a0d0d-28cc-48f4-93aa-df952bc41da7>node_stepping-01: Test stepping in async frames and async call stacks</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <li><a href=https://app.replay.io/recording/167c7d8e-950f-4404-9bc0-bf2d1456bb4c>node_worker-01: make sure node workers don't cause crashes</a></li>
      <details>
        <summary><a href=https://app.replay.io/recording/cdbec44c-ee0c-4bbf-a704-e87a3acc7d6f>object_preview-02: should allow objects in scope to be inspected</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <li><a href=https://app.replay.io/recording/ff9f5feb-5c9a-4afb-907a-c358afde72f5>object_preview-03: Test previews when switching between frames and stepping</a></li>
      <details>
        <summary><a href=https://app.replay.io/recording/a2154b63-50bb-468c-9e6a-b865d6122eb0>object_preview-04: Test scope mapping and switching between generated/original sources</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/2b99b595-1de1-4e11-baf7-c0f7bcc64230>object_preview-05: Should support logging objects as values</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <li><a href=https://app.replay.io/recording/17955d9a-263a-4020-a1af-b03a920b2fe8>repaint: repaints the screen screen when stepping over code that modifies the DOM</a></li>
      <li><a href=https://app.replay.io/recording/93bfd3d9-6ea2-462c-a417-c6b1e5a07b97>resizable-panels-01: Left side Toolbar should be collapsible</a></li>
      <details>
        <summary><a href=https://app.replay.io/recording/c3ad1667-5ef9-4966-b341-dd29dbe313c4>scopes_rerender: Test that scopes are rerendered</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <li><a href=https://app.replay.io/recording/3a0f17b3-ceee-4ab1-a6bc-fbbdea56eae9>sourcemap_stacktrace: Test that stacktraces are sourcemapped</a></li>
      <details>
        <summary><a href=https://app.replay.io/recording/51ace44d-af04-4d75-8be3-e630db5997f6>stacking: Element highlighter selects the correct element when they overlap</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: "true"
          Received: "false"
          ```
        </ol>
      </details>
      <details>
        <summary><a href=https://app.replay.io/recording/2c2b7db2-bf4c-4af1-a026-0c05417a34e7>stepping-05: Test stepping in pretty-printed code</a></summary>
        <ol type="1">
          
          ```
          expect(received).toBe(expected) // Object.is equality
          
          Expected: true
          Received: false
          ```
        </ol>
      </details>
      

View test run on Replay ↗︎

Snapshot Tests

1 replays were recorded for 7a85bc0.

image 1 Failed
image 0 Passed

View test run on Replay ↗︎

@markerikson markerikson changed the title [DRAFT] Add POC "React Renders" panel Add POC "React Renders" panel Mar 11, 2023
@markerikson markerikson force-pushed the feature/FE-1304-react-renders-list branch from deaf30c to 7a85bc0 Compare March 11, 2023 04:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants