diff --git a/src/store/reducers/query/streamingReducers.ts b/src/store/reducers/query/streamingReducers.ts index d807d01f04..740b44eed7 100644 --- a/src/store/reducers/query/streamingReducers.ts +++ b/src/store/reducers/query/streamingReducers.ts @@ -53,6 +53,13 @@ export const setStreamQueryResponse = ( state.result.data.preparedPlan = Object.keys(planData).length > 0 ? planData : undefined; state.result.data.simplifiedPlan = simplifiedPlan; state.result.data.plan = chunk.plan; + } + + if ('stats' in chunk) { + if (!state.result.data) { + state.result.data = prepareQueryData(null); + } + state.result.data.stats = chunk.stats; } diff --git a/tests/suites/tenant/queryEditor/models/QueryEditor.ts b/tests/suites/tenant/queryEditor/models/QueryEditor.ts index 5794c05e33..964340d6ab 100644 --- a/tests/suites/tenant/queryEditor/models/QueryEditor.ts +++ b/tests/suites/tenant/queryEditor/models/QueryEditor.ts @@ -349,4 +349,29 @@ export class QueryEditor { throw new Error(`Status did not change to ${expectedStatus} within ${timeout}ms`); } + + async getStatsTabContent() { + // First navigate to Stats tab + await this.paneWrapper.selectTab(ResultTabNames.Stats); + + // Get the stats content area + const statsContent = this.selector.locator('.ydb-query-result__result'); + await statsContent.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT}); + + return statsContent.innerText(); + } + + async hasStatsJsonViewer() { + // First navigate to Stats tab + await this.paneWrapper.selectTab(ResultTabNames.Stats); + + // Check for JSON viewer element + const jsonViewer = this.selector.locator('.ydb-json-viewer'); + try { + await jsonViewer.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT}); + return true; + } catch { + return false; + } + } } diff --git a/tests/suites/tenant/queryEditor/queryEditor.test.ts b/tests/suites/tenant/queryEditor/queryEditor.test.ts index 61418d15eb..de6d77dca2 100644 --- a/tests/suites/tenant/queryEditor/queryEditor.test.ts +++ b/tests/suites/tenant/queryEditor/queryEditor.test.ts @@ -11,6 +11,7 @@ import { longRunningStreamQuery, longTableSelect, longerRunningStreamQuery, + simpleQuery, } from '../constants'; import { @@ -407,4 +408,42 @@ test.describe('Test Query Editor', async () => { // Verify clipboard contains the query result expect(clipboardContent).toContain('42'); }); + + test.describe('Statistics Modes Tests', async () => { + test('Stats tab shows no stats message when STATISTICS_MODES.none', async ({page}) => { + const queryEditor = new QueryEditor(page); + + // Set query and configure statistics mode to none + await queryEditor.setQuery(simpleQuery); + await queryEditor.clickGearButton(); + await queryEditor.settingsDialog.changeStatsLevel(STATISTICS_MODES.none); + await queryEditor.settingsDialog.clickButton(ButtonNames.Save); + + // Execute query + await queryEditor.clickRunButton(); + await expect(queryEditor.waitForStatus('Completed')).resolves.toBe(true); + + // Check Stats tab content + const statsContent = await queryEditor.getStatsTabContent(); + expect(statsContent).toContain('There is no Stats for the request'); + }); + + test('Stats tab shows JSON viewer when STATISTICS_MODES.basic', async ({page}) => { + const queryEditor = new QueryEditor(page); + + // Set query and configure statistics mode to basic + await queryEditor.setQuery(simpleQuery); + await queryEditor.clickGearButton(); + await queryEditor.settingsDialog.changeStatsLevel(STATISTICS_MODES.basic); + await queryEditor.settingsDialog.clickButton(ButtonNames.Save); + + // Execute query + await queryEditor.clickRunButton(); + await expect(queryEditor.waitForStatus('Completed')).resolves.toBe(true); + + // Check that Stats tab contains JSON viewer + const hasJsonViewer = await queryEditor.hasStatsJsonViewer(); + expect(hasJsonViewer).toBe(true); + }); + }); });