Bug 1514815 - Keep console scrolled to bottom when rendering SmartTrace; r=bgrins.

Depends on D14999

Differential Revision: https://phabricator.services.mozilla.com/D15010

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nicolas Chevobbe 2018-12-19 21:06:40 +00:00
parent e753e09155
commit ece2924f8d
9 changed files with 85 additions and 17 deletions

View File

@ -67,6 +67,7 @@ class ConsoleOutput extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.onContextMenu = this.onContextMenu.bind(this); this.onContextMenu = this.onContextMenu.bind(this);
this.maybeScrollToBottom = this.maybeScrollToBottom.bind(this);
} }
componentDidMount() { componentDidMount() {
@ -125,6 +126,10 @@ class ConsoleOutput extends Component {
} }
componentDidUpdate() { componentDidUpdate() {
this.maybeScrollToBottom();
}
maybeScrollToBottom() {
if (this.shouldScrollBottom) { if (this.shouldScrollBottom) {
scrollToBottom(this.outputNode); scrollToBottom(this.outputNode);
} }
@ -177,6 +182,7 @@ class ConsoleOutput extends Component {
pausedExecutionPoint, pausedExecutionPoint,
getMessage: () => messages.get(messageId), getMessage: () => messages.get(messageId),
isPaused: pausedMessage && pausedMessage.id == messageId, isPaused: pausedMessage && pausedMessage.id == messageId,
maybeScrollToBottom: this.maybeScrollToBottom,
})); }));
return ( return (

View File

@ -36,6 +36,7 @@ GripMessageBody.propTypes = {
escapeWhitespace: PropTypes.bool, escapeWhitespace: PropTypes.bool,
type: PropTypes.string, type: PropTypes.string,
helperType: PropTypes.string, helperType: PropTypes.string,
maybeScrollToBottom: PropTypes.func,
}; };
GripMessageBody.defaultProps = { GripMessageBody.defaultProps = {
@ -51,6 +52,7 @@ function GripMessageBody(props) {
escapeWhitespace, escapeWhitespace,
mode = MODE.LONG, mode = MODE.LONG,
dispatch, dispatch,
maybeScrollToBottom,
} = props; } = props;
let styleObject; let styleObject;
@ -61,6 +63,7 @@ function GripMessageBody(props) {
const objectInspectorProps = { const objectInspectorProps = {
autoExpandDepth: shouldAutoExpandObjectInspector(props) ? 1 : 0, autoExpandDepth: shouldAutoExpandObjectInspector(props) ? 1 : 0,
mode, mode,
maybeScrollToBottom,
// TODO: we disable focus since the tabbing trail is a bit weird in the output (e.g. // TODO: we disable focus since the tabbing trail is a bit weird in the output (e.g.
// location links are not focused). Let's remove the property below when we found and // location links are not focused). Let's remove the property below when we found and
// fixed the issue (See Bug 1456060). // fixed the issue (See Bug 1456060).

View File

@ -70,6 +70,7 @@ class Message extends Component {
frame: PropTypes.any, frame: PropTypes.any,
})), })),
isPaused: PropTypes.bool, isPaused: PropTypes.bool,
maybeScrollToBottom: PropTypes.func,
}; };
} }
@ -210,6 +211,7 @@ class Message extends Component {
onViewSourceInScratchpad: serviceContainer.onViewSourceInScratchpad onViewSourceInScratchpad: serviceContainer.onViewSourceInScratchpad
|| serviceContainer.onViewSource, || serviceContainer.onViewSource,
onViewSource: serviceContainer.onViewSource, onViewSource: serviceContainer.onViewSource,
onReady: this.props.maybeScrollToBottom,
sourceMapService: serviceContainer.sourceMapService, sourceMapService: serviceContainer.sourceMapService,
}), }),
); );

View File

@ -24,6 +24,7 @@ ConsoleApiCall.propTypes = {
open: PropTypes.bool, open: PropTypes.bool,
serviceContainer: PropTypes.object.isRequired, serviceContainer: PropTypes.object.isRequired,
timestampsVisible: PropTypes.bool.isRequired, timestampsVisible: PropTypes.bool.isRequired,
maybeScrollToBottom: PropTypes.func,
}; };
ConsoleApiCall.defaultProps = { ConsoleApiCall.defaultProps = {
@ -41,6 +42,7 @@ function ConsoleApiCall(props) {
repeat, repeat,
pausedExecutionPoint, pausedExecutionPoint,
isPaused, isPaused,
maybeScrollToBottom,
} = props; } = props;
const { const {
id: messageId, id: messageId,
@ -66,6 +68,7 @@ function ConsoleApiCall(props) {
userProvidedStyles, userProvidedStyles,
serviceContainer, serviceContainer,
type, type,
maybeScrollToBottom,
}; };
if (type === "trace") { if (type === "trace") {
@ -137,6 +140,7 @@ function ConsoleApiCall(props) {
timeStamp, timeStamp,
timestampsVisible, timestampsVisible,
parameters, parameters,
maybeScrollToBottom,
}); });
} }
@ -150,6 +154,7 @@ function formatReps(options = {}) {
serviceContainer, serviceContainer,
userProvidedStyles, userProvidedStyles,
type, type,
maybeScrollToBottom,
} = options; } = options;
return ( return (
@ -166,6 +171,7 @@ function formatReps(options = {}) {
loadedObjectProperties, loadedObjectProperties,
loadedObjectEntries, loadedObjectEntries,
type, type,
maybeScrollToBottom,
})) }))
// Interleave spaces. // Interleave spaces.
.reduce((arr, v, i) => { .reduce((arr, v, i) => {

View File

@ -17,6 +17,7 @@ ConsoleCommand.propTypes = {
message: PropTypes.object.isRequired, message: PropTypes.object.isRequired,
timestampsVisible: PropTypes.bool.isRequired, timestampsVisible: PropTypes.bool.isRequired,
serviceContainer: PropTypes.object, serviceContainer: PropTypes.object,
maybeScrollToBottom: PropTypes.func,
}; };
/** /**
@ -27,6 +28,7 @@ function ConsoleCommand(props) {
message, message,
timestampsVisible, timestampsVisible,
serviceContainer, serviceContainer,
maybeScrollToBottom,
} = props; } = props;
const { const {
@ -51,6 +53,7 @@ function ConsoleCommand(props) {
indent, indent,
timeStamp, timeStamp,
timestampsVisible, timestampsVisible,
maybeScrollToBottom,
}); });
} }

View File

@ -19,6 +19,7 @@ EvaluationResult.propTypes = {
message: PropTypes.object.isRequired, message: PropTypes.object.isRequired,
timestampsVisible: PropTypes.bool.isRequired, timestampsVisible: PropTypes.bool.isRequired,
serviceContainer: PropTypes.object, serviceContainer: PropTypes.object,
maybeScrollToBottom: PropTypes.func,
}; };
function EvaluationResult(props) { function EvaluationResult(props) {
@ -27,6 +28,7 @@ function EvaluationResult(props) {
message, message,
serviceContainer, serviceContainer,
timestampsVisible, timestampsVisible,
maybeScrollToBottom,
} = props; } = props;
const { const {
@ -63,6 +65,7 @@ function EvaluationResult(props) {
escapeWhitespace: false, escapeWhitespace: false,
type, type,
helperType, helperType,
maybeScrollToBottom,
}); });
} }
@ -83,6 +86,7 @@ function EvaluationResult(props) {
parameters, parameters,
notes, notes,
timestampsVisible, timestampsVisible,
maybeScrollToBottom,
}); });
} }

View File

@ -18,6 +18,7 @@ PageError.propTypes = {
open: PropTypes.bool, open: PropTypes.bool,
timestampsVisible: PropTypes.bool.isRequired, timestampsVisible: PropTypes.bool.isRequired,
serviceContainer: PropTypes.object, serviceContainer: PropTypes.object,
maybeScrollToBottom: PropTypes.func,
}; };
PageError.defaultProps = { PageError.defaultProps = {
@ -33,6 +34,7 @@ function PageError(props) {
serviceContainer, serviceContainer,
timestampsVisible, timestampsVisible,
isPaused, isPaused,
maybeScrollToBottom,
} = props; } = props;
const { const {
id: messageId, id: messageId,
@ -77,6 +79,7 @@ function PageError(props) {
timeStamp, timeStamp,
notes, notes,
timestampsVisible, timestampsVisible,
maybeScrollToBottom,
}); });
} }

View File

@ -8,9 +8,16 @@
const TEST_URI = const TEST_URI =
`data:text/html;charset=utf-8,<p>Web Console test for scroll.</p> `data:text/html;charset=utf-8,<p>Web Console test for scroll.</p>
<script> <script>
for (let i = 0; i < 100; i++) { var a = () => b();
console.log("init-" + i); var b = () => c();
} var c = () => console.trace("trace in C");
for (let i = 0; i < 100; i++) {
if (i % 10 === 0) {
c();
}
console.log("init-" + i);
}
</script> </script>
`; `;
add_task(async function() { add_task(async function() {
@ -23,6 +30,10 @@ add_task(async function() {
ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow"); ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow");
ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom"); ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom");
info("Wait until all stacktraces are rendered");
await waitFor(() => outputContainer.querySelectorAll(".frames").length === 10);
ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom");
await refreshTab(); await refreshTab();
info("Console should be scrolled to bottom after refresh from page logs"); info("Console should be scrolled to bottom after refresh from page logs");
@ -30,39 +41,68 @@ add_task(async function() {
ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow"); ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow");
ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom"); ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom");
info("Wait until all stacktraces are rendered");
await waitFor(() => outputContainer.querySelectorAll(".frames").length === 10);
ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom");
info("Scroll up"); info("Scroll up");
outputContainer.scrollTop = 0; outputContainer.scrollTop = 0;
info("Add a message to check that the scroll isn't impacted"); info("Add a console.trace message to check that the scroll isn't impacted");
let receievedMessages = waitForMessages({hud, messages: [{ let onMessage = waitForMessage(hud, "trace in C");
text: "stay",
}]});
ContentTask.spawn(gBrowser.selectedBrowser, {}, function() { ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
content.wrappedJSObject.console.log("stay"); content.wrappedJSObject.c();
}); });
await receievedMessages; let message = await onMessage;
ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow"); ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow");
is(outputContainer.scrollTop, 0, "The console stayed scrolled to the top"); is(outputContainer.scrollTop, 0, "The console stayed scrolled to the top");
info("Wait until the stacktrace is rendered");
await waitFor(() => message.node.querySelector(".frame"));
is(outputContainer.scrollTop, 0, "The console stayed scrolled to the top");
info("Evaluate a command to check that the console scrolls to the bottom"); info("Evaluate a command to check that the console scrolls to the bottom");
receievedMessages = waitForMessages({hud, messages: [{ onMessage = waitForMessage(hud, "42");
text: "42",
}]});
ui.jsterm.execute("21 + 21"); ui.jsterm.execute("21 + 21");
await receievedMessages; await onMessage;
ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow"); ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow");
ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom"); ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom");
info("Add a message to check that the console do scroll since we're at the bottom"); info("Add a message to check that the console do scroll since we're at the bottom");
receievedMessages = waitForMessages({hud, messages: [{ onMessage = waitForMessage(hud, "scroll");
text: "scroll",
}]});
ContentTask.spawn(gBrowser.selectedBrowser, {}, function() { ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
content.wrappedJSObject.console.log("scroll"); content.wrappedJSObject.console.log("scroll");
}); });
await receievedMessages; await onMessage;
ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow"); ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow");
ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom"); ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom");
info("Evaluate an Error object to check that the console scrolls to the bottom");
onMessage = waitForMessage(hud, "myErrorObject", ".message.result");
ui.jsterm.execute(`
x = new Error("myErrorObject");
x.stack = "a@b/c.js:1:2\\nd@e/f.js:3:4";
x;`
);
message = await onMessage;
ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom");
info("Wait until the stacktrace is rendered and check the console is scrolled");
await waitFor(() => message.node.querySelector(".objectBox-stackTrace .frame"));
ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom");
info("Add a console.trace message to check that the console stays scrolled to bottom");
onMessage = waitForMessage(hud, "trace in C");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
content.wrappedJSObject.c();
});
message = await onMessage;
ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow");
ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom");
info("Wait until the stacktrace is rendered");
await waitFor(() => message.node.querySelector(".frame"));
ok(isScrolledToBottom(outputContainer), "The console is scrolled to the bottom");
}); });
function hasVerticalOverflow(container) { function hasVerticalOverflow(container) {

View File

@ -62,6 +62,7 @@ function getObjectInspector(grip, serviceContainer, override = {}) {
? serviceContainer.onViewSourceInScratchpad || serviceContainer.onViewSource ? serviceContainer.onViewSourceInScratchpad || serviceContainer.onViewSource
: null, : null,
onViewSource: serviceContainer.onViewSource, onViewSource: serviceContainer.onViewSource,
onReady: override.maybeScrollToBottom,
sourceMapService: serviceContainer ? serviceContainer.sourceMapService : null, sourceMapService: serviceContainer ? serviceContainer.sourceMapService : null,
}), }),
}; };