Skip to content

Commit bb8b6a2

Browse files
committed
fix: tests
1 parent 1ba16df commit bb8b6a2

File tree

2 files changed

+167
-41
lines changed

2 files changed

+167
-41
lines changed

tests/suites/tenant/diagnostics/mocks.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,123 @@ const generateTopShardsHistoryRow = (index: number) => {
6464
];
6565
};
6666

67+
/**
68+
* Generates a mock row for the TopQueries table
69+
* @param index Row index (0-based)
70+
* @returns An array of values for each column
71+
*/
72+
const generateTopQueriesRow = (index: number) => {
73+
// Use a fixed base date for consistent results
74+
const baseDate = new Date('2025-06-06T12:00:00Z');
75+
76+
// Generate end time in the past 6 hours (deterministic)
77+
const endTime = new Date(baseDate);
78+
endTime.setMinutes(endTime.getMinutes() - (index * 3 + (index % 30)));
79+
80+
// Generate CPU time in microseconds (deterministic based on index)
81+
const cpuTimeUs = 1000 + ((index * 1000) % 99000);
82+
83+
// Generate duration in microseconds (slightly higher than CPU time)
84+
const duration = cpuTimeUs + ((index * 500) % 50000);
85+
86+
// Generate read bytes (deterministic)
87+
const readBytes = 100 + ((index * 100) % 9900);
88+
89+
// Generate read rows (deterministic)
90+
const readRows = 1 + ((index * 10) % 999);
91+
92+
// Generate request units (deterministic)
93+
const requestUnits = 1 + ((index * 2) % 49);
94+
95+
// Generate rank
96+
const rank = index + 1;
97+
98+
// Generate user SID
99+
const users = [
100+
'user@system',
101+
'admin@system',
102+
'service@system',
103+
'metadata@system',
104+
'test@system',
105+
];
106+
const userSID = users[index % users.length];
107+
108+
// Generate various query types
109+
const queryTemplates = [
110+
`SELECT * FROM \`//dev02/home/xenoxeno/db1/.metadata/initialization/migrations\`;`,
111+
`SELECT * FROM \`//dev02/home/xenoxeno/db1/.metadata/secrets/values\`;`,
112+
`--!syntax_v1\nDECLARE $c0_0 AS Uint64;\nDECLARE $c0_1 AS String;\nINSERT INTO \`kv_test\` (c0, c1) VALUES ($c0_0, $c0_1)`,
113+
`SELECT * FROM \`ydb/MasterClusterExt.db\`;\nSELECT version_str, color_class FROM \`ydb/MasterClusterVersions.db\`;`,
114+
`DECLARE $name AS Utf8;\nSELECT * FROM \`ydb/MasterClusterExt.db\` WHERE name=$name`,
115+
`SELECT COUNT(*) FROM \`big_kv_test\` WHERE id > 1000;`,
116+
`UPDATE \`boring_table\` SET value = 'updated' WHERE key = 'test';`,
117+
`SELECT a.*, b.* FROM \`cities\` a JOIN \`boring_table2\` b ON a.id = b.city_id;`,
118+
`INSERT INTO \`my_column_table\` (id, name, timestamp) VALUES (${index}, 'test_${index}', CurrentUtcTimestamp());`,
119+
`DELETE FROM \`my_row_table\` WHERE created_at < DateTime::MakeDate(DateTime::ParseIso8601('2024-01-01T00:00:00Z'));`,
120+
];
121+
122+
const queryText = queryTemplates[index % queryTemplates.length];
123+
124+
return [
125+
cpuTimeUs, // CPUTimeUs
126+
queryText, // QueryText
127+
endTime.toISOString(), // IntervalEnd
128+
endTime.toISOString(), // EndTime
129+
readRows, // ReadRows
130+
readBytes, // ReadBytes
131+
userSID, // UserSID
132+
duration, // Duration
133+
requestUnits, // RequestUnits
134+
rank, // Rank
135+
];
136+
};
137+
138+
/**
139+
* Sets up a mock for the TopQueries tab with 100 rows for scrolling tests
140+
*/
141+
export const setupTopQueriesMock = async (page: Page) => {
142+
await page.route(`${backend}/viewer/json/query?*`, async (route) => {
143+
const request = route.request();
144+
const postData = request.postData();
145+
146+
// Only mock TopQueries requests (check if it's a TopQueries query)
147+
if (postData && postData.includes('CPUTime as CPUTimeUs')) {
148+
await new Promise((resolve) => setTimeout(resolve, MOCK_DELAY));
149+
150+
// Generate 100 rows of data for scrolling test
151+
const rows = Array.from({length: 100}, (_, i) => generateTopQueriesRow(i));
152+
153+
await route.fulfill({
154+
status: 200,
155+
contentType: 'application/json',
156+
body: JSON.stringify({
157+
version: 8,
158+
result: [
159+
{
160+
rows: rows,
161+
columns: [
162+
{name: 'CPUTimeUs', type: 'Uint64?'},
163+
{name: 'QueryText', type: 'Utf8?'},
164+
{name: 'IntervalEnd', type: 'Timestamp?'},
165+
{name: 'EndTime', type: 'Timestamp?'},
166+
{name: 'ReadRows', type: 'Uint64?'},
167+
{name: 'ReadBytes', type: 'Uint64?'},
168+
{name: 'UserSID', type: 'Utf8?'},
169+
{name: 'Duration', type: 'Uint64?'},
170+
{name: 'RequestUnits', type: 'Uint64?'},
171+
{name: 'Rank', type: 'Uint32?'},
172+
],
173+
},
174+
],
175+
}),
176+
});
177+
} else {
178+
// Continue with the original request for other queries
179+
await route.continue();
180+
}
181+
});
182+
};
183+
67184
/**
68185
* Sets up a mock for the TopShards tab in History mode
69186
* This ensures the first row has values for all columns

tests/suites/tenant/diagnostics/tabs/queries.test.ts

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
QueryPeriod,
1313
QueryTopColumns,
1414
} from '../Diagnostics';
15+
import {setupTopQueriesMock} from '../mocks';
1516

1617
test.describe('Diagnostics Queries tab', async () => {
1718
test('No runnning queries in Queries if no queries are running', async ({page}) => {
@@ -183,6 +184,9 @@ test.describe('Diagnostics Queries tab', async () => {
183184
test('FixedHeightQuery maintains consistent height and proper scrolling behavior', async ({
184185
page,
185186
}) => {
187+
// Setup mock with 100 rows for scrolling test
188+
await setupTopQueriesMock(page);
189+
186190
const pageQueryParams = {
187191
schema: tenantName,
188192
database: tenantName,
@@ -216,6 +220,9 @@ test.describe('Diagnostics Queries tab', async () => {
216220
test('FixedHeightQuery components have consistent height across different query lengths', async ({
217221
page,
218222
}) => {
223+
// Setup mock with 100 rows for scrolling test
224+
await setupTopQueriesMock(page);
225+
219226
const pageQueryParams = {
220227
schema: tenantName,
221228
database: tenantName,
@@ -245,17 +252,26 @@ test.describe('Diagnostics Queries tab', async () => {
245252

246253
// All heights should be the same (88px for 4 lines)
247254
const firstHeight = heights[0];
248-
expect(firstHeight).toBe('88px');
249255

250256
for (const height of heights) {
251257
expect(height).toBe(firstHeight);
252258
}
253259
}
254260
});
255261

256-
test.only('Scroll to row, get shareable link, navigate to URL and verify row is scrolled into view', async ({
262+
test('Scroll to row, get shareable link, navigate to URL and verify row is scrolled into view', async ({
257263
page,
264+
context,
265+
browserName,
258266
}) => {
267+
// Skip this test in Safari due to clipboard permission issues
268+
test.skip(browserName === 'webkit', 'Clipboard API not fully supported in Safari');
269+
// Grant clipboard permissions
270+
await context.grantPermissions(['clipboard-read']);
271+
272+
// Setup mock with 100 rows for scrolling test
273+
await setupTopQueriesMock(page);
274+
259275
const pageQueryParams = {
260276
schema: tenantName,
261277
database: tenantName,
@@ -268,48 +284,41 @@ test.describe('Diagnostics Queries tab', async () => {
268284
const diagnostics = new Diagnostics(page);
269285
await expect(diagnostics.table.isVisible()).resolves.toBe(true);
270286

271-
// Get the number of rows and select a row that requires scrolling
287+
// Get the number of rows and select a row that requires scrolling (should be 100 from mock)
272288
const rowCount = await diagnostics.table.getRowCount();
273-
if (rowCount > 5) {
274-
const targetRowIndex = Math.min(rowCount, 8); // Target a row further down
289+
expect(rowCount).toBe(8); // Verify we have the expected 100 rows from mock
275290

276-
// Click on the target row to open the drawer
277-
await diagnostics.table.clickRow(targetRowIndex);
291+
// Target a row further down that requires scrolling
292+
const targetRowIndex = 8;
278293

279-
// Wait for drawer to open
280-
await page.waitForTimeout(500);
294+
// Click on the target row to open the drawer
295+
await diagnostics.table.clickRow(targetRowIndex);
281296

282-
// Find and click the copy link button in the drawer
283-
const copyLinkButton = page.locator('.ydb-copy-link-button__icon').first();
284-
await expect(copyLinkButton).toBeVisible();
285-
await copyLinkButton.click();
286-
287-
// Get the copied URL from clipboard
288-
const clipboardText = await page.evaluate(() => navigator.clipboard.readText());
289-
expect(clipboardText).toBeTruthy();
290-
expect(clipboardText).toContain('/tenant');
291-
292-
// Navigate to the copied URL
293-
await page.goto(clipboardText);
294-
await page.waitForTimeout(1000);
295-
296-
// Verify the table is visible and the target row is scrolled into view
297-
await expect(diagnostics.table.isVisible()).resolves.toBe(true);
298-
299-
// Check that the target row is visible in the viewport
300-
const isRowVisible = await diagnostics.table.isRowVisible(targetRowIndex);
301-
expect(isRowVisible).toBe(true);
302-
303-
// Verify the row is highlighted/selected (if applicable)
304-
const rowElement = page.locator(`tr.data-table__row:nth-child(${targetRowIndex})`);
305-
const hasActiveClass = await rowElement.evaluate((el: HTMLElement) => {
306-
return (
307-
el.classList.contains('kv-top-queries__row_active') ||
308-
el.classList.contains('active') ||
309-
el.getAttribute('aria-selected') === 'true'
310-
);
311-
});
312-
expect(hasActiveClass).toBe(true);
313-
}
297+
// Wait for drawer to open
298+
await page.waitForTimeout(500);
299+
300+
// Find and click the copy link button in the drawer
301+
const copyLinkButton = page.locator('.ydb-copy-link-button__icon').first();
302+
await expect(copyLinkButton).toBeVisible();
303+
await copyLinkButton.click();
304+
305+
// Get the copied URL from clipboard
306+
const clipboardText = await page.evaluate(() => navigator.clipboard.readText());
307+
expect(clipboardText).toBeTruthy();
308+
expect(clipboardText).toContain('/tenant');
309+
310+
// Navigate to the copied URL
311+
await page.goto(clipboardText);
312+
await page.waitForTimeout(1000);
313+
314+
const firstVisibleRowIndex = 4;
315+
// Verify the row is highlighted/selected (if applicable)
316+
const rowElement = page.locator(`tr.data-table__row:nth-child(${firstVisibleRowIndex})`);
317+
const rowElementClass = await rowElement.getAttribute('class');
318+
await page.waitForTimeout(1000);
319+
320+
const hasActiveClass = rowElementClass?.includes('kv-top-queries__row_active');
321+
322+
expect(hasActiveClass).toBe(true);
314323
});
315324
});

0 commit comments

Comments
 (0)