mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 16:09:05 +00:00
test: multi y-axis stacked charts (#6549)
This commit is contained in:
@@ -122,6 +122,7 @@ jobs:
|
||||
"reportsUpdated2.spec.js",
|
||||
"dashboards/dashboard-filter.spec.js",
|
||||
"dashboards/dashboard-folder.spec.js",
|
||||
"dashboards/dashboard-multi-y-axis.spec.js",
|
||||
"join.spec.js",
|
||||
"changeOrg.spec.js",
|
||||
"serviceAccount.spec.js",
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
import { expect } from "@playwright/test";
|
||||
|
||||
// pages/chartTypeSelector.js
|
||||
// Methods : selectChartType, selectStreamType, searchAndAddField, selectStream
|
||||
|
||||
export default class ChartTypeSelector {
|
||||
constructor(page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
// Chart Type select
|
||||
async selectChartType(chartType) {
|
||||
const chartOption = this.page.locator(
|
||||
`[data-test="selected-chart-${chartType}-item"]`
|
||||
);
|
||||
await chartOption.waitFor({ state: "visible", timeout: 5000 });
|
||||
await chartOption.click();
|
||||
}
|
||||
|
||||
// Stream Type select
|
||||
async selectStreamType(type) {
|
||||
// Click the dropdown
|
||||
await this.page.locator('[data-test="index-dropdown-stream_type"]').click();
|
||||
|
||||
await this.page
|
||||
.getByRole("option", { name: type })
|
||||
.locator("div")
|
||||
.nth(2)
|
||||
.click();
|
||||
}
|
||||
|
||||
// Stream select
|
||||
async selectStream(streamName) {
|
||||
const streamInput = this.page.locator(
|
||||
'[data-test="index-dropdown-stream"]'
|
||||
);
|
||||
await streamInput.click();
|
||||
await streamInput.press("Control+a");
|
||||
await streamInput.fill(streamName);
|
||||
|
||||
const streamOption = this.page
|
||||
.getByRole("option", { name: streamName, exact: true })
|
||||
.locator("div")
|
||||
.nth(2);
|
||||
|
||||
await streamOption.waitFor({ state: "visible", timeout: 5000 });
|
||||
await streamOption.click();
|
||||
}
|
||||
|
||||
// Search field and added for X, Y,Breakdown etc.
|
||||
async searchAndAddField(fieldName, target) {
|
||||
const searchInput = this.page.locator(
|
||||
'[data-test="index-field-search-input"]'
|
||||
);
|
||||
await searchInput.click();
|
||||
await searchInput.fill(fieldName);
|
||||
|
||||
const buttonSelectors = {
|
||||
x: '[data-test="dashboard-add-x-data"]',
|
||||
y: '[data-test="dashboard-add-y-data"]',
|
||||
b: '[data-test="dashboard-add-b-data"]',
|
||||
filter: '[data-test="dashboard-add-filter-data"]',
|
||||
latitude: '[data-test="dashboard-add-latitude-data"]',
|
||||
longitude: '[data-test="dashboard-add-longitude-data"]',
|
||||
weight: '[data-test="dashboard-add-weight-data"]',
|
||||
z: '[data-test="dashboard-add-z-data"]',
|
||||
};
|
||||
|
||||
const buttonSelector = buttonSelectors[target];
|
||||
|
||||
if (!buttonSelector) {
|
||||
throw new Error(`Invalid target type: ${target}`);
|
||||
}
|
||||
|
||||
await this.page.locator(buttonSelector).click();
|
||||
}
|
||||
|
||||
// Add filter condition
|
||||
async addFilterCondition(initialFieldName, newFieldName, operator, value) {
|
||||
// Step 1: Click the existing field if provided
|
||||
if (initialFieldName) {
|
||||
await this.page
|
||||
.locator(
|
||||
`[data-test="dashboard-add-condition-label-0-${initialFieldName}"]`
|
||||
)
|
||||
.click();
|
||||
}
|
||||
|
||||
// Step 2: Change field if newFieldName is provided
|
||||
if (newFieldName) {
|
||||
const fieldDropdown = this.page.locator(
|
||||
'[data-test="dashboard-add-condition-column-0\\}"]'
|
||||
);
|
||||
|
||||
await fieldDropdown.click();
|
||||
await fieldDropdown.fill(newFieldName);
|
||||
|
||||
await this.page
|
||||
.getByRole("option", { name: newFieldName, exact: true })
|
||||
.first()
|
||||
.click();
|
||||
}
|
||||
|
||||
const selectedField = newFieldName || initialFieldName;
|
||||
|
||||
// Step 3: Open the condition configuration if operator or value is being handled
|
||||
if (operator || value) {
|
||||
await this.page
|
||||
.locator('[data-test="dashboard-add-condition-list-0"]')
|
||||
.click();
|
||||
await this.page
|
||||
.locator('[data-test="dashboard-add-condition-condition-0"]')
|
||||
.click();
|
||||
}
|
||||
|
||||
// Step 4: Select operator if provided
|
||||
if (operator) {
|
||||
await this.page
|
||||
.locator('[data-test="dashboard-add-condition-operator"]')
|
||||
.click();
|
||||
await this.page.getByRole("option", { name: operator }).click();
|
||||
}
|
||||
|
||||
// Step 5: Enter value if provided
|
||||
if (value) {
|
||||
const valueInput = this.page.locator(
|
||||
'[data-test="common-auto-complete"]'
|
||||
);
|
||||
await valueInput.click();
|
||||
await valueInput.fill(value);
|
||||
} else if (operator && selectedField) {
|
||||
// Step 6: Assert dynamic error message for missing value
|
||||
const expectedError = `Filter: ${selectedField}: Condition value required`;
|
||||
const errorMessageLocator = this.page
|
||||
.locator("div")
|
||||
.filter({ hasText: expectedError })
|
||||
.first();
|
||||
await expect(errorMessageLocator).toBeVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { expect } from "@playwright/test";
|
||||
|
||||
// pages/chartTypeSelector.js
|
||||
// methods: createDashboard, searchDashboard, AddPanel, applyButton
|
||||
|
||||
export default class DashboardCreate {
|
||||
constructor(page) {
|
||||
this.page = page;
|
||||
this.dashCreateBtn = page.locator('[data-test="dashboard-add"]');
|
||||
this.dashName = page.locator('[data-test="add-dashboard-name"]');
|
||||
this.submitBtn = page.locator('[data-test="dashboard-add-submit"]');
|
||||
this.deleteIcon = page.locator('[data-test="dashboard-delete"]');
|
||||
this.confirmDelete = page.locator('[data-test="confirm-button"]');
|
||||
this.searchDash = page.locator('[data-test="dashboard-search"]');
|
||||
this.addPanelIfEmptyBtn = page.locator(
|
||||
'[data-test="dashboard-if-no-panel-add-panel-btn"]'
|
||||
);
|
||||
this.applyQueryBtn = page.locator('[data-test="dashboard-apply"]');
|
||||
}
|
||||
async createDashboard(dashboardName) {
|
||||
await this.dashCreateBtn.click();
|
||||
await this.dashName.click();
|
||||
await this.dashName.fill(dashboardName);
|
||||
await this.submitBtn.click();
|
||||
}
|
||||
|
||||
//Search Folder
|
||||
async searchDashboard(dashboardName) {
|
||||
await this.page
|
||||
.locator('[data-test="dashboard-folder-tab-default"]')
|
||||
.waitFor({ state: "visible" });
|
||||
|
||||
await this.searchDash.click();
|
||||
await this.searchDash.fill(dashboardName);
|
||||
}
|
||||
|
||||
//Add Panel to dashboard
|
||||
async addPanel() {
|
||||
await expect(this.addPanelIfEmptyBtn).toBeVisible({ timeout: 5000 });
|
||||
await this.addPanelIfEmptyBtn.click();
|
||||
}
|
||||
|
||||
async applyButton() {
|
||||
await this.applyQueryBtn.click();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Dashboard actions page
|
||||
// Methods : AddPanelName, SavePanel, ApplyDashboardBtn
|
||||
|
||||
export default class DashboardactionPage {
|
||||
constructor(page) {
|
||||
this.page = page;
|
||||
|
||||
this.panelNameInput = page.locator('[data-test="dashboard-panel-name"]');
|
||||
this.panelSaveBtn = page.locator('[data-test="dashboard-panel-save"]');
|
||||
this.applyDashboard = page.locator('[data-test="dashboard-apply"]');
|
||||
}
|
||||
|
||||
// Add panel name
|
||||
async addPanelName(panelName) {
|
||||
await this.panelNameInput.click();
|
||||
await this.panelNameInput.fill(panelName);
|
||||
}
|
||||
|
||||
// Save panel button
|
||||
async savePanel() {
|
||||
await this.panelSaveBtn.click();
|
||||
}
|
||||
|
||||
//Apply dashboard button
|
||||
async applyDashboardBtn() {
|
||||
await this.applyDashboard.click();
|
||||
}
|
||||
|
||||
// Wait for chart to render
|
||||
|
||||
async waitForChartToRender() {
|
||||
// Wait for it to go back to bg-secondary (render complete)
|
||||
await this.page.waitForFunction(() => {
|
||||
const btn = document.querySelector('[data-test="dashboard-apply"]');
|
||||
return btn && btn.classList.contains("bg-secondary");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { expect } from "@playwright/test";
|
||||
|
||||
//methods : setRelativeTimeRange
|
||||
|
||||
export default class DateTimeHelper {
|
||||
constructor(page) {
|
||||
this.page = page;
|
||||
this.applyQueryBtn = page.locator('[data-test="dashboard-apply"]');
|
||||
this.timePickerBtn = page.locator('[data-test="date-time-btn"]');
|
||||
this.applyTimeBtn = page.locator('[data-test="date-time-apply-btn"]');
|
||||
}
|
||||
// set relative time range
|
||||
async setRelativeTimeRange(rangeCode) {
|
||||
// Minutes= m Hours= h Days= d Weeks= w Months= M
|
||||
await this.applyQueryBtn.click();
|
||||
await this.timePickerBtn.click();
|
||||
await this.page
|
||||
.locator(`[data-test="date-time-relative-${rangeCode}-btn"]`)
|
||||
.click();
|
||||
await this.applyTimeBtn.click();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { test, expect } from "../baseFixtures.js";
|
||||
import logData from "../../cypress/fixtures/log.json";
|
||||
import logsdata from "../../../test-data/logs_data.json";
|
||||
import { login } from "../utils/dashLogin.js";
|
||||
import { ingestion } from "../utils/dashIngestion.js";
|
||||
import {
|
||||
waitForDashboardPage,
|
||||
deleteDashboard,
|
||||
} from "../utils/dashCreation.js";
|
||||
|
||||
import ChartTypeSelector from "../../pages/dashboardPages/dashboard-chart.js";
|
||||
import DashboardListPage from "../../pages/dashboardPages/dashboard-list.js";
|
||||
import DashboardCreate from "../../pages/dashboardPages/dashboard-create.js";
|
||||
import DateTimeHelper from "../../pages/dashboardPages/dashboard-time.js";
|
||||
import DashboardactionPage from "../../pages/dashboardPages/dashboard-panel-actions.js";
|
||||
|
||||
const randomDashboardName =
|
||||
"Dashboard_" + Math.random().toString(36).substr(2, 9);
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.describe("dashboard multi y axis testcases", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
console.log("running before each");
|
||||
await login(page);
|
||||
await page.waitForTimeout(1000);
|
||||
await ingestion(page);
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const orgNavigation = page.goto(
|
||||
`${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}`
|
||||
);
|
||||
await orgNavigation;
|
||||
});
|
||||
|
||||
test("Should correctly add multiple Y-axes to the stacked chart type.", async ({
|
||||
page,
|
||||
}) => {
|
||||
const chartTypeSelector = new ChartTypeSelector(page);
|
||||
const dashboardPage = new DashboardListPage(page);
|
||||
const dashboardCreate = new DashboardCreate(page);
|
||||
const dateTimeHelper = new DateTimeHelper(page);
|
||||
const dashboardPageActions = new DashboardactionPage(page);
|
||||
|
||||
await dashboardPage.menuItem("dashboards-item");
|
||||
|
||||
await waitForDashboardPage(page);
|
||||
|
||||
await dashboardCreate.createDashboard(randomDashboardName);
|
||||
|
||||
await dashboardCreate.addPanel();
|
||||
|
||||
await chartTypeSelector.selectChartType("stacked");
|
||||
|
||||
await chartTypeSelector.selectStreamType("logs");
|
||||
|
||||
await chartTypeSelector.selectStream("e2e_automate");
|
||||
|
||||
await chartTypeSelector.searchAndAddField("kubernetes_namespace_name", "y");
|
||||
|
||||
await chartTypeSelector.searchAndAddField("kubernetes_container_name", "y");
|
||||
|
||||
await chartTypeSelector.searchAndAddField("kubernetes_labels_name", "b");
|
||||
|
||||
await dateTimeHelper.setRelativeTimeRange("6-w");
|
||||
|
||||
await dashboardPageActions.waitForChartToRender();
|
||||
|
||||
await page
|
||||
.locator('[data-test="dashboard-panel-data-view-query-inspector-btn"]')
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
page
|
||||
.getByRole("cell", {
|
||||
name: 'SELECT histogram(_timestamp) as "x_axis_1", count(kubernetes_namespace_name) as "y_axis_1", count(kubernetes_container_name) as "y_axis_2", kubernetes_labels_name as "breakdown_1" FROM "e2e_automate" GROUP BY x_axis_1, breakdown_1 ORDER BY x_axis_1 ASC',
|
||||
})
|
||||
.first()
|
||||
).toBeVisible();
|
||||
|
||||
await page.locator('[data-test="query-inspector-close-btn"]').click();
|
||||
|
||||
await dashboardPageActions.addPanelName(randomDashboardName);
|
||||
|
||||
await dashboardPageActions.savePanel();
|
||||
|
||||
await page.locator('[data-test="dashboard-back-btn"]').click();
|
||||
|
||||
await deleteDashboard(page, randomDashboardName);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user