mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-23 20:55:41 +00:00
fix(devtools): network tab panel inner scroll (#8329)
* fix: ui overflow for the network tab * test(e2e): scroller behaviour for network tab
This commit is contained in:
@@ -317,6 +317,7 @@ const StyledWrapper = styled.div`
|
||||
height: 100% !important;
|
||||
max-height: 400px !important;
|
||||
padding: 0.5rem !important;
|
||||
overflow: auto !important;
|
||||
|
||||
.network-logs-pre {
|
||||
color: ${(props) => props.theme.console.messageColor} !important;
|
||||
|
||||
9
tests/devtools/network/fixtures/collection/bruno.json
Normal file
9
tests/devtools/network/fixtures/collection/bruno.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": "1",
|
||||
"name": "network-log-scroll",
|
||||
"type": "collection",
|
||||
"ignore": [
|
||||
"node_modules",
|
||||
".git"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
meta {
|
||||
name: network-log-scroll
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:8081/api/echo/headers
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
headers {
|
||||
X-Network-Log-1: value-1
|
||||
X-Network-Log-2: value-2
|
||||
X-Network-Log-3: value-3
|
||||
X-Network-Log-4: value-4
|
||||
X-Network-Log-5: value-5
|
||||
X-Network-Log-6: value-6
|
||||
X-Network-Log-7: value-7
|
||||
X-Network-Log-8: value-8
|
||||
X-Network-Log-9: value-9
|
||||
X-Network-Log-10: value-10
|
||||
X-Network-Log-11: value-11
|
||||
X-Network-Log-12: value-12
|
||||
X-Network-Log-13: value-13
|
||||
X-Network-Log-14: value-14
|
||||
X-Network-Log-15: value-15
|
||||
X-Network-Log-16: value-16
|
||||
X-Network-Log-17: value-17
|
||||
X-Network-Log-18: value-18
|
||||
X-Network-Log-19: value-19
|
||||
X-Network-Log-20: value-20
|
||||
X-Network-Log-21: value-21
|
||||
X-Network-Log-22: value-22
|
||||
X-Network-Log-23: value-23
|
||||
X-Network-Log-24: value-24
|
||||
X-Network-Log-25: value-25
|
||||
X-Network-Log-26: value-26
|
||||
X-Network-Log-27: value-27
|
||||
X-Network-Log-28: value-28
|
||||
X-Network-Log-29: value-29
|
||||
X-Network-Log-30: value-30
|
||||
X-Network-Log-31: value-31
|
||||
X-Network-Log-32: value-32
|
||||
X-Network-Log-33: value-33
|
||||
X-Network-Log-34: value-34
|
||||
X-Network-Log-35: value-35
|
||||
X-Network-Log-36: value-36
|
||||
X-Network-Log-37: value-37
|
||||
X-Network-Log-38: value-38
|
||||
X-Network-Log-39: value-39
|
||||
X-Network-Log-40: value-40
|
||||
X-Network-Log-41: value-41
|
||||
X-Network-Log-42: value-42
|
||||
X-Network-Log-43: value-43
|
||||
X-Network-Log-44: value-44
|
||||
X-Network-Log-45: value-45
|
||||
X-Network-Log-46: value-46
|
||||
X-Network-Log-47: value-47
|
||||
X-Network-Log-48: value-48
|
||||
X-Network-Log-49: value-49
|
||||
X-Network-Log-50: value-50
|
||||
X-Network-Log-51: value-51
|
||||
X-Network-Log-52: value-52
|
||||
X-Network-Log-53: value-53
|
||||
X-Network-Log-54: value-54
|
||||
X-Network-Log-55: value-55
|
||||
X-Network-Log-56: value-56
|
||||
X-Network-Log-57: value-57
|
||||
X-Network-Log-58: value-58
|
||||
X-Network-Log-59: value-59
|
||||
X-Network-Log-60: value-60
|
||||
X-Network-Log-61: value-61
|
||||
X-Network-Log-62: value-62
|
||||
X-Network-Log-63: value-63
|
||||
X-Network-Log-64: value-64
|
||||
X-Network-Log-65: value-65
|
||||
X-Network-Log-66: value-66
|
||||
X-Network-Log-67: value-67
|
||||
X-Network-Log-68: value-68
|
||||
X-Network-Log-69: value-69
|
||||
X-Network-Log-70: value-70
|
||||
X-Network-Log-71: value-71
|
||||
X-Network-Log-72: value-72
|
||||
X-Network-Log-73: value-73
|
||||
X-Network-Log-74: value-74
|
||||
X-Network-Log-75: value-75
|
||||
X-Network-Log-76: value-76
|
||||
X-Network-Log-77: value-77
|
||||
X-Network-Log-78: value-78
|
||||
X-Network-Log-79: value-79
|
||||
X-Network-Log-80: value-80
|
||||
X-Network-Log-81: value-81
|
||||
X-Network-Log-82: value-82
|
||||
X-Network-Log-83: value-83
|
||||
X-Network-Log-84: value-84
|
||||
X-Network-Log-85: value-85
|
||||
X-Network-Log-86: value-86
|
||||
X-Network-Log-87: value-87
|
||||
X-Network-Log-88: value-88
|
||||
X-Network-Log-89: value-89
|
||||
X-Network-Log-90: value-90
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"collections": [
|
||||
{
|
||||
"path": "{{collectionPath}}",
|
||||
"securityConfig": {
|
||||
"jsSandboxMode": "safe"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
12
tests/devtools/network/init-user-data/preferences.json
Normal file
12
tests/devtools/network/init-user-data/preferences.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"maximized": false,
|
||||
"lastOpenedCollections": [
|
||||
"{{collectionPath}}"
|
||||
],
|
||||
"preferences": {
|
||||
"onboarding": {
|
||||
"hasLaunchedBefore": true,
|
||||
"hasSeenWelcomeModal": true
|
||||
}
|
||||
}
|
||||
}
|
||||
101
tests/devtools/network/network-log-details-scroll.spec.ts
Normal file
101
tests/devtools/network/network-log-details-scroll.spec.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { test, expect, type Locator } from '../../../playwright';
|
||||
import { openCollection, openRequest, sendRequest } from '../../utils/page';
|
||||
|
||||
const COLLECTION_NAME = 'network-log-scroll';
|
||||
const REQUEST_NAME = 'network-log-scroll';
|
||||
|
||||
const isEntryVisibleInScroller = async (scroller: Locator, entry: Locator) => {
|
||||
const entryHandle = await entry.elementHandle();
|
||||
if (!entryHandle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return scroller.evaluate((container, entryEl) => {
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const entryRect = entryEl.getBoundingClientRect();
|
||||
|
||||
return (
|
||||
entryRect.height > 0
|
||||
&& entryRect.top >= containerRect.top - 1
|
||||
&& entryRect.bottom <= containerRect.bottom + 1
|
||||
);
|
||||
}, entryHandle);
|
||||
};
|
||||
|
||||
test.describe('DevTools Network Log Details Scroll', () => {
|
||||
test('last network log lines are visible and scrollable in request details panel', async ({ pageWithUserData: page }) => {
|
||||
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
|
||||
|
||||
await test.step('Open fixture request and send it', async () => {
|
||||
await openCollection(page, COLLECTION_NAME);
|
||||
await openRequest(page, COLLECTION_NAME, REQUEST_NAME);
|
||||
await sendRequest(page, 200);
|
||||
});
|
||||
|
||||
await test.step('Open DevTools Network tab and select the request', async () => {
|
||||
await page.locator('button[data-trigger="dev-tools"]').click();
|
||||
await expect(page.locator('.console-header')).toBeVisible();
|
||||
|
||||
const networkTab = page.locator('.console-tab').filter({ hasText: 'Network' });
|
||||
await expect(networkTab).toBeVisible();
|
||||
await networkTab.click();
|
||||
await expect(networkTab).toHaveClass(/active/);
|
||||
|
||||
const requestRow = page.getByTestId('network-request-row').first();
|
||||
await expect(requestRow).toBeVisible();
|
||||
await requestRow.click();
|
||||
});
|
||||
|
||||
const panel = page.locator('.details-panel-wrapper');
|
||||
const outerScroller = panel.locator('.panel-content');
|
||||
const innerScroller = panel.locator('.network-logs-wrapper .network-logs-container');
|
||||
const lastEntry = innerScroller.locator('.network-logs-entry').last();
|
||||
|
||||
await test.step('Open Network sub-tab in request details panel', async () => {
|
||||
await expect(panel.getByText('Request Details')).toBeVisible();
|
||||
const networkSubTab = panel.locator('.tab-button').filter({ hasText: 'Network' });
|
||||
await expect(networkSubTab).toBeVisible();
|
||||
await networkSubTab.click();
|
||||
await expect(networkSubTab).toHaveClass(/active/);
|
||||
await expect(innerScroller).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('Verify nested inner scroller overflows', async () => {
|
||||
const innerOverflows = await innerScroller.evaluate((el) => el.scrollHeight > el.clientHeight);
|
||||
expect(innerOverflows).toBe(true);
|
||||
await expect(lastEntry).toContainText(/Request completed in/);
|
||||
});
|
||||
|
||||
await test.step('Outer panel scroll alone does not reveal the last log line', async () => {
|
||||
const initialOuterScrollTop = await outerScroller.evaluate((el) => el.scrollTop);
|
||||
expect(initialOuterScrollTop).toBe(0);
|
||||
|
||||
await outerScroller.evaluate((el) => {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
});
|
||||
|
||||
await expect.poll(() => isEntryVisibleInScroller(innerScroller, lastEntry)).toBe(false);
|
||||
|
||||
await outerScroller.evaluate((el) => {
|
||||
el.scrollTop = 0;
|
||||
});
|
||||
});
|
||||
|
||||
await test.step('Scroll nested inner container and verify last log line is visible in viewport', async () => {
|
||||
await expect(async () => {
|
||||
await innerScroller.evaluate((el) => {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
});
|
||||
|
||||
const scrollTop = await innerScroller.evaluate((el) => el.scrollTop);
|
||||
expect(scrollTop).toBeGreaterThan(0);
|
||||
|
||||
await expect(lastEntry).toBeVisible({ timeout: 1000 });
|
||||
expect(await isEntryVisibleInScroller(innerScroller, lastEntry)).toBe(true);
|
||||
}).toPass({ timeout: 10000 });
|
||||
|
||||
const outerScrollTop = await outerScroller.evaluate((el) => el.scrollTop);
|
||||
expect(outerScrollTop).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user