Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
<!DOCTYPE HTML>
<html>
<!--
Test the rendering of a stack trace
-->
<head>
  <meta charset="utf-8">
  <title>StackTrace component test</title>
</head>
<body>
<script src="head.js"></script>
<script>
"use strict";
window.onload = function() {
  const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
  const React = browserRequire("devtools/client/shared/vendor/react");
  const SmartTrace = React.createFactory(
    browserRequire("devtools/client/shared/components/SmartTrace"));
  ok(SmartTrace, "Got the SmartTrace factory");
  add_task(async function() {
    const REACT_FRAMES_COUNT = 10;
    const stacktrace = [
      {
        lineNumber: 55,
        columnNumber: 10,
        functionName: null,
      },
      // Simulated Redux frame
      {
        functionName: "rootReducer",
        lineNumber: 2,
      },
      {
        functionName: "loadFunc",
        lineNumber: 10,
      },
      // Simulated react frames
      ...(Array.from({length: REACT_FRAMES_COUNT}, (_, i) => ({
        functionName: "internalReact" + (REACT_FRAMES_COUNT - i),
        lineNumber: Number(i.toString().repeat(2)),
      }))),
      {
        lineNumber: 10,
        columnNumber: 3,
        functionName: "onClick",
      },
    ];
    const props = {
      stacktrace,
      onViewSourceInDebugger: () => {},
    };
    const trace = ReactDOM.render(SmartTrace(props), window.document.body);
    await forceRender(trace);
    const traceEl = ReactDOM.findDOMNode(trace);
    ok(traceEl, "Rendered SmartTrace has an element");
    isDeeply(getStacktraceText(traceEl), [
      `rootReducer Redux`,
      `▶︎ React 10`,
    ], "React frames are grouped - Redux frame is not");
    info("Expand React group");
    let onReactGroupExpanded = waitFor(() =>
      traceEl.querySelector(".frames-group.expanded"));
    traceEl.querySelector(".frames-group").click();
    await onReactGroupExpanded;
    isDeeply(getStacktraceText(traceEl), [
      `rootReducer Redux`,
      `▼ React 10`,
      `| internalReact10`,
      `| internalReact9`,
      `| internalReact8`,
      `| internalReact7`,
      `| internalReact6`,
      `| internalReact5`,
      `| internalReact4`,
      `| internalReact3`,
      `| internalReact2`,
      `| internalReact1`,
    ], "React frames can be expanded");
    info("Collapse React group");
    onReactGroupExpanded = waitFor(() =>
      !traceEl.querySelector(".frames-group.expanded"));
    traceEl.querySelector(".frames-group").click();
    await onReactGroupExpanded;
    isDeeply(getStacktraceText(traceEl), [
      `rootReducer Redux`,
      `▶︎ React 10`,
    ], "React frames can be collapsed");
  });
  function getStacktraceText(traceElement) {
    return Array.from(traceElement.querySelectorAll(".frame")).map(el => {
        // If it's a group, we want to append an arrow representing the group state
        if (el.classList.contains("frames-group")) {
          const arrow = el.classList.contains("expanded") ? "▼" : "▶︎";
          const content = el.textContent.trim();
          return `${arrow} ${content}`;
        }
        const title = el.querySelector(".title");
        if (el.closest(".frames-list")) {
          return `| ${title.textContent}`;
        }
        const location = el.querySelector(".location");
        return `${title.textContent} ${location.textContent}`;
      });
  }
};
</script>
</body>
</html>