Files
openobserve/tests/ui-testing/playwright-tests/Logs/logsQueryBuilder-editor.spec.js
T
4ca7a04864 test: model pricing E2E tests (13 journey flows) + Build tab timing fix (#12525)
## Summary

- **13 Playwright E2E journey tests** for the Model Pricing feature
(\`/settings/model_pricing\`), consolidating all P0–P2 scenarios into
journey-based flows
- New page object \`ModelPricingPage\` under \`pages/generalPages/\`
- API cleanup integrated into the centralized \`APICleanup\` class and
called from \`cleanup.spec.js\`
- CI matrix updated: \`ZO_MODEL_PRICING_ENABLED=true\` env var added;
\`model-pricing.spec.js\` added to the \`GeneralTests\` job
- **Bug fix**: \`waitForBuildTabLoaded\` now polls the Monaco editor for
non-empty content (Phase 3), fixing a timing race where Build tab SQL
tests read an empty query string on slower CI machines

## Test coverage

| Journey | Scenarios covered |
|---------|------------------|
| List, tabs & search | Controls, tab switching, search, built-in tab |
| Create & validation | All form validation cases + successful save |
| Edit, cancel & delete | Full lifecycle |
| Duplicate & clone | Org model duplicate + built-in clone |
| Bulk actions | Select, export JSON, bulk delete |
| Toggle | Disable/re-enable with correct visual state |
| Test match dialog | Empty state, no-result, clear, match result |
| Import | Valid JSON, correction flow, cancel |
| Editor features | Multi-tier, pricing template, pattern examples |
| Pricing drawer | Overflow link → drawer with all price keys |
| Empty state | CTA when org has no custom models |
| Cost applied | LLM span matched → cost stored correctly |
| No matching model | Unknown model name → zero cost stored |

## Bug fix: Build tab query editor timing

\`waitForBuildTabLoaded\`'s Phase 2 (chart-type-selected signal) fires
as soon as \`initializeFromQuery\` sets the chart type — before
\`makeAutoSQLQuery\` has run. On slower CI machines this left
\`queries[0].query\` empty when tests read the editor, causing the "SQL
ON + Auto mode" and "Auto → Custom" tests to receive \`""\` instead of
generated SQL.

Phase 3 polls the Monaco editor
(\`[data-test="logs-search-bar-query-editor"]\`) for non-empty content,
confirming \`onBuildQueryGenerated\` has been called and the query is
ready.

## Test plan

- [x] All 13 model pricing tests pass locally
- [x] \`logsQueryBuilder-editor.spec.js\` (23 tests) — all pass with
Phase 3 fix applied
- [x] Sentinel code audit passed (no blocking issues)
- [x] API cleanup added to \`cleanup.spec.js\` via
\`apiCleanup.cleanupModelPricingModels()\` — 404-safe for instances
where the feature is disabled

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-09 18:33:07 +00:00

583 lines
24 KiB
JavaScript

/**
* Logs Query Builder — Editor & Mode Tests
*
* Covers: builder tab improvement, edge cases, query mode toggle,
* SQL mode toggle in builder, search bar editor state,
* bare field select defaults, and field list button visibility.
*
* @tags @queryBuilder @logs @all
*/
const { test, expect, navigateToBase } = require('../utils/enhanced-baseFixtures.js');
const testLogger = require('../utils/test-logger.js');
const PageManager = require('../../pages/page-manager.js');
const {
ingestForQueryBuilderTest,
setupQueryAndSwitchToBuild,
initQueryBuilderTest,
} = require('../utils/queryBuilder-helpers.js');
// ============================================================================
// Test Suite: P1 - Builder Tab Improvement
// ============================================================================
test.describe("Logs Query Builder - Builder Tab Improvement", () => {
test.describe.configure({ mode: 'parallel' });
let pm;
test.beforeAll(async ({ request }) => {
await ingestForQueryBuilderTest(request);
});
test.beforeEach(async ({ page }, testInfo) => {
testLogger.testStart(testInfo.title, testInfo.file);
await navigateToBase(page);
pm = new PageManager(page);
await initQueryBuilderTest(page, pm);
testLogger.info('Builder Tab Improvement test setup completed');
});
test("SQL OFF + empty query → Build tab opens with default fields and bar chart", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing Case 1: SQL OFF + empty → default histogram/count');
await pm.logsPage.disableSqlModeIfNeeded();
await pm.logsPage.clickBuildToggle();
await pm.logsPage.waitForBuildTabLoaded();
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.verifyChartTypeSelected('bar');
const sqlModeOn = await pm.logsPage.isSqlModeOn();
expect(sqlModeOn).toBe(false);
testLogger.info('Case 1: SQL OFF + empty → default fields + bar - PASSED');
});
test("SQL OFF + WHERE clause → Build tab parses filter into builder", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing Case 2: SQL OFF + WHERE clause → filter parsed');
await pm.logsPage.disableSqlModeIfNeeded();
await page.waitForLoadState('domcontentloaded');
await pm.logsPage.setQueryEditorContent("code = '200'");
await pm.logsPage.clickBuildToggle();
await pm.logsPage.waitForBuildTabLoaded();
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.verifyChartTypeSelected('bar');
const sqlModeOn = await pm.logsPage.isSqlModeOn();
expect(sqlModeOn).toBe(false);
testLogger.info('Case 2: SQL OFF + WHERE → filter parsed + bar - PASSED');
});
test("SQL ON + empty query → Build tab opens with default fields and bar chart", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing Case 3: SQL ON + empty → default histogram/count');
await pm.logsPage.enableSqlModeIfNeeded();
await pm.logsPage.setQueryEditorContent('');
await pm.logsPage.clickBuildToggle();
await pm.logsPage.waitForBuildTabLoaded();
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.verifyChartTypeSelected('bar');
testLogger.info('Case 3: SQL ON + empty → default fields + bar - PASSED');
});
test("Query mode toggle: Auto → Custom shows SQL editor", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing query mode toggle: Auto → Custom');
const histogramQuery = 'SELECT histogram(_timestamp) as time, count(*) as count FROM "e2e_automate" GROUP BY time';
await setupQueryAndSwitchToBuild(pm, page, histogramQuery);
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.clickCustomQueryType();
await pm.logsPage.expectCustomModeActive();
testLogger.info('Query mode toggle: Auto → Custom - PASSED');
});
test("SQL ON + multiple aggregations → builder shows multiple Y-axis fields", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing multiple aggregations → multiple Y-axis');
const multiAggQuery = 'SELECT histogram(_timestamp) as "x_axis_1", count(_timestamp) as "y_axis_1", avg(code) as "y_axis_2" FROM "e2e_automate" GROUP BY x_axis_1 ORDER BY x_axis_1 ASC';
await setupQueryAndSwitchToBuild(pm, page, multiAggQuery);
await pm.logsPage.verifyChartTypeSelected('bar');
await pm.logsPage.expectXAxisLayoutVisible();
await pm.logsPage.expectYAxisLayoutVisible();
testLogger.info('Multiple aggregations → multiple Y-axis - PASSED');
});
test("SQL ON + breakdown field → builder shows breakdown section", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing breakdown field populated in builder');
const breakdownQuery = 'SELECT histogram(_timestamp) as "x_axis_1", count(_timestamp) as "y_axis_1", code as "z_axis_1" FROM "e2e_automate" GROUP BY x_axis_1, z_axis_1 ORDER BY x_axis_1 ASC';
await setupQueryAndSwitchToBuild(pm, page, breakdownQuery);
await pm.logsPage.verifyChartTypeSelected('bar');
await pm.logsPage.expectXAxisLayoutVisible();
await pm.logsPage.expectYAxisLayoutVisible();
await pm.logsPage.expectBreakdownLayoutVisible();
testLogger.info('Breakdown field populated - PASSED');
});
});
// ============================================================================
// Test Suite: P2 - Edge Cases
// ============================================================================
test.describe("Logs Query Builder - Edge Cases", () => {
test.describe.configure({ mode: 'parallel' });
let pm;
test.beforeAll(async ({ request }) => {
await ingestForQueryBuilderTest(request);
});
test.beforeEach(async ({ page }, testInfo) => {
testLogger.testStart(testInfo.title, testInfo.file);
await navigateToBase(page);
pm = new PageManager(page);
await initQueryBuilderTest(page, pm);
testLogger.info('Edge Cases test setup completed');
});
test("SQL ON mode preserved when toggling to Build tab", {
tag: ['@queryBuilder', '@edge', '@P2', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing SQL ON preserved on Build tab switch');
await pm.logsPage.enableSqlModeIfNeeded();
await pm.logsPage.clickBuildToggle();
await pm.logsPage.waitForBuildTabLoaded();
const preserved = await pm.logsPage.verifySqlModePreservedOnBuild(true);
expect(preserved).toBeTruthy();
testLogger.info('SQL ON preserved on Build tab - PASSED');
});
test("Window function query selects table chart on Build tab", {
tag: ['@queryBuilder', '@edge', '@P2', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing window function → table chart');
const windowQuery = 'SELECT *, ROW_NUMBER() OVER (ORDER BY _timestamp DESC) as rn FROM "e2e_automate" LIMIT 10';
await setupQueryAndSwitchToBuild(pm, page, windowQuery);
await pm.logsPage.expectDashboardPanelTableVisible();
await pm.logsPage.verifyChartTypeSelected('table');
testLogger.info('Window function → table chart - PASSED');
});
test("Case 7: SQL ON + >2 GROUP BY → table chart", {
tag: ['@queryBuilder', '@edge', '@P2', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing Case 7: >2 GROUP BY → table chart');
const multiGroupByQuery = 'SELECT code, method, level, count(*) as "y_axis_1" FROM "e2e_automate" GROUP BY code, method, level';
await setupQueryAndSwitchToBuild(pm, page, multiGroupByQuery);
await pm.logsPage.expectDashboardPanelTableVisible();
await pm.logsPage.verifyChartTypeSelected('table');
testLogger.info('Case 7: >2 GROUP BY → table chart - PASSED');
});
test("Case 9: SQL ON + multi-stream JOIN → builder mode, bar chart", {
tag: ['@queryBuilder', '@edge', '@P2', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing Case 9: multi-stream JOIN → builder mode → bar');
const joinQuery = 'SELECT a._timestamp, b._timestamp FROM "e2e_automate" a JOIN "e2e_automate" b ON a._timestamp = b._timestamp LIMIT 10';
await setupQueryAndSwitchToBuild(pm, page, joinQuery);
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.verifyChartTypeSelected('bar');
testLogger.info('Case 9: multi-stream JOIN → builder mode, bar chart - PASSED');
});
});
// ============================================================================
// Test Suite: Query Mode Toggle (Auto ↔ Custom) While in Builder
// ============================================================================
test.describe("Logs Query Builder - Query Mode Toggle", () => {
test.describe.configure({ mode: 'parallel' });
let pm;
test.beforeAll(async ({ request }) => {
await ingestForQueryBuilderTest(request);
});
test.beforeEach(async ({ page }, testInfo) => {
testLogger.testStart(testInfo.title, testInfo.file);
await navigateToBase(page);
pm = new PageManager(page);
await initQueryBuilderTest(page, pm);
testLogger.info('Query Mode Toggle test setup completed');
});
test("SQL ON: Auto → Custom shows full generated SQL in editor", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing Auto → Custom (SQL ON)');
const histogramQuery = 'SELECT histogram(_timestamp) as "x_axis_1", count(_timestamp) as "y_axis_1" FROM "e2e_automate" GROUP BY x_axis_1';
await setupQueryAndSwitchToBuild(pm, page, histogramQuery);
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.clickCustomQueryType();
await pm.logsPage.expectCustomModeActive();
const editorText = await pm.logsPage.getQueryEditorText();
expect(editorText.toLowerCase()).toContain('select');
expect(editorText.toLowerCase()).toContain('from');
testLogger.info('Auto → Custom (SQL ON) - PASSED');
});
test("SQL OFF: Auto → Custom shows WHERE clause in editor", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing Auto → Custom (SQL OFF)');
await pm.logsPage.disableSqlModeIfNeeded();
await pm.logsPage.setQueryEditorContent("code = '200'");
await pm.logsPage.clickBuildToggle();
await pm.logsPage.waitForBuildTabLoaded();
await pm.logsPage.clickCustomQueryType();
await pm.logsPage.expectCustomModeActive();
const editorText = await pm.logsPage.getQueryEditorText();
expect(editorText.toLowerCase()).not.toContain('select');
testLogger.info('Auto → Custom (SQL OFF) - PASSED');
});
});
// ============================================================================
// Test Suite: SQL Mode Toggle While in Builder
// ============================================================================
test.describe("Logs Query Builder - SQL Mode Toggle in Builder", () => {
test.describe.configure({ mode: 'parallel' });
let pm;
test.beforeAll(async ({ request }) => {
await ingestForQueryBuilderTest(request);
});
test.beforeEach(async ({ page }, testInfo) => {
testLogger.testStart(testInfo.title, testInfo.file);
await navigateToBase(page);
pm = new PageManager(page);
await initQueryBuilderTest(page, pm);
testLogger.info('SQL Mode Toggle in Builder test setup completed');
});
test("SQL OFF → ON in builder: search bar shows full SQL", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing SQL OFF → ON in builder');
await pm.logsPage.disableSqlModeIfNeeded();
await pm.logsPage.clickBuildToggle();
await pm.logsPage.waitForBuildTabLoaded();
await pm.logsPage.enableSqlModeIfNeeded();
await page.waitForLoadState('domcontentloaded');
const editorText = await pm.logsPage.getQueryEditorText();
expect(editorText.toLowerCase()).toContain('select');
expect(editorText.toLowerCase()).toContain('from');
testLogger.info('SQL OFF → ON: full SQL shown - PASSED');
});
test("SQL ON → OFF in builder: search bar shows WHERE clause only", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing SQL ON → OFF in builder');
const filterQuery = 'SELECT histogram(_timestamp) as "x_axis_1", count(_timestamp) as "y_axis_1" FROM "e2e_automate" WHERE code = \'200\' GROUP BY x_axis_1';
await setupQueryAndSwitchToBuild(pm, page, filterQuery);
await pm.logsPage.disableSqlModeIfNeeded();
await page.waitForLoadState('domcontentloaded');
const editorText = await pm.logsPage.getQueryEditorText();
// When SQL mode is turned OFF in the build tab, `onBuildQueryGenerated`
// syncs ONLY the extracted WHERE clause condition (no `WHERE` keyword) into
// the search bar — matching the search bar's filter-only mode. Verify the
// filter content (`code` field) is retained.
expect(editorText.toLowerCase()).toContain('code');
testLogger.info('SQL ON → OFF: WHERE clause filter preserved in builder-generated SQL - PASSED');
});
});
// ============================================================================
// Test Suite: Search Bar Editor State in Builder
// ============================================================================
test.describe("Logs Query Builder - Search Bar Editor State", () => {
test.describe.configure({ mode: 'parallel' });
let pm;
test.beforeAll(async ({ request }) => {
await ingestForQueryBuilderTest(request);
});
test.beforeEach(async ({ page }, testInfo) => {
testLogger.testStart(testInfo.title, testInfo.file);
await navigateToBase(page);
pm = new PageManager(page);
await initQueryBuilderTest(page, pm);
testLogger.info('Search Bar Editor State test setup completed');
});
test("SQL OFF + Auto mode: editor disabled with WHERE clause", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing SQL OFF + Auto: editor disabled');
await pm.logsPage.disableSqlModeIfNeeded();
await pm.logsPage.setQueryEditorContent("code = '200'");
await pm.logsPage.clickBuildToggle();
await pm.logsPage.waitForBuildTabLoaded();
await pm.logsPage.expectMonacoEditorAreaVisible();
await pm.logsPage.expectBuilderModeActive();
testLogger.info('SQL OFF + Auto: editor disabled - PASSED');
});
test("SQL ON + Auto mode: editor disabled with full generated SQL", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing SQL ON + Auto: editor disabled');
const histogramQuery = 'SELECT histogram(_timestamp) as "x_axis_1", count(_timestamp) as "y_axis_1" FROM "e2e_automate" GROUP BY x_axis_1';
await setupQueryAndSwitchToBuild(pm, page, histogramQuery);
// Wait for builder toggle to be active AND for the editor to actually contain SQL.
// expectBuilderModeActive() passes as soon as the toggle state is set (from the
// PanelEditor immediate watcher), but makeAutoSQLQuery() needs the updateGroupedFields
// API call to finish first — that takes longer in CI.
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.expectQueryEditorPopulated();
const editorText = await pm.logsPage.getQueryEditorText();
expect(editorText.toLowerCase()).toContain('select');
expect(editorText.toLowerCase()).toContain('from');
testLogger.info('SQL ON + Auto: editor disabled - PASSED');
});
test("SQL ON + Custom mode: editor editable with full SQL", {
tag: ['@queryBuilder', '@functional', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing SQL ON + Custom: editor editable');
const histogramQuery = 'SELECT histogram(_timestamp) as "x_axis_1", count(_timestamp) as "y_axis_1" FROM "e2e_automate" GROUP BY x_axis_1';
await setupQueryAndSwitchToBuild(pm, page, histogramQuery);
// Wait for builder toggle AND editor content before switching to Custom mode.
// onBuildModeToggle reads queries[0].query to populate the editor; that value
// is set by makeAutoSQLQuery() which needs the updateGroupedFields API call first.
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.expectQueryEditorPopulated();
await pm.logsPage.clickCustomQueryType();
await pm.logsPage.expectCustomModeActive();
const editorText = await pm.logsPage.getQueryEditorText();
expect(editorText.toLowerCase()).toContain('select');
await pm.logsPage.setQueryEditorContent('SELECT count(*) FROM "e2e_automate"');
const newText = await pm.logsPage.getQueryEditorText();
expect(newText.toLowerCase()).toContain('count');
testLogger.info('SQL ON + Custom: editor editable - PASSED');
});
});
// ============================================================================
// Test Suite: Bare Field Select → Default histogram/count (Case 3a)
// ============================================================================
test.describe("Logs Query Builder — Bare Field Select defaults (Case 3a)", () => {
test.describe.configure({ mode: 'parallel' });
let pm;
test.beforeAll(async ({ request }) => {
await ingestForQueryBuilderTest(request);
});
test.beforeEach(async ({ page }, testInfo) => {
testLogger.testStart(testInfo.title, testInfo.file);
await navigateToBase(page);
pm = new PageManager(page);
await initQueryBuilderTest(page, pm);
testLogger.info('Bare field select test setup completed');
});
test("Single bare field gets default histogram/count on build toggle", {
tag: ['@queryBuilder', '@bareFieldSelect', '@P0', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing SELECT single_field → default histogram/count');
await setupQueryAndSwitchToBuild(pm, page, 'SELECT kubernetes_container_name FROM "e2e_automate"');
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.expectXAxisHasItems();
await pm.logsPage.expectYAxisHasItems();
await pm.logsPage.verifyChartTypeSelected('bar');
testLogger.info('Single bare field → default histogram/count - PASSED');
});
test("Multiple bare fields get default histogram/count on build toggle", {
tag: ['@queryBuilder', '@bareFieldSelect', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing SELECT field1, field2 → default histogram/count');
await setupQueryAndSwitchToBuild(pm, page, 'SELECT kubernetes_container_name, kubernetes_host FROM "e2e_automate"');
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.expectXAxisHasItems();
await pm.logsPage.expectYAxisHasItems();
await pm.logsPage.verifyChartTypeSelected('bar');
testLogger.info('Multiple bare fields → default histogram/count - PASSED');
});
test("Bare field with WHERE clause preserves filter and uses defaults", {
tag: ['@queryBuilder', '@bareFieldSelect', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing SELECT field WHERE condition → defaults + filter preserved');
await setupQueryAndSwitchToBuild(pm, page, "SELECT kubernetes_container_name FROM \"e2e_automate\" WHERE kubernetes_host = 'test'");
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.expectXAxisHasItems();
await pm.logsPage.expectYAxisHasItems();
await pm.logsPage.verifyChartTypeSelected('bar');
testLogger.info('Bare field with WHERE → defaults + filter - PASSED');
});
test("Query with aggregation does NOT use defaults (parsed normally)", {
tag: ['@queryBuilder', '@bareFieldSelect', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing query with aggregation → parsed normally');
const aggQuery = 'SELECT kubernetes_container_name, count(_timestamp) as "y_axis_1" FROM "e2e_automate" GROUP BY kubernetes_container_name';
await setupQueryAndSwitchToBuild(pm, page, aggQuery);
await pm.logsPage.expectBuilderModeActive();
const xCount = await pm.logsPage.expectXAxisHasItems();
expect(xCount).toBeGreaterThanOrEqual(1);
const yCount = await pm.logsPage.expectYAxisHasItems();
expect(yCount).toBeGreaterThanOrEqual(1);
testLogger.info('Query with aggregation → parsed normally - PASSED');
});
});
// ============================================================================
// Test Suite: FieldList Button Visibility
// ============================================================================
test.describe("Logs Query Builder — FieldList button visibility", () => {
test.describe.configure({ mode: 'parallel' });
let pm;
test.beforeAll(async ({ request }) => {
await ingestForQueryBuilderTest(request);
});
test.beforeEach(async ({ page }, testInfo) => {
testLogger.testStart(testInfo.title, testInfo.file);
await navigateToBase(page);
pm = new PageManager(page);
await initQueryBuilderTest(page, pm);
testLogger.info('FieldList button test setup completed');
});
test("Search filter does not break button visibility in builder mode", {
tag: ['@queryBuilder', '@fieldListButtons', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Verifying search filter does not break buttons');
await setupQueryAndSwitchToBuild(pm, page, 'SELECT * FROM "e2e_automate"');
await pm.logsPage.expectBuilderModeActive();
await pm.logsPage.searchFieldInBuilder('kubernetes');
const visibleXCount = await pm.logsPage.getAddXButtonCount();
expect(visibleXCount).toBeGreaterThan(0);
testLogger.info(`After filter: ${visibleXCount} +X buttons visible`);
await pm.logsPage.searchFieldInBuilder('');
const afterClearCount = await pm.logsPage.getAddXButtonCount();
expect(afterClearCount).toBeGreaterThan(0);
testLogger.info(`After clear: ${afterClearCount} +X buttons visible - PASSED`);
});
test("Custom mode: buttons visible on custom/VRL fields after search", {
tag: ['@queryBuilder', '@fieldListButtons', '@P1', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Verifying buttons in custom mode with search');
await setupQueryAndSwitchToBuild(pm, page, 'SELECT kubernetes_container_name, kubernetes_host FROM "e2e_automate"');
await pm.logsPage.clickCustomQueryType();
await pm.logsPage.searchFieldInBuilder('axis');
const buttonCount = await pm.logsPage.getAddXButtonCount();
testLogger.info(`Custom mode + search: ${buttonCount} +X buttons`);
expect(buttonCount).toBeGreaterThan(0);
testLogger.info('Custom mode buttons with search - PASSED');
});
});