From 89cc402d64cd83df9cd98ca9bf196d20088ad975 Mon Sep 17 00:00:00 2001 From: ktx-akshay Date: Sat, 6 Sep 2025 17:40:07 +0530 Subject: [PATCH] test: add dashboard visualize test cases (#8303) ### **PR Type** Tests, Enhancement ___ ### **Description** - Add visualize error message test - Add quick mode toggle verification - Use enhanced base fixtures for tests - Enable visualize spec in CI workflow ___ ### Diagram Walkthrough ```mermaid flowchart LR Tests["Visualize tests updated"] -- "use" --> Fixtures["Enhanced base fixtures"] Tests -- "verify" --> ErrorMsg["Aggregation alias error message"] Tests -- "verify" --> QuickMode["Quick mode toggle true"] CI["Playwright workflow"] -- "enable" --> VisualizeSpec["visualize.spec.js run"] ```

File Walkthrough

Relevant files
Enhancement
visualise.js
Add helper to verify quick mode toggle                                     

tests/ui-testing/pages/dashboardPages/visualise.js
  • Add quick mode toggle verification helper
  • Check aria-checked and CSS class
+37/-0   
page-manager.js
Export PageManager default for imports                                     

tests/ui-testing/pages/page-manager.js - Export PageManager as default
+1/-1     
Tests
visualize.spec.js
Extend visualize e2e tests and base setup                               

tests/ui-testing/playwright-tests/dashboards/visualize.spec.js
  • Switch to enhanced base fixtures
  • Add test for aggregation alias error
  • Add test for quick mode toggle true
  • Improve navigation and waits
+79/-8   
Configuration changes
playwright.yml
Enable visualize spec in CI                                                           

.github/workflows/playwright.yml - Enable visualize.spec.js in workflow run list
+1/-1     
___ --- .../pages/dashboardPages/visualise.js | 153 +++++++++++++++++- tests/ui-testing/pages/page-manager.js | 10 +- .../dashboards/visualize.spec.js | 105 ++++++++++-- 3 files changed, 243 insertions(+), 25 deletions(-) diff --git a/tests/ui-testing/pages/dashboardPages/visualise.js b/tests/ui-testing/pages/dashboardPages/visualise.js index a657ef58a7..6af6225142 100644 --- a/tests/ui-testing/pages/dashboardPages/visualise.js +++ b/tests/ui-testing/pages/dashboardPages/visualise.js @@ -301,17 +301,150 @@ export default class LogsVisualise { const chartRenderer = page.locator( '[data-test="chart-renderer"], [data-test="dashboard-panel-table"]' ); - const chartExists = await chartRenderer.count(); - if (chartExists > 0) { - // Check if the chart is visible without using expect in page object - const isVisible = await chartRenderer.first().isVisible(); - if (!isVisible) { - throw new Error("Chart renderer is present but not visible"); + try { + // Wait for chart renderer to be present and visible + await chartRenderer.first().waitFor({ + state: "visible", + timeout: 15000, + }); + + // Additional check to ensure the chart is actually rendered + const chartExists = await chartRenderer.count(); + + if (chartExists > 0) { + // Double-check visibility after waiting + const isVisible = await chartRenderer.first().isVisible(); + if (!isVisible) { + // Wait for chart content to be rendered intelligently + const chartContentReady = await this.waitForChartContent(page, 3000); + + if (!chartContentReady) { + // Fallback: try waiting for chart renderer to be stable + try { + await chartRenderer.first().waitFor({ + state: "visible", + timeout: 2000, + }); + } catch (fallbackError) { + throw new Error( + `Chart renderer present but content failed to load after intelligent waiting. Error: ${fallbackError.message}` + ); + } + } + + // Final visibility check after intelligent waiting + const isVisibleRetry = await chartRenderer.first().isVisible(); + if (!isVisibleRetry) { + throw new Error( + "Chart renderer is present but not visible after intelligent retry" + ); + } + } + } + + return chartExists > 0; + } catch (error) { + // If waiting times out, check if element exists but is not visible + const chartExists = await chartRenderer.count(); + if (chartExists > 0) { + const isVisible = await chartRenderer.first().isVisible(); + throw new Error( + `Chart renderer found (${chartExists} elements) but visibility check failed. Is visible: ${isVisible}. Original error: ${error.message}` + ); + } else { + throw new Error( + `No chart renderer found. Original error: ${error.message}` + ); + } + } + } + + // RECOMMENDED: Native browser function (fastest & most reliable) + async waitForChartContent(page, timeout = 5000) { + return page + .waitForFunction( + () => + document.querySelector( + '[data-test="chart-renderer"], [data-test="dashboard-panel-table"]' + )?.offsetParent !== null, + {}, + { timeout } + ) + .then(() => true) + .catch(() => false); + } + + // Get quick mode toggle state using the most reliable method + async getQuickModeToggleState() { + const quickModeToggle = this.page.locator( + '[data-test="logs-search-bar-quick-mode-toggle-btn"]' + ); + + // Wait for the toggle to be present + await quickModeToggle.waitFor({ state: "visible", timeout: 10000 }); + + // Check aria-checked attribute - this is the most reliable indicator + // Falls back to aria-pressed if aria-checked is not available + let ariaChecked = await quickModeToggle.getAttribute("aria-checked"); + if (ariaChecked === null) { + ariaChecked = await quickModeToggle.getAttribute("aria-pressed"); + } + + return ariaChecked === "true"; + } + + // Verify quick mode toggle state + async verifyQuickModeToggle(expectedState = true) { + const isChecked = await this.getQuickModeToggleState(); + + // Validate the toggle state matches expectation + if (expectedState !== isChecked) { + throw new Error( + `Expected quick mode to be ${expectedState} but actual state is ${isChecked}` + ); + } + + return isChecked; + } + + // Toggle quick mode to specific state (enable/disable) + async setQuickModeToggle(enableState) { + const quickModeToggle = this.page.locator( + '[data-test="logs-search-bar-quick-mode-toggle-btn"]' + ); + + await quickModeToggle.waitFor({ state: "visible", timeout: 10000 }); + + const currentState = await this.getQuickModeToggleState(); + + // Only click if we need to change the state + if (currentState !== enableState) { + await quickModeToggle.click(); + + // Wait for state change to complete + await this.page.waitForTimeout(500); + + // Verify the state actually changed + const newState = await this.getQuickModeToggleState(); + if (newState !== enableState) { + throw new Error( + `Failed to set quick mode to ${enableState}. Current state: ${newState}` + ); } } - return chartExists > 0; + return enableState; + } + + // Enable quick mode if it's currently disabled + async enableQuickModeIfDisabled() { + return await this.setQuickModeToggle(true); + } + + // Disable quick mode if it's currently enabled + async disableQuickModeIfEnabled() { + return await this.setQuickModeToggle(false); } // Helper function to verify chart type selection @@ -353,4 +486,10 @@ export default class LogsVisualise { await this.updateSettingsBtn.waitFor({ state: "visible", timeout: 5000 }); await this.updateSettingsBtn.click(); } + + //wait for query inspector to be visible + async waitForQueryInspector(page) { + const queryInspector = page.getByText("Query Inspectorclose"); + await expect(queryInspector).toBeVisible({ timeout: 10000 }); + } } diff --git a/tests/ui-testing/pages/page-manager.js b/tests/ui-testing/pages/page-manager.js index ede2e063ea..1a9da325ae 100644 --- a/tests/ui-testing/pages/page-manager.js +++ b/tests/ui-testing/pages/page-manager.js @@ -56,7 +56,7 @@ class PageManager { */ constructor(page) { this.page = page; - + // ===== EXISTING DASHBOARD PAGE OBJECTS ===== this.dashboardCreate = new DashboardCreate(page); this.dashboardList = new DashboardListPage(page); @@ -75,10 +75,10 @@ class PageManager { this.dateTimeHelper = new DateTimeHelper(page); this.logsVisualise = new LogsVisualise(page); this.dashboardPage = new DashboardPage(page); - + // ===== EXISTING ALERTS PAGE OBJECT ===== this.alertsPage = new AlertsPage(page); - + // ===== SANITY SPEC ADDITIONAL PAGE OBJECTS ===== this.logsPage = new LogsPage(page); this.streamsPage = new StreamsPage(page); @@ -87,7 +87,7 @@ class PageManager { this.pipelinesPage = new PipelinesPage(page); this.loginPage = new LoginPage(page); this.ingestionPage = new IngestionPage(page); - + // ===== GENERAL TESTS ADDITIONAL PAGE OBJECTS ===== this.homePage = new HomePage(page); this.metricsPage = new MetricsPage(page); @@ -106,7 +106,7 @@ class PageManager { this.enrichmentPage = new EnrichmentPage(page); this.schemaPage = new SchemaPage(page); this.schemaLoadPage = new SchemaLoadPage(page); - + // ===== LOGS, REPORTS, STREAMS, PIPELINES ADDITIONAL PAGE OBJECTS ===== this.logsQueryPage = new LogsQueryPage(page); this.unflattenedPage = new UnflattenedPage(page); diff --git a/tests/ui-testing/playwright-tests/dashboards/visualize.spec.js b/tests/ui-testing/playwright-tests/dashboards/visualize.spec.js index 690bc07630..8df6619d76 100644 --- a/tests/ui-testing/playwright-tests/dashboards/visualize.spec.js +++ b/tests/ui-testing/playwright-tests/dashboards/visualize.spec.js @@ -1,8 +1,12 @@ -import { test, expect } from "@playwright/test"; -import { login } from "./utils/dashLogin.js"; +const { + test, + expect, + navigateToBase, +} = require("../utils/enhanced-baseFixtures.js"); import { ingestion } from "./utils/dashIngestion.js"; import logData from "../../fixtures/log.json"; import PageManager from "../../pages/page-manager"; +import { waitForDateTimeButtonToBeEnabled } from "../../pages/dashboardPages/dashboard-time"; import { waitForDashboardPage, deleteDashboard } from "./utils/dashCreation.js"; @@ -46,16 +50,19 @@ const largeDatasetSqlQuery = `SELECT kubernetes_annotations_kubectl_kubernetes_i const histogramQuery = `SELECT histogram(_timestamp) as "x_axis_1", count(kubernetes_namespace_name) as "y_axis_1" FROM "${STREAM_NAME}" GROUP BY x_axis_1 ORDER BY x_axis_1 ASC `; +// Query without aliases for testing error message +const queryWithoutAliases = `SELECT count(kubernetes_container_hash), count(kubernetes_container_name), count(kubernetes_host) FROM "${STREAM_NAME}" WHERE kubernetes_namespace_name IS NOT NULL GROUP BY kubernetes_annotations_kubectl_kubernetes_io_default_container`; + test.describe("logs testcases", () => { test.beforeEach(async ({ page }) => { - await login(page); - await page.waitForTimeout(1000); + await navigateToBase(page); await ingestion(page); - await page.waitForTimeout(2000); - await page.goto( - `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` - ); + // Navigate to logs page + const logsUrl = `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}`; + + await page.goto(logsUrl); + await page.waitForLoadState("networkidle"); // Instantiate PageManager with the current page const pm = new PageManager(page); @@ -437,20 +444,26 @@ test.describe("logs testcases", () => { await pm.logsVisualise.openVisualiseTab(); + await pm.logsVisualise.runQueryAndWaitForCompletion(); + await pm.logsVisualise.verifyChartRenders(page); await pm.logsVisualise.addPanelToNewDashboard( randomDashboardName, panelName ); - await page.waitForTimeout(2000); + + // Wait for and assert the success message + const successMessage = page.getByText("Panel added to dashboard"); + await expect(successMessage).toBeVisible({ timeout: 10000 }); await page .locator('[data-test="dashboard-edit-panel-' + panelName + '-dropdown"]') .click(); await page.locator('[data-test="dashboard-query-inspector-panel"]').click(); - await page.waitForTimeout(2000); + await pm.logsVisualise.waitForQueryInspector(page); + await expect( page .getByRole("cell", { @@ -479,20 +492,24 @@ test.describe("logs testcases", () => { await pm.logsVisualise.openVisualiseTab(); - await page.waitForTimeout(2000); + await pm.logsVisualise.runQueryAndWaitForCompletion(); await pm.logsVisualise.addPanelToNewDashboard( randomDashboardName, panelName ); - await page.waitForTimeout(2000); + // Wait for and assert the success message + const successMessage = page.getByText("Panel added to dashboard"); + await expect(successMessage).toBeVisible({ timeout: 10000 }); + await page .locator('[data-test="dashboard-edit-panel-' + panelName + '-dropdown"]') .click(); await page.locator('[data-test="dashboard-query-inspector-panel"]').click(); - await page.waitForTimeout(2000); + await pm.logsVisualise.waitForQueryInspector(page); + await expect( page .getByRole("cell", { @@ -505,4 +522,66 @@ test.describe("logs testcases", () => { await page.locator('[data-test="dashboard-back-btn"]').click(); await deleteDashboard(page, randomDashboardName); }); + + test("should show error message when using aggregation functions without aliases in SQL query", async ({ + page, + }) => { + const pm = new PageManager(page); + + // Step 1: Open logs page + await pm.logsVisualise.openLogs(); + + // Step 2: Fill the query editor with SQL query without aliases + await pm.logsVisualise.fillLogsQueryEditor(queryWithoutAliases); + + // Step 3: Set relative time + await pm.logsVisualise.setRelative("6", "w"); + + // Step 4: Apply the query + await pm.logsVisualise.logsApplyQueryButton(); + + // Step 5: Open the visualize tab + await pm.logsVisualise.openVisualiseTab(); + + // Step 6: Wait for error message to appear + const errorMessage = page.getByText( + "Fields using aggregation functions must have aliases" + ); + + // Wait for the error message to appear on the page + await errorMessage.waitFor({ state: "visible", timeout: 10000 }); + + // Step 7: Check for the specific error message using getByText + // Verify the error message is displayed + await expect(errorMessage.first()).toBeVisible(); + }); + test("should show quick mode as true when toggling to visualize tab", async ({ + page, + }) => { + const pm = new PageManager(page); + + await pm.logsVisualise.openLogs(); + + await pm.logsVisualise.logsSelectStream("e2e_automate"); + + await waitForDateTimeButtonToBeEnabled(page); + + await pm.logsVisualise.setRelative("6", "w"); + + // Step 4: Apply the query + await pm.logsVisualise.logsApplyQueryButton(); + + // Step 5: Open the visualize tab + await pm.logsVisualise.openVisualiseTab(); + + // Step 7: Verify quick mode toggle is true + const quickModeState = await pm.logsVisualise.verifyQuickModeToggle(true); + expect(quickModeState).toBe(true); + + // Additional assertion using Playwright's expect for the toggle state + const quickModeToggle = page.locator( + '[data-test="logs-search-bar-quick-mode-toggle-btn"]' + ); + await expect(quickModeToggle).toHaveAttribute("aria-checked", "true"); + }); });