Skip to content

Commit

Permalink
Bug 1776262 - [devtools] Fix stuck to bottom console output. r=jdesco…
Browse files Browse the repository at this point in the history
…ttes, a=RyanVM

When the last visible message was an evaluation result
but the last message in the store was something else,
the console would trigger the pin-to-bottom behavior.
This is fixed by checking if the last message in the
store (and not the last visible message) is a result.
A test case is added to make sure we don't regress.

Differential Revision: https://phabricator.services.mozilla.com/D150225
  • Loading branch information
nchevobbe committed Jun 24, 2022
1 parent 5e5ab80 commit 62832d3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 3 deletions.
10 changes: 7 additions & 3 deletions devtools/client/webconsole/components/Output/ConsoleOutput.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const {
getAllMessagesUiById,
getAllCssMessagesMatchingElements,
getAllNetworkMessagesUpdateById,
getLastMessageId,
getVisibleMessages,
getAllRepeatById,
getAllWarningGroupsById,
Expand Down Expand Up @@ -65,6 +66,7 @@ class ConsoleOutput extends Component {
editorMode: PropTypes.bool.isRequired,
cacheGeneration: PropTypes.number.isRequired,
disableVirtualization: PropTypes.bool,
lastMessageId: PropTypes.string.isRequired,
};
}

Expand Down Expand Up @@ -165,11 +167,12 @@ class ConsoleOutput extends Component {
const visibleMessagesDelta =
nextProps.visibleMessages.length - this.props.visibleMessages.length;
const messagesDelta = nextProps.messageCount - this.props.messageCount;
// We can retrieve the last message id in visibleMessages as evaluation result are
// always visible.
// Evaluation results are never filtered out, so if it's in the store, it will be
// visible in the output.
const isNewMessageEvaluationResult =
messagesDelta > 0 &&
nextProps.mutableMessages.get(nextProps.visibleMessages.at(-1))?.type ===
nextProps.lastMessageId &&
nextProps.mutableMessages.get(nextProps.lastMessageId)?.type ===
MESSAGE_TYPE.RESULT;

const messagesUiDelta =
Expand Down Expand Up @@ -350,6 +353,7 @@ function mapStateToProps(state, props) {
// on state change (since we can't do it with mutableMessagesById).
messageCount: mutableMessages.size,
mutableMessages,
lastMessageId: getLastMessageId(state),
visibleMessages: getVisibleMessages(state),
messagesUi: getAllMessagesUiById(state),
cssMatchingElements: getAllCssMessagesMatchingElements(state),
Expand Down
5 changes: 5 additions & 0 deletions devtools/client/webconsole/selectors/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ function getAllWarningGroupsById(state) {
return state.messages.warningGroupsById;
}

function getLastMessageId(state) {
return state.messages.lastMessageId;
}

function isMessageInWarningGroup(message, visibleMessages = []) {
if (!getWarningGroupType(message)) {
return false;
Expand All @@ -76,6 +80,7 @@ module.exports = {
getCurrentGroup,
getFilteredMessagesCount,
getGroupsById,
getLastMessageId,
getMessage,
getVisibleMessages,
isMessageInWarningGroup,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const TEST_URI = `data:text/html;charset=utf-8,<!DOCTYPE html><p>Web Console tes
}
</script>
`;

const { MESSAGE_SOURCE } = require("devtools/client/webconsole/constants");

add_task(async function() {
const hud = await openNewTabAndConsole(TEST_URI);
const { ui } = hud;
Expand Down Expand Up @@ -90,6 +93,47 @@ add_task(async function() {
"The console is scrolled to the bottom"
);

info("Scroll up and wait for the layout to stabilize");
outputContainer.scrollTop = 0;
await new Promise(r =>
window.requestAnimationFrame(() => TestUtils.executeSoon(r))
);

info(
"Trigger a network request so the last message in the console store won't be visible"
);
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
await content.fetch(
"http://mochi.test:8888/browser/devtools/client/webconsole/test/browser/sjs_cors-test-server.sjs",
{ mode: "cors" }
);
});

// Wait until the evalation result message isn't the last in the store anymore
await waitFor(() => {
const state = ui.wrapper.getStore().getState();
return (
state.messages.mutableMessagesById.get(state.messages.lastMessageId)
?.source === MESSAGE_SOURCE.NETWORK
);
});

// Wait a bit so the pin to bottom would have the chance to be hit.
await wait(500);
ok(
!isScrolledToBottom(outputContainer),
"The console is not scrolled to the bottom"
);

info(
"Evaluate a new command to check that the console scrolls to the bottom"
);
await executeAndWaitForResultMessage(hud, "7 + 2", "9");
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"
);
Expand Down

0 comments on commit 62832d3

Please sign in to comment.