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

View File

@ -36,6 +36,7 @@ GripMessageBody.propTypes = {
escapeWhitespace: PropTypes.bool,
type: PropTypes.string,
helperType: PropTypes.string,
maybeScrollToBottom: PropTypes.func,
};
GripMessageBody.defaultProps = {
@ -51,6 +52,7 @@ function GripMessageBody(props) {
escapeWhitespace,
mode = MODE.LONG,
dispatch,
maybeScrollToBottom,
} = props;
let styleObject;
@ -61,6 +63,7 @@ function GripMessageBody(props) {
const objectInspectorProps = {
autoExpandDepth: shouldAutoExpandObjectInspector(props) ? 1 : 0,
mode,
maybeScrollToBottom,
// 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
// fixed the issue (See Bug 1456060).

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,9 +8,16 @@
const TEST_URI =
`data:text/html;charset=utf-8,<p>Web Console test for scroll.</p>
<script>
for (let i = 0; i < 100; i++) {
console.log("init-" + i);
}
var a = () => b();
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>
`;
add_task(async function() {
@ -23,6 +30,10 @@ add_task(async function() {
ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow");
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();
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(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");
outputContainer.scrollTop = 0;
info("Add a message to check that the scroll isn't impacted");
let receievedMessages = waitForMessages({hud, messages: [{
text: "stay",
}]});
info("Add a console.trace message to check that the scroll isn't impacted");
let onMessage = waitForMessage(hud, "trace in C");
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");
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");
receievedMessages = waitForMessages({hud, messages: [{
text: "42",
}]});
onMessage = waitForMessage(hud, "42");
ui.jsterm.execute("21 + 21");
await receievedMessages;
await onMessage;
ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow");
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");
receievedMessages = waitForMessages({hud, messages: [{
text: "scroll",
}]});
onMessage = waitForMessage(hud, "scroll");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
content.wrappedJSObject.console.log("scroll");
});
await receievedMessages;
await onMessage;
ok(hasVerticalOverflow(outputContainer), "There is a vertical overflow");
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) {

View File

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