From 139d71a8f8a739b0062be0e5a95a90e050285661 Mon Sep 17 00:00:00 2001 From: Pooja Date: Wed, 8 Jul 2026 19:12:12 +0530 Subject: [PATCH] fix(ws): preserve message editor scroll when selecting another message (#8536) --- .../WsBody/SingleWSMessage/index.js | 1 - .../fixtures/collection/ws-two-long-msgs.bru | 637 ++++++++++++++++++ .../websockets/message-editor-scroll.spec.ts | 31 + 3 files changed, 668 insertions(+), 1 deletion(-) create mode 100644 tests/websockets/fixtures/collection/ws-two-long-msgs.bru diff --git a/packages/bruno-app/src/components/RequestPane/WsBody/SingleWSMessage/index.js b/packages/bruno-app/src/components/RequestPane/WsBody/SingleWSMessage/index.js index 00ce48e11..f424e5b00 100644 --- a/packages/bruno-app/src/components/RequestPane/WsBody/SingleWSMessage/index.js +++ b/packages/bruno-app/src/components/RequestPane/WsBody/SingleWSMessage/index.js @@ -270,7 +270,6 @@ export const SingleWSMessage = ({ onSave={onSave} mode={codemirrorMode[displayMode] ?? 'text/plain'} enableVariableHighlighting={true} - readOnly={isSelected ? false : 'nocursor'} /> )} diff --git a/tests/websockets/fixtures/collection/ws-two-long-msgs.bru b/tests/websockets/fixtures/collection/ws-two-long-msgs.bru new file mode 100644 index 000000000..a12d5684f --- /dev/null +++ b/tests/websockets/fixtures/collection/ws-two-long-msgs.bru @@ -0,0 +1,637 @@ +meta { + name: ws-two-long-msgs + type: ws + seq: 6 +} + +ws { + url: ws://localhost:8081/ws/echo + body: ws + auth: inherit +} + +body:ws { + name: message 1 + type: json + content: ''' + { + "type": "bulk", + "count": 60, + "items": [ + { + "id": 0, + "name": "item-0", + "active": true + }, + { + "id": 1, + "name": "item-1", + "active": false + }, + { + "id": 2, + "name": "item-2", + "active": true + }, + { + "id": 3, + "name": "item-3", + "active": false + }, + { + "id": 4, + "name": "item-4", + "active": true + }, + { + "id": 5, + "name": "item-5", + "active": false + }, + { + "id": 6, + "name": "item-6", + "active": true + }, + { + "id": 7, + "name": "item-7", + "active": false + }, + { + "id": 8, + "name": "item-8", + "active": true + }, + { + "id": 9, + "name": "item-9", + "active": false + }, + { + "id": 10, + "name": "item-10", + "active": true + }, + { + "id": 11, + "name": "item-11", + "active": false + }, + { + "id": 12, + "name": "item-12", + "active": true + }, + { + "id": 13, + "name": "item-13", + "active": false + }, + { + "id": 14, + "name": "item-14", + "active": true + }, + { + "id": 15, + "name": "item-15", + "active": false + }, + { + "id": 16, + "name": "item-16", + "active": true + }, + { + "id": 17, + "name": "item-17", + "active": false + }, + { + "id": 18, + "name": "item-18", + "active": true + }, + { + "id": 19, + "name": "item-19", + "active": false + }, + { + "id": 20, + "name": "item-20", + "active": true + }, + { + "id": 21, + "name": "item-21", + "active": false + }, + { + "id": 22, + "name": "item-22", + "active": true + }, + { + "id": 23, + "name": "item-23", + "active": false + }, + { + "id": 24, + "name": "item-24", + "active": true + }, + { + "id": 25, + "name": "item-25", + "active": false + }, + { + "id": 26, + "name": "item-26", + "active": true + }, + { + "id": 27, + "name": "item-27", + "active": false + }, + { + "id": 28, + "name": "item-28", + "active": true + }, + { + "id": 29, + "name": "item-29", + "active": false + }, + { + "id": 30, + "name": "item-30", + "active": true + }, + { + "id": 31, + "name": "item-31", + "active": false + }, + { + "id": 32, + "name": "item-32", + "active": true + }, + { + "id": 33, + "name": "item-33", + "active": false + }, + { + "id": 34, + "name": "item-34", + "active": true + }, + { + "id": 35, + "name": "item-35", + "active": false + }, + { + "id": 36, + "name": "item-36", + "active": true + }, + { + "id": 37, + "name": "item-37", + "active": false + }, + { + "id": 38, + "name": "item-38", + "active": true + }, + { + "id": 39, + "name": "item-39", + "active": false + }, + { + "id": 40, + "name": "item-40", + "active": true + }, + { + "id": 41, + "name": "item-41", + "active": false + }, + { + "id": 42, + "name": "item-42", + "active": true + }, + { + "id": 43, + "name": "item-43", + "active": false + }, + { + "id": 44, + "name": "item-44", + "active": true + }, + { + "id": 45, + "name": "item-45", + "active": false + }, + { + "id": 46, + "name": "item-46", + "active": true + }, + { + "id": 47, + "name": "item-47", + "active": false + }, + { + "id": 48, + "name": "item-48", + "active": true + }, + { + "id": 49, + "name": "item-49", + "active": false + }, + { + "id": 50, + "name": "item-50", + "active": true + }, + { + "id": 51, + "name": "item-51", + "active": false + }, + { + "id": 52, + "name": "item-52", + "active": true + }, + { + "id": 53, + "name": "item-53", + "active": false + }, + { + "id": 54, + "name": "item-54", + "active": true + }, + { + "id": 55, + "name": "item-55", + "active": false + }, + { + "id": 56, + "name": "item-56", + "active": true + }, + { + "id": 57, + "name": "item-57", + "active": false + }, + { + "id": 58, + "name": "item-58", + "active": true + }, + { + "id": 59, + "name": "item-59", + "active": false + } + ] + } + ''' +} + +body:ws { + name: message 2 + type: json + content: ''' + { + "type": "bulk", + "count": 60, + "items": [ + { + "id": 0, + "name": "item-0", + "active": true + }, + { + "id": 1, + "name": "item-1", + "active": false + }, + { + "id": 2, + "name": "item-2", + "active": true + }, + { + "id": 3, + "name": "item-3", + "active": false + }, + { + "id": 4, + "name": "item-4", + "active": true + }, + { + "id": 5, + "name": "item-5", + "active": false + }, + { + "id": 6, + "name": "item-6", + "active": true + }, + { + "id": 7, + "name": "item-7", + "active": false + }, + { + "id": 8, + "name": "item-8", + "active": true + }, + { + "id": 9, + "name": "item-9", + "active": false + }, + { + "id": 10, + "name": "item-10", + "active": true + }, + { + "id": 11, + "name": "item-11", + "active": false + }, + { + "id": 12, + "name": "item-12", + "active": true + }, + { + "id": 13, + "name": "item-13", + "active": false + }, + { + "id": 14, + "name": "item-14", + "active": true + }, + { + "id": 15, + "name": "item-15", + "active": false + }, + { + "id": 16, + "name": "item-16", + "active": true + }, + { + "id": 17, + "name": "item-17", + "active": false + }, + { + "id": 18, + "name": "item-18", + "active": true + }, + { + "id": 19, + "name": "item-19", + "active": false + }, + { + "id": 20, + "name": "item-20", + "active": true + }, + { + "id": 21, + "name": "item-21", + "active": false + }, + { + "id": 22, + "name": "item-22", + "active": true + }, + { + "id": 23, + "name": "item-23", + "active": false + }, + { + "id": 24, + "name": "item-24", + "active": true + }, + { + "id": 25, + "name": "item-25", + "active": false + }, + { + "id": 26, + "name": "item-26", + "active": true + }, + { + "id": 27, + "name": "item-27", + "active": false + }, + { + "id": 28, + "name": "item-28", + "active": true + }, + { + "id": 29, + "name": "item-29", + "active": false + }, + { + "id": 30, + "name": "item-30", + "active": true + }, + { + "id": 31, + "name": "item-31", + "active": false + }, + { + "id": 32, + "name": "item-32", + "active": true + }, + { + "id": 33, + "name": "item-33", + "active": false + }, + { + "id": 34, + "name": "item-34", + "active": true + }, + { + "id": 35, + "name": "item-35", + "active": false + }, + { + "id": 36, + "name": "item-36", + "active": true + }, + { + "id": 37, + "name": "item-37", + "active": false + }, + { + "id": 38, + "name": "item-38", + "active": true + }, + { + "id": 39, + "name": "item-39", + "active": false + }, + { + "id": 40, + "name": "item-40", + "active": true + }, + { + "id": 41, + "name": "item-41", + "active": false + }, + { + "id": 42, + "name": "item-42", + "active": true + }, + { + "id": 43, + "name": "item-43", + "active": false + }, + { + "id": 44, + "name": "item-44", + "active": true + }, + { + "id": 45, + "name": "item-45", + "active": false + }, + { + "id": 46, + "name": "item-46", + "active": true + }, + { + "id": 47, + "name": "item-47", + "active": false + }, + { + "id": 48, + "name": "item-48", + "active": true + }, + { + "id": 49, + "name": "item-49", + "active": false + }, + { + "id": 50, + "name": "item-50", + "active": true + }, + { + "id": 51, + "name": "item-51", + "active": false + }, + { + "id": 52, + "name": "item-52", + "active": true + }, + { + "id": 53, + "name": "item-53", + "active": false + }, + { + "id": 54, + "name": "item-54", + "active": true + }, + { + "id": 55, + "name": "item-55", + "active": false + }, + { + "id": 56, + "name": "item-56", + "active": true + }, + { + "id": 57, + "name": "item-57", + "active": false + }, + { + "id": 58, + "name": "item-58", + "active": true + }, + { + "id": 59, + "name": "item-59", + "active": false + } + ] + } + ''' +} diff --git a/tests/websockets/message-editor-scroll.spec.ts b/tests/websockets/message-editor-scroll.spec.ts index 07de91a7f..67f771f1f 100644 --- a/tests/websockets/message-editor-scroll.spec.ts +++ b/tests/websockets/message-editor-scroll.spec.ts @@ -3,6 +3,7 @@ import { openRequest, closeAllCollections } from '../utils/page/actions'; const COLLECTION_NAME = 'collection'; const SCROLL_REQ = 'ws-scroll-top'; +const TWO_MSG_REQ = 'ws-two-long-msgs'; test.describe('websocket message editor scroll behaviour', () => { test.afterEach(async ({ pageWithUserData: page }) => { @@ -39,4 +40,34 @@ test.describe('websocket message editor scroll behaviour', () => { .poll(() => page.getByTestId('ws-message-body-0').locator('.CodeMirror-scroll').evaluate((el) => el.scrollTop)) .toBeGreaterThan(target - 60); }); + + test('selecting another message does not reset the deselected editor scroll to top', async ({ + pageWithUserData: page + }) => { + await openRequest(page, COLLECTION_NAME, TWO_MSG_REQ); + + // Message 1 is selected + expanded by default. + const firstBody = page.getByTestId('ws-message-body-0'); + await expect(firstBody).toBeVisible(); + + const firstScroll = firstBody.locator('.CodeMirror-scroll'); + await expect + .poll(() => firstScroll.evaluate((el) => el.scrollHeight - el.clientHeight)) + .toBeGreaterThan(0); + + // Scroll message 1's editor down into the body. + const target = await firstScroll.evaluate((el) => { + el.scrollTop = Math.floor((el.scrollHeight - el.clientHeight) * 0.6); + return el.scrollTop; + }); + expect(target).toBeGreaterThan(0); + + // Select message 2. + await page.getByTestId('ws-message-header-1').click({ position: { x: 8, y: 12 } }); + + // Message 1 stays expanded; its scroll must not have jumped to the top. + await expect + .poll(() => page.getByTestId('ws-message-body-0').locator('.CodeMirror-scroll').evaluate((el) => el.scrollTop)) + .toBeGreaterThan(target - 60); + }); });