Skip to content

Commit 835e61e

Browse files
committed
fix: add tests
1 parent 0dde76b commit 835e61e

File tree

3 files changed

+198
-2
lines changed

3 files changed

+198
-2
lines changed

src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ function QuerySettingsForm({initialValues, onSubmit, onClose}: QuerySettingsForm
161161
<label htmlFor="resourcePool" className={b('field-title')}>
162162
{QUERY_SETTINGS_FIELD_SETTINGS.resourcePool.title}
163163
</label>
164-
<div className={b('control-wrapper')}>
164+
<div className={b('control-wrapper', {resourcePool: true})}>
165165
<Controller
166166
name="resourcePool"
167167
control={control}

tests/suites/tenant/queryEditor/models/SettingsDialog.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export class SettingsDialog {
2323
private timeoutLabel: Locator;
2424

2525
private queryModeSelect: Locator;
26+
private resourcePoolSelect: Locator;
2627
private transactionModeSelect: Locator;
2728
private statisticsModeSelect: Locator;
2829
private statisticsModeTooltip: Locator;
@@ -47,6 +48,9 @@ export class SettingsDialog {
4748
this.queryModeSelect = this.dialog.locator(
4849
'.ydb-query-settings-dialog__control-wrapper_queryMode',
4950
);
51+
this.resourcePoolSelect = this.dialog.locator(
52+
'.ydb-query-settings-dialog__control-wrapper_resourcePool',
53+
);
5054
this.transactionModeSelect = this.dialog.locator(
5155
'.ydb-query-settings-dialog__control-wrapper_transactionMode',
5256
);
@@ -66,6 +70,46 @@ export class SettingsDialog {
6670
await this.page.waitForTimeout(1000);
6771
}
6872

73+
async getResourcePoolOptions() {
74+
await this.resourcePoolSelect.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
75+
await this.resourcePoolSelect.click();
76+
await this.selectPopup.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
77+
78+
const items = this.selectPopup.locator('.ydb-query-settings-select__item-title');
79+
const count = await items.count();
80+
const options: string[] = [];
81+
82+
for (let index = 0; index < count; index += 1) {
83+
const text = await items.nth(index).textContent();
84+
if (text) {
85+
options.push(text.trim());
86+
}
87+
}
88+
89+
return options;
90+
}
91+
92+
async changeResourcePool(value: string) {
93+
await this.resourcePoolSelect.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
94+
await this.resourcePoolSelect.click();
95+
await this.selectPopup.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
96+
await this.page.locator(`.ydb-query-settings-select__item_type_${value}`).click();
97+
await this.page.waitForTimeout(1000);
98+
}
99+
100+
async getResourcePoolValue() {
101+
await this.resourcePoolSelect.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
102+
const selectedText = await this.resourcePoolSelect
103+
.locator('.g-select-control__option-text')
104+
.textContent();
105+
return selectedText?.trim() || '';
106+
}
107+
108+
async isResourcePoolDisabled() {
109+
await this.resourcePoolSelect.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
110+
return this.resourcePoolSelect.locator('.g-select-control_disabled').isVisible();
111+
}
112+
69113
async changeTransactionMode(level: (typeof TRANSACTION_MODES)[keyof typeof TRANSACTION_MODES]) {
70114
await this.transactionModeSelect.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
71115
await this.transactionModeSelect.click();

tests/suites/tenant/queryEditor/querySettings.test.ts

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,39 @@
11
import {expect, test} from '@playwright/test';
2+
import type {Page, Route} from '@playwright/test';
23

34
import {QUERY_MODES, TRANSACTION_MODES} from '../../../../src/utils/query';
4-
import {database} from '../../../utils/constants';
5+
import {backend, database} from '../../../utils/constants';
56
import {toggleExperiment} from '../../../utils/toggleExperiment';
67
import {TenantPage, VISIBILITY_TIMEOUT} from '../TenantPage';
78
import {longRunningQuery} from '../constants';
89

910
import {ButtonNames, QueryEditor} from './models/QueryEditor';
1011

12+
async function setupResourcePoolMock(page: Page, pools: string[] = ['default', 'olap']) {
13+
await page.route(`${backend}/viewer/json/query?*`, async (route: Route) => {
14+
const request = route.request();
15+
const postData = request.postData();
16+
17+
if (postData && postData.includes('.sys/resource_pools')) {
18+
await route.fulfill({
19+
status: 200,
20+
contentType: 'application/json',
21+
body: JSON.stringify({
22+
version: 8,
23+
result: [
24+
{
25+
rows: pools.map((name) => [name]),
26+
columns: [{name: 'Name', type: 'Utf8?'}],
27+
},
28+
],
29+
}),
30+
});
31+
} else {
32+
await route.continue();
33+
}
34+
});
35+
}
36+
1137
test.describe('Test Query Settings', async () => {
1238
const testQuery = 'SELECT 1, 2, 3, 4, 5;';
1339

@@ -252,4 +278,130 @@ test.describe('Test Query Settings', async () => {
252278
// Restore Query Streaming experiment
253279
await toggleExperiment(page, 'on', 'Query Streaming');
254280
});
281+
282+
test('Resource pool dropdown is populated from system view', async ({page}) => {
283+
await setupResourcePoolMock(page, ['default', 'olap']);
284+
285+
const queryEditor = new QueryEditor(page);
286+
await queryEditor.clickGearButton();
287+
288+
const options = await queryEditor.settingsDialog.getResourcePoolOptions();
289+
290+
expect(options).toContain('No pool override');
291+
expect(options).toContain('default');
292+
expect(options).toContain('olap');
293+
});
294+
295+
test('Resource pool selection is persisted between dialog opens', async ({page}) => {
296+
await setupResourcePoolMock(page, ['default', 'olap']);
297+
298+
const queryEditor = new QueryEditor(page);
299+
await queryEditor.clickGearButton();
300+
301+
await queryEditor.settingsDialog.changeResourcePool('olap');
302+
await queryEditor.settingsDialog.clickButton(ButtonNames.Save);
303+
await expect(queryEditor.settingsDialog.isHidden()).resolves.toBe(true);
304+
305+
await queryEditor.clickGearButton();
306+
const value = await queryEditor.settingsDialog.getResourcePoolValue();
307+
308+
expect(value).toBe('olap');
309+
});
310+
311+
test('Resource pool is disabled for PG query mode', async ({page}) => {
312+
await setupResourcePoolMock(page, ['default', 'olap']);
313+
314+
const queryEditor = new QueryEditor(page);
315+
await queryEditor.clickGearButton();
316+
317+
await queryEditor.settingsDialog.changeQueryMode(QUERY_MODES.pg);
318+
319+
await expect(queryEditor.settingsDialog.isResourcePoolDisabled()).resolves.toBe(true);
320+
});
321+
322+
test('Selected resource pool is sent in API requests and no override omits parameter', async ({
323+
page,
324+
}) => {
325+
const capturedBodies: Array<Record<string, unknown>> = [];
326+
327+
await page.route(`${backend}/viewer/json/query?*`, async (route: Route) => {
328+
const request = route.request();
329+
const postData = request.postData();
330+
331+
if (!postData) {
332+
await route.continue();
333+
return;
334+
}
335+
336+
if (postData.includes('.sys/resource_pools')) {
337+
await route.fulfill({
338+
status: 200,
339+
contentType: 'application/json',
340+
body: JSON.stringify({
341+
version: 8,
342+
result: [
343+
{
344+
rows: [['default'], ['olap']],
345+
columns: [{name: 'Name', type: 'Utf8?'}],
346+
},
347+
],
348+
}),
349+
});
350+
return;
351+
}
352+
353+
const body = JSON.parse(postData) as Record<string, unknown>;
354+
capturedBodies.push(body);
355+
356+
await route.fulfill({
357+
status: 200,
358+
contentType: 'application/json',
359+
body: JSON.stringify({
360+
version: 8,
361+
result: [
362+
{
363+
rows: [],
364+
columns: [],
365+
},
366+
],
367+
}),
368+
});
369+
});
370+
371+
const queryEditor = new QueryEditor(page);
372+
373+
// Select a concrete resource pool and run a query
374+
await queryEditor.clickGearButton();
375+
await queryEditor.settingsDialog.changeResourcePool('olap');
376+
await queryEditor.settingsDialog.clickButton(ButtonNames.Save);
377+
await queryEditor.setQuery('SELECT 1;');
378+
await queryEditor.clickRunButton();
379+
380+
await expect(async () => {
381+
const lastBody = capturedBodies[capturedBodies.length - 1] as {
382+
query?: string;
383+
resource_pool?: string;
384+
};
385+
386+
expect(lastBody.query).toContain('SELECT 1;');
387+
expect(lastBody.resource_pool).toBe('olap');
388+
}).toPass({timeout: VISIBILITY_TIMEOUT});
389+
390+
// Now switch to "No pool override" and ensure resource_pool is omitted
391+
await queryEditor.clickGearButton();
392+
await queryEditor.settingsDialog.changeResourcePool('No pool override');
393+
await queryEditor.settingsDialog.clickButton(ButtonNames.Save);
394+
await queryEditor.setQuery('SELECT 2;');
395+
await queryEditor.clickRunButton();
396+
397+
await expect(async () => {
398+
const lastBody = capturedBodies[capturedBodies.length - 1] as {
399+
query?: string;
400+
resource_pool?: string;
401+
};
402+
403+
expect(lastBody.query).toContain('SELECT 2;');
404+
expect(lastBody.resource_pool).toBeUndefined();
405+
}).toPass({timeout: VISIBILITY_TIMEOUT});
406+
});
255407
});

0 commit comments

Comments
 (0)