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
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE HTML>
<html>
<!--
Test the rendering of a stack trace
-->
<head>
<meta charset="utf-8">
<title>StackTrace component test</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</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 testHappyPath() {
const stacktrace = [
{
lineNumber: 1,
columnNumber: 10,
},
{
functionName: "loadFunc",
lineNumber: 2,
},
];
let onReadyCount = 0;
const props = {
stacktrace,
initialRenderDelay: 2000,
onViewSourceInDebugger: () => {},
onReady: () => {
onReadyCount++;
},
// A mock source map service.
sourceMapURLService: {
subscribeByLocation ({ line, column }, callback) {
const newLine = Number(line.toString().repeat(2));
// Resolve immediately.
callback({
line: newLine,
column,
});
return () => {};
},
},
};
const trace = ReactDOM.render(SmartTrace(props),
window.document.body.querySelector("#s1"));
await forceRender(trace);
const traceEl = ReactDOM.findDOMNode(trace);
ok(traceEl, "Rendered SmartTrace has an element");
const frameEls = Array.from(traceEl.querySelectorAll(".frame"));
ok(frameEls, "Rendered SmartTrace has frames");
is(frameEls.length, 2, "SmartTrace has 2 frames");
checkSmartFrameString({
el: frameEls[0],
functionName: "<anonymous>",
location: "original.js:11",
tooltip: "View source in Debugger → https://bugzilla.mozilla.org/original.js:11",
});
checkSmartFrameString({
el: frameEls[1],
functionName: "loadFunc",
location: "original.js:22",
tooltip: "View source in Debugger → https://bugzilla.mozilla.org/original.js:22",
});
is(onReadyCount, 1, "onReady was called once");
});
add_task(async function testSlowSourcemapService() {
const stacktrace = [
{
functionName: "last",
lineNumber: 1,
columnNumber: 10,
},
{
functionName: "first",
lineNumber: 2,
columnNumber: 10,
},
];
const sourcemapTimeout = 2000;
const initialRenderDelay = 300;
let onReadyCount = 0;
const props = {
stacktrace,
initialRenderDelay,
onViewSourceInDebugger: () => {},
onReady: () => {
onReadyCount++;
},
// A mock source map service.
sourceMapURLService: {
subscribeByLocation ({ line, column }, callback) {
// Resolve after a while.
setTimeout(() => {
const newLine = Number(line.toString().repeat(2));
callback({
line: newLine,
column,
});
}, sourcemapTimeout)
return () => {};
},
},
};
const trace = ReactDOM.render(SmartTrace(props),
window.document.body.querySelector("#s2"));
let traceEl = ReactDOM.findDOMNode(trace);
ok(!traceEl, "Nothing was rendered at first");
is(onReadyCount, 0, "onReady isn't called if SmartTrace isn't rendered");
info("Wait for the initial delay to be over");
await new Promise(res => setTimeout(res, initialRenderDelay));
traceEl = ReactDOM.findDOMNode(trace);
ok(traceEl, "The trace was rendered");
let frameEls = Array.from(traceEl.querySelectorAll(".frame"));
ok(frameEls, "Rendered SmartTrace has frames");
is(frameEls.length, 2, "SmartTrace has 2 frames");
info("Check that the original frames are displayed after the initial delay");
checkSmartFrameString({
el: frameEls[0],
functionName: "last",
tooltip: "View source in Debugger → https://myfile.com/bundle.js:1",
});
checkSmartFrameString({
el: frameEls[1],
functionName: "first",
tooltip: "View source in Debugger → https://myfile.com/bundle.js:2",
});
is(onReadyCount, 1, "onReady was called once");
info("Check the the sourcemapped version is rendered after the sourcemapTimeout");
await waitFor(() => !!traceEl.querySelector(".group"));
frameEls = Array.from(traceEl.querySelectorAll(".frame"));
is(frameEls.length, 0, "SmartTrace has no frame");
const groups = Array.from(traceEl.querySelectorAll(".group"));
is(groups.length, 1, "SmartTrace has a group");
is(groups[0].textContent.trim(), "React 2", "A collapsed React group is displayed");
is(onReadyCount, 1, "onReady was only called once");
});
add_task(async function testFlakySourcemapService() {
const stacktrace = [
{
functionName: "last",
lineNumber: 1,
columnNumber: 10,
},
{
functionName: "pending",
lineNumber: 2,
columnNumber: 10,
},
{
functionName: "first",
lineNumber: 3,
columnNumber: 10,
},
];
const initialRenderDelay = 300;
const onSourceMapResultDebounceDelay = 50;
let onReadyCount = 0;
const props = {
stacktrace,
initialRenderDelay,
onSourceMapResultDebounceDelay,
onViewSourceInDebugger: () => {},
onReady: () => {
onReadyCount++;
},
// A mock source map service.
sourceMapURLService: {
subscribeByLocation ({ line, column }, callback) {
// Don't call the callback for the second frame to simulate a flaky sourcemap
// service request.
if (line === 2) {
return () => {};
}
const newLine = Number(line.toString().repeat(2));
callback({
url: `https://myfile.com/file-${line}.js`,
line: newLine,
column,
});
return () => {};
},
},
};
const trace = ReactDOM.render(SmartTrace(props),
window.document.body.querySelector("#s3"));
let traceEl = ReactDOM.findDOMNode(trace);
ok(!traceEl, "Nothing was rendered at first");
is(onReadyCount, 0, "onReady isn't called if SmartTrace isn't rendered");
info("Wait for the initial delay + debounce to be over");
await waitFor(() => {
const el = ReactDOM.findDOMNode(trace)
return el && el.textContent.includes("file-1.js");
});
traceEl = ReactDOM.findDOMNode(trace);
ok(traceEl, "The trace was rendered");
const frameEls = Array.from(traceEl.querySelectorAll(".frame"));
ok(frameEls, "Rendered SmartTrace has frames");
is(frameEls.length, 3, "SmartTrace has 3 frames");
info("Check that the original frames are displayed even if there's no sourcemap " +
"response for some frames");
checkSmartFrameString({
el: frameEls[0],
functionName: "last",
location: "file-1.js:11",
tooltip: "View source in Debugger → https://myfile.com/file-1.js:11",
});
checkSmartFrameString({
el: frameEls[1],
functionName: "pending",
location: "bundle.js:2",
tooltip: "View source in Debugger → https://myfile.com/bundle.js:2",
});
checkSmartFrameString({
el: frameEls[2],
functionName: "first",
location: "file-3.js:33",
tooltip: "View source in Debugger → https://myfile.com/file-3.js:33",
});
is(onReadyCount, 1, "onReady was only called once");
});
};
</script>
<section id=s1></section>
<section id=s2></section>
<section id=s3></section>
</body>
</html>