tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 9e78e273bf8c1a71fece48f072120cf3a3d0a847
parent 1fd5f4ea8bc7ac5c731a59a5b20f83a78c1ea418
Author: Hubert Boma Manilla <hmanilla@mozilla.com>
Date:   Mon,  6 Oct 2025 17:23:02 +0000

Bug 1988710 - [devtools] Makes sure to scroll to selected matched text r=devtools-reviewers,nchevobbe

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

Diffstat:
Mdevtools/client/netmonitor/src/actions/search.js | 2+-
Mdevtools/client/netmonitor/src/components/previews/SourcePreview.js | 16+++++++++++++---
Mdevtools/client/netmonitor/test/browser_net_search-results.js | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdevtools/client/netmonitor/test/head.js | 10++++++++++
Mdevtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand.js | 6------
Mdevtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand_before_updates.js | 6------
Mdevtools/client/webconsole/test/browser/head.js | 12++++++++++++
7 files changed, 155 insertions(+), 16 deletions(-)

diff --git a/devtools/client/netmonitor/src/actions/search.js b/devtools/client/netmonitor/src/actions/search.js @@ -298,7 +298,7 @@ function navigate(searchResult) { // for search result navigation within the side panels. dispatch(setTargetSearchResult(searchResult)); - // Preselect the right side panel. + // Preselect the required side panel. dispatch(selectDetailsPanelTab(searchResult.panel)); // Select related request in the UI (it also opens the diff --git a/devtools/client/netmonitor/src/components/previews/SourcePreview.js b/devtools/client/netmonitor/src/components/previews/SourcePreview.js @@ -160,6 +160,16 @@ class SourcePreview extends Component { } } -module.exports = connect(null, dispatch => ({ - resetTargetSearchResult: () => dispatch(setTargetSearchResult(null)), -}))(SourcePreview); +module.exports = connect( + state => { + if (!state.search) { + return null; + } + return { + targetSearchResult: state.search.targetSearchResult, + }; + }, + dispatch => ({ + resetTargetSearchResult: () => dispatch(setTargetSearchResult(null)), + }) +)(SourcePreview); diff --git a/devtools/client/netmonitor/test/browser_net_search-results.js b/devtools/client/netmonitor/test/browser_net_search-results.js @@ -349,6 +349,125 @@ add_task(async function searchWithRequestOnUnload() { await teardown(monitor); }); +// Asserts that the content is scrolled to show the correct matched content +// on the line when a match is selected from the network search list. +add_task(async function testContentIsScrolledWhenMatchIsSelected() { + const httpServer = createTestHTTPServer(); + httpServer.registerPathHandler(`/`, function (request, response) { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.write(`<html><meta charset=utf8> + <script type="text/javascript" src="/script.js"></script> + <h1>Test matches in scrolled content</h1> + </html>`); + }); + + // The "data" path takes a size query parameter and will return a body of the + // requested size. + httpServer.registerPathHandler("/script.js", function (request, response) { + response.setHeader("Content-Type", "text/javascript"); + response.setStatusLine(request.httpVersion, 200, "OK"); + response.write( + `${Array.from({ length: 40 }, (_, i) => `// line ${++i}x`).join("\n")}` + ); + }); + + const TEST_URI = `http://localhost:${httpServer.identity.primaryPort}/`; + + const { tab, monitor } = await initNetMonitor(TEST_URI, { + requestCount: 1, + }); + info("Starting test... "); + const { document, store, windowRequire } = monitor.panelWin; + + // Action should be processed synchronously in tests. + const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); + store.dispatch(Actions.batchEnable(false)); + + // reload tab, expect the html page and the script request + const waitForEvents = waitForNetworkEvents(monitor, 2); + tab.linkedBrowser.reload(); + await waitForEvents; + + // Open the Search panel + await store.dispatch(Actions.openSearch()); + + // Fill search input with text and check displayed messages. + const waitForResult = waitFor(() => + document.querySelector(".search-panel-content .treeRow.resourceRow") + ); + typeInNetmonitor("line 3x", monitor); + EventUtils.synthesizeKey("KEY_Enter"); + await waitForResult; + + const result = document.querySelector( + ".search-panel-content .treeRow.resourceRow" + ); + // Click the matches to + const waitForMatches = waitFor( + () => + document.querySelectorAll(".search-panel-content .treeRow.resultRow") + ?.length == 1 + ); + clickElement(result, monitor); + await waitForMatches; + + const matches = document.querySelectorAll( + ".search-panel-content .treeRow.resultRow" + ); + // Click the first result match + const waitForResponsePanelContent = waitFor(() => + document.querySelector(`#response-panel .cm-content`) + ); + clickElement(matches[0], monitor); + await waitForResponsePanelContent; + + const editor = getCMEditor(monitor); + is( + editor.getSelectionCursor().from.line, + 3, + "The content on line 3 is highlighted" + ); + is( + editor.getText(editor.getSelectionCursor().from.line), + "// line 3x", + "The content on the line with cursor (line 3) is correct" + ); + + // Set the cursor to the bottom of the document + let onScrolled = waitForEditorScrolling(monitor); + await editor.setCursorAt(40, 0); + await onScrolled; + + is( + editor.getSelectionCursor().from.line, + 40, + "The content on line 40 is highlighted" + ); + is( + editor.getText(editor.getSelectionCursor().from.line), + "// line 40x", + "The content on the line with cursor (line 40) is correct" + ); + + // Click the first result match again + onScrolled = waitForEditorScrolling(monitor); + clickElement(matches[0], monitor); + await onScrolled; + + // The editor should scroll back up and the matched content on line 3 should be highlighted + + is( + editor.getSelectionCursor().from.line, + 3, + "The content on line 3 is highlighted" + ); + is( + editor.getText(editor.getSelectionCursor().from.line), + "// line 3x", + "The content on the line with cursor (line 3) is correct" + ); +}); + async function makeRequests(urls) { await content.wrappedJSObject.get(urls[0]); await content.wrappedJSObject.get(urls[1]); diff --git a/devtools/client/netmonitor/test/head.js b/devtools/client/netmonitor/test/head.js @@ -1193,6 +1193,16 @@ function getCodeMirrorValue(monitor) { } /** + * Waits for the currently triggered editor scroll to complete + * + * @param {*} monitor + * @returns {Promise} + */ +async function waitForEditorScrolling(monitor) { + return getCMEditor(monitor).once("cm-editor-scrolled"); +} + +/** * Helper function opening the options menu */ function openSettingsMenu(monitor) { diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand.js b/devtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand.js @@ -239,12 +239,6 @@ async function waitForPayloadReady(hud) { return hud.ui.once("network-request-payload-ready"); } -async function waitForSourceEditor(panel) { - return waitUntil(() => { - return !!panel.querySelector(".cm-editor"); - }); -} - async function waitForRequestUpdates(hud) { return hud.ui.once("network-messages-updated"); } diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand_before_updates.js b/devtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand_before_updates.js @@ -298,12 +298,6 @@ async function testSecurity(messageNode) { ); } -async function waitForSourceEditor(panel) { - return waitUntil(() => { - return !!panel.querySelector(".cm-content"); - }); -} - function expandXhrMessage(node) { info( "Click on XHR message and wait for the network detail panel to be displayed" diff --git a/devtools/client/webconsole/test/browser/head.js b/devtools/client/webconsole/test/browser/head.js @@ -270,6 +270,18 @@ async function waitForMessageByType(hud, text, typeSelector) { } /** + * Wait for the Source editor to be available. + * + * @param {Object} panel + * @returns + */ +async function waitForSourceEditor(panel) { + return waitUntil(() => { + return !!panel.querySelector(".cm-editor"); + }); +} + +/** * Execute an input expression. * * @param {Object} hud : The webconsole.