diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 6ed4ba4e0a..4d4ada20ef 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -122,10 +122,10 @@ jobs: "dashboards/visualization-vrl.spec.js", "enrichment.spec.js", "join.spec.js", - "logshistogram.spec.js", - "logspage.spec.js", - "logsqueries.spec.js", - "logsquickmode.spec.js", + "Logs/logshistogram.spec.js", + "Logs/logspage.spec.js", + "Logs/logsqueries.spec.js", + "Logs/logsquickmode.spec.js", "multiselect-stream.spec.js", "pagination.spec.js", "pipelines.spec.js", diff --git a/tests/ui-testing/pages/logsPage.js b/tests/ui-testing/pages/logsPage.js deleted file mode 100644 index 405ce5bebd..0000000000 --- a/tests/ui-testing/pages/logsPage.js +++ /dev/null @@ -1,830 +0,0 @@ -// logsPage.js -import { expect } from '@playwright/test'; -const { chromium } = require('playwright'); -import { dateTimeButtonLocator, relative30SecondsButtonLocator, absoluteTabLocator, Past30SecondsValue } from '../pages/CommonLocator.js'; -import logData from '../cypress/fixtures/log.json'; - -export class LogsPage { - constructor(page) { - - this.page = page; - - this.orgDropdown = '[data-test="navbar-organizations-select"]'; - this.defaultOrgOption = this.page.getByRole('option', { name: 'default', exact: true }).locator('div').nth(2); - this.logsMenuItem = page.locator('[data-test="menu-link-\\/logs-item"]'); - this.indexDropDown = page.locator('[data-test="logs-search-index-list"]').getByText('arrow_drop_down'); - this.streamToggle = page.locator('[data-test="log-search-index-list-stream-toggle-default"] div'); - this.exploreButton = page.getByRole('button', { name: 'Explore' }); - this.timestampColumnMenu = page.locator('[data-test="log-table-column-1-_timestamp"] [data-test="table-row-expand-menu"]'); - - this.filterMessage = page.locator('div:has-text("info Adjust filter parameters and click \'Run query\'")'); - - this.dateTimeButton = dateTimeButtonLocator; - this.relative30SecondsButton = page.locator(relative30SecondsButtonLocator); - - this.sqlModeToggle = this.page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2) - - this.absoluteTab = absoluteTabLocator; - - this.homeButton = "[name ='home']"; - - - this.timeZoneDropdown = "//label[contains(@class,'timezone-select')]"; - this.timeZoneOption = (zone) => `role=option[name="${zone}"]`; - this.dateSelector = (day) => `//div[contains(@class,'q-date__calendar-item--in')]/button/span[contains(@class,'q-btn__content')]/span[text()='${day}']`; - this.monthSelector = (month) => `//span[text() ='${month}']`; - this.yearSelector = (year) => `//span[text() ='${year}']`; - this.startTimeField = "input[class = 'q-field__native q-placeholder']:nth-of-type(2)"; - this.endTimeField = "input[class = 'q-field__native q-placeholder']:nth-of-type(3)"; - this.scheduleText = "//i[text() ='schedule']/following-sibling::span"; - this.calendarDate = "//div[contains(@class,'q-date__calendar-item--in')]/button/span[contains(@class,'q-btn__content')]/span[text()='"; - this.startTimeInput = "input[class = 'q-field__native q-placeholder']:nth-child(2)"; - this.endTimeInput = "input[class = 'q-field__native q-placeholder']:nth-child(3)"; - this.timezoneSelector = "//label[contains(@class,'timezone-select')]"; - - this.streamDropdown = '[data-test="log-search-index-list-select-stream"]'; - this.queryButton = "[data-test='logs-search-bar-refresh-btn']"; - this.queryEditor = '[data-test="logs-search-bar-query-editor"]'; - this.quickModeToggle = '[data-test="logs-search-bar-quick-mode-toggle-btn"]'; - - this.profileButton = page.locator('[data-test="header-my-account-profile-icon"]'); - this.signOutButton = page.getByText('Sign Out'); - - // Search Partition locators - this.searchPartitionButton = page.locator('[data-test="logs-search-partition-btn"]'); - this.partitionDropdown = page.locator('[data-test="logs-search-partition-dropdown"]'); - this.partitionOption = (option) => page.getByRole('option', { name: option }); - this.partitionValueInput = page.locator('[data-test="logs-search-partition-value-input"]'); - this.partitionApplyButton = page.locator('[data-test="logs-search-partition-apply-btn"]'); - this.partitionClearButton = page.locator('[data-test="logs-search-partition-clear-btn"]'); - this.partitionActiveIndicator = page.locator('[data-test="logs-search-partition-active"]'); - this.resultText = '[data-test="logs-search-search-result"]'; - - // String match ignore case locators - this.logsSearchBarQueryEditor = '[data-test="logs-search-bar-query-editor"]'; - this.searchBarRefreshButton = '[data-cy="search-bar-refresh-button"] > .q-btn__content'; - this.logTableColumnSource = '[data-test="log-table-column-0-source"]'; - - } - - async selectOrganization() { - await this.page.locator(this.orgDropdown).getByText('arrow_drop_down').click(); - await this.defaultOrgOption.click(); - } - - - async navigateToLogs() { - // Click on Logs menu item - await this.page.locator(this.homeButton).hover(); - await this.logsMenuItem.click(); - await this.page.waitForTimeout(3000); - // await expect(this.page.locator('[data-test="logs-search-no-stream-selected-text"]')).toContainText('info Select a stream and press \'Run query\' to continue. Additionally, you can apply additional filters and adjust the date range to enhance search.'); - } - - async validateLogsPage() { - await expect(this.page.locator('[data-test="logs-search-no-stream-selected-text"]')).toContainText('info Select a stream and press \'Run query\' to continue. Additionally, you can apply additional filters and adjust the date range to enhance search.'); - } - - async logsPageDefaultMultiOrg() { - await this.page.waitForTimeout(2000); - await this.page.reload(); - await this.page.locator('[data-test="navbar-organizations-select"]').getByText('arrow_drop_down').click(); - await this.page.waitForTimeout(2000); - await this.page.getByRole('option', { name: 'defaulttestmulti' }).locator('div').nth(2).click(); - } - - async logsPageURLValidation() { - // TODO: fix the test - // await expect(this.page).not.toHaveURL(/default/); - } - - async selectIndexAndStream() { - // Select index and stream - await this.indexDropDown.click(); - await this.streamToggle.first().click(); - // await this.page.waitForTimeout(3000); - await this.streamToggle.nth(2).click(); - } - - async selectIndexAndStreamJoin() { - await this.page.locator('[data-test="logs-search-index-list"]').getByText('arrow_drop_down').click(); - await this.page.waitForTimeout(3000); - await this.page.locator('[data-test="log-search-index-list-stream-toggle-default"] div').first().click(); - await this.page.waitForTimeout(3000); - await this.page.locator('[data-test="log-search-index-list-stream-toggle-e2e_automate"] div').first().click(); - await this.page.waitForTimeout(3000); - } - - async selectRunQuery() { - - await this.page.locator(this.queryButton).click(); - await this.page.waitForTimeout(5000); - } - - async setTimeToPast30Seconds() { - // Set the time filter to the last 30 seconds - await expect(this.page.locator(this.dateTimeButton)).toBeVisible(); - await this.page.locator(this.dateTimeButton).click(); - await this.relative30SecondsButton.click(); - - } - - async verifyTimeSetTo30Seconds() { - // Verify that the time filter displays "Past 30 Seconds" - await expect(this.page.locator(this.dateTimeButton)).toContainText(Past30SecondsValue); - } - - async enableSQLMode() { - await this.sqlModeToggle.click(); - } - - async setDateTime() { - await expect(this.page.locator(this.dateTimeButton)).toBeVisible(); - await this.page.locator(this.dateTimeButton).click(); - await this.page.locator(this.absoluteTab).click(); - await this.page.waitForTimeout(1000); - - } - - async setAbsoluteDate(year, month, day, currentMonth, currentYear) { - // await this.page.locator(this.dateTimeButton).click(); - // await this.page.getByText(" Absolute ").click(); - - if (currentMonth.includes(month) && year === currentYear.toString()) { - await this.page.locator(this.calendarDate + day + "']").dblclick(); - } else if (year === currentYear.toString()) { - await this.page.getByText(currentMonth).click(); - await this.page.locator("//span[text() ='" + month + "']").click(); - await this.page.locator("//span[text() ='" + day + "']").dblclick(); - } else { - await this.page.getByText(currentMonth).click(); - await this.page.locator("//span[text() ='" + month + "']").click(); - await this.page.locator("//span[text() ='" + currentYear + "']").click(); - await this.page.locator("//span[text() ='" + year + "']").click(); - await this.page.locator("//span[text() ='" + day + "']").dblclick(); - } - } - - async setStartAndEndTime(startTime, endTime) { - await this.page.locator(this.startTimeInput).fill(startTime); - await this.page.locator(this.endTimeInput).fill(endTime); - } - - async setTimeRange(startTime, endTime) { - await this.page.locator(this.startTimeField).fill(startTime); - await this.page.locator(this.endTimeField).fill(endTime); - } - - async verifySchedule(expectedTime) { - const schedule = await this.page.locator(this.scheduleText).textContent(); - expect(schedule).toEqual(expectedTime); - } - - async setTimeZone(zone) { - await this.page.locator(this.timeZoneDropdown).click(); - await this.page.getByRole(this.timeZoneOption(zone)).click(); - } - - async changeTimeZone() { - await this.page.locator("//label[contains(@class,'timezone-select')]").click() - await this.page.getByRole('option', { name: 'Asia/Dubai' }).click() - } - - async verifyDateTime(startTime, endTime) { - await expect(this.page.locator(this.dateTimeButton)).toContainText(`${startTime} - ${endTime}`); - } - - async copyShare() { - const browser = await chromium.launch(); - - const context = await browser.newContext({ - permissions: ['clipboard-read', 'clipboard-write'] - }); - const page = await context.newPage(); - await page.locator("[title ='Share Link']").click(); - const copiedUrl = await page.evaluate(() => navigator.clipboard.readText()) - console.log(copiedUrl); - // console.log(Copied text: ${copiedUrl}) - const newpage = await context.newPage() - await newpage.waitForTimeout(5000) - await newpage.goto(copiedUrl) - console.log(newpage.url()) - expect(copiedUrl).toContain('short') - } - - async getScheduleText() { - return await this.page.locator("//button[(@data-test ='date-time-btn')]/span[contains(@class,'q-btn__content')]/span").textContent(); - } - - async selectStream(stream) { - await this.page.waitForTimeout(4000); - await this.page.locator(this.streamDropdown).click({ force: true }); - await this.page.locator("div.q-item").getByText(`${stream}`).first().click({ force: true }); - } - - async applyQuery() { - const search = this.page.waitForResponse(logData.applyQuery); - await this.page.waitForTimeout(3000); - await this.page.locator("[data-test='logs-search-bar-refresh-btn']").click({ - force: true, - }); - await expect.poll(async () => (await search).status()).toBe(200); - } - - async applyQueryButton(expectedUrl) { - const searchResponse = this.page.waitForResponse(expectedUrl); - await this.page.waitForTimeout(3000); - await this.page.locator(this.queryButton).click({ force: true }); - await expect.poll(async () => (await searchResponse).status()).toBe(200); - } - - async clearAndRunQuery() { - await this.page.locator(this.queryButton).click(); - await this.page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await this.page.locator(this.queryEditor).click(); - await this.page.keyboard.press(process.platform === "darwin" ? "Meta+A" : "Control+A"); - await this.page.keyboard.press("Backspace"); - await this.page.waitForTimeout(3000); - await this.page.locator(this.queryButton).click(); - await this.page.getByText("SQL query is missing or invalid. Please submit a valid SQL statement.").click(); - } - - - async kubernetesContainerName() { - await this.page.getByLabel('Expand "kubernetes_container_name"').click(); - await this.page.waitForTimeout(5000); - await this.page.locator('[data-test="logs-search-subfield-add-kubernetes_container_name-ziox"] [data-test="log-search-subfield-list-equal-kubernetes_container_name-field-btn"]').click(); - - } - - async kubernetesContainerNameJoin() { - await this.page - .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') - .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a join "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name'); - await this.page.waitForTimeout(5000); - } - - async kubernetesContainerNameJoinLimit() { - await this.page - .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') - .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a join "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name LIMIT 10'); - await this.page.waitForTimeout(5000); - } - - - async kubernetesContainerNameJoinLike() { - await this.page - .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') - .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a join "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name WHERE a.kubernetes_container_name LIKE "%ziox%"'); - await this.page.waitForTimeout(5000); - } - - async kubernetesContainerNameLeftJoin() { - await this.page - .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') - .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a LEFT JOIN "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name'); - await this.page.waitForTimeout(5000); - } - - async kubernetesContainerNameRightJoin() { - await this.page - .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') - .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a RIGHT JOIN "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name'); - await this.page.waitForTimeout(5000); - } - - async kubernetesContainerNameFullJoin() { - await this.page - .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') - .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a FULL JOIN "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name'); - await this.page.waitForTimeout(5000); - } - - async displayCountQuery() { - await this.page.waitForTimeout(4000); - await expect(this.page.getByRole('heading', { name: 'Error while fetching' })).not.toBeVisible(); - } - - async validateResult() { - await this.page.waitForTimeout(10000); - await expect(this.page.locator('[data-test="logs-search-search-result"]')).toBeVisible(); - await this.page.locator('td[data-test="log-table-column-0-source"]').nth(0).click(); - await expect(this.page.locator('[data-test="log-expand-detail-key-kubernetes_container_name-text"]')).toBeVisible(); - - } - - - - - async signOut() { - await this.profileButton.click(); - await this.signOutButton.click(); - } - - async displayTwoStreams() { - await expect(this.page.locator('[data-test="logs-search-index-list"]')).toContainText('default, e2e_automate'); - } - - async verifyQuickModeToggle() { - await expect(this.page.locator(this.quickModeToggle)).toBeVisible(); - } - - async clickQuickModeToggle() { - - // Get the toggle button element - const toggleButton = await this.page.$('[data-test="logs-search-bar-quick-mode-toggle-btn"] > .q-toggle__inner'); - // Evaluate the class attribute to determine if the toggle is in the off state - const isSwitchedOff = await toggleButton.evaluate(node => node.classList.contains('q-toggle__inner--falsy')); - // If the toggle is switched off, click on it to switch it on - if (isSwitchedOff) { - await toggleButton.click(); - - } - - } - - async clickInterestingFields() { - - await this.page.locator('[data-cy="index-field-search-input"]').fill("kubernetes_container_name"); - await this.page.waitForTimeout(2000); - await this.page.locator('[data-test="log-search-index-list-interesting-kubernetes_container_name-field-btn"]').first().click(); - await this.page.waitForTimeout(2000); - } - - async validateInterestingFields() { - await expect(this.page.locator('[data-test="logs-search-bar-query-editor"]').getByText(/kubernetes_container_name/).first()).toBeVisible(); - } - - async validateInterestingFieldsQuery() { - await this.page.waitForSelector('[data-test="logs-search-bar-query-editor"]'); - await expect(this.page.locator('[data-test="logs-search-bar-query-editor"]').locator('text=kubernetes_container_name FROM "default"') - ).toBeVisible(); - } - - async addRemoveInteresting() { - - await this.page.locator('[data-cy="index-field-search-input"]').clear(); - await this.page.locator('[data-cy="index-field-search-input"]').fill("job"); - await this.page.waitForTimeout(2000); - await this.page.locator('[data-test="log-search-index-list-interesting-job-field-btn"]').last().click({ force: true, }); - await this.page.locator('[data-cy="search-bar-refresh-button"] > .q-btn__content').click({ force: true, }); - await this.page.waitForTimeout(2000); - await this.page.locator('[data-test="log-search-index-list-interesting-job-field-btn"]').last().click({ force: true, }); - await this.page.waitForTimeout(2000); - await expect(this.page.locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox')).not.toHaveText(/job/); - } - - - async setDateTimeToToday() { - // Set up route interception and apply filters - await this.page.route('**/api/default/_search**', (route) => route.continue());; - - // Click on the date-time button - await expect(this.page.locator(this.dateTimeButton)).toBeVisible(); - await this.page.locator(this.dateTimeButton).click(); - - // Select the absolute date-time tab - await this.page.locator('[data-test="date-time-absolute-tab"]').click(); - - // Select the current date - const date = new Date().getDate(); - await this.page.getByRole('button', { name: date.toString(), exact: true }).last().click(); - await this.page.getByRole('button', { name: date.toString(), exact: true }).last().click(); - - // Fill the start time - const startTimeInput = this.page.locator(".startEndTime td:nth-child(1) input"); - await startTimeInput.click(); - await startTimeInput.fill(""); - await startTimeInput.type("000000"); - - // Wait briefly for UI stability - // await this.page.waitForTimeout(2000); - await this.page.waitForSelector('.startEndTime td:nth-child(2) input', { state: 'visible' }); - - - // Fill the end time - const endTimeInput = this.page.locator(".startEndTime td:nth-child(2) input"); - await endTimeInput.click(); - await endTimeInput.fill(""); - await this.page.waitForTimeout(2000); - await endTimeInput.type("235900"); - await this.page.locator('[data-test="logs-logs-toggle"]', { state: 'visible' }).click(); - await this.page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - - // Wait briefly for search results to load - await this.page.waitForTimeout(2000); - - // Validate the date range of the log entries - const startDate = new Date(); - startDate.setHours(0, 0, 0); - const endDate = new Date(); - endDate.setHours(23, 59, 59); - - const startDateStr = `${startDate.getFullYear()}-${String(startDate.getMonth() + 1).padStart(2, "0")}-${String(startDate.getDate()).padStart(2, "0")} 00:00:00`; - const endDateStr = `${endDate.getFullYear()}-${String(endDate.getMonth() + 1).padStart(2, "0")}-${String(endDate.getDate()).padStart(2, "0")} 23:59:59`; - - const rows = await this.page.locator('[data-test="logs-search-result-logs-table"] tbody:nth-of-type(2) tr').all(); - - for (let i = 2; i < rows.length; i++) { - const dateText = await rows[i].locator('td:first-child div div:nth-child(2) span span').textContent(); - if (dateText) { - const date = new Date(dateText.trim()); - const startDate = new Date(startDateStr); - const endDate = new Date(endDateStr); - - // Check if the parsed date is valid - if (isNaN(date.getTime())) { - throw new Error(`Invalid date format: ${dateText}`); - } - - expect(date >= startDate && date <= endDate).toBeTruthy(); - } - } - - await expect(this.page.locator('[data-test="logs-search-result-logs-table"]')).toBeVisible(); - } - - async selectStreamAndStreamTypeForLogs(stream) { - - await this.page.locator('[data-test="log-search-index-list-select-stream"]').click(); - await this.page.waitForTimeout(2000); - await this.page.locator('[data-test="log-search-index-list-select-stream"]').fill(stream); - await this.page.waitForTimeout(2000); - await this.page.waitForSelector(`[data-test="log-search-index-list-stream-toggle-${stream}"] div`, { state: "visible" }); - await this.page.waitForTimeout(2000); - await this.page.locator(`[data-test="log-search-index-list-stream-toggle-${stream}"] div`).first().click(); -} - -async toggleHistogram() { - await this.page.waitForSelector('[data-test="logs-search-bar-show-histogram-toggle-btn"]'); - await this.page.locator('[data-test="logs-search-bar-show-histogram-toggle-btn"] div').nth(2).click(); -} - -async checkErrorVisible() { - return this.page.getByRole('heading', { name: 'Error while fetching' }).isVisible(); -} - -async getErrorDetails() { - return this.page.locator('[data-test="logs-search-search-result"]').getByRole('heading'); -} - -async selectIndexStreamDefault() { - await this.page.locator('[data-test="logs-search-index-list"]').getByText('arrow_drop_down').click(); - await this.page.waitForTimeout(3000); - await this.page.locator('[data-test="log-search-index-list-stream-toggle-default"] div').first().click(); - -} - -async selectIndexStream(streamName) { - await this.page.locator('[data-test="logs-search-index-list"]').getByText('arrow_drop_down').click(); - await this.page.waitForTimeout(3000); - await this.page.locator(`[data-test="log-search-index-list-stream-toggle-${streamName}"] div`).first().click(); - -} - -async clearAndFillQueryEditor(query) { - const editor = this.page.locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox'); - await editor.fill(''); // Clear the editor - await this.page.waitForTimeout(1000); // Optional: adjust or remove as per your needs - await editor.fill(query); // Fill with the new query -} - -async typeQuery(query) { - const queryEditor = this.page.locator('[data-test="logs-search-bar-query-editor"]'); - await expect(queryEditor).toBeVisible(); - await queryEditor.click(); - await this.page.locator('[data-test="logs-search-bar-query-editor"]').locator('.cm-content').fill(query); - await this.page.waitForTimeout(1000); - - - -} - -async waitForSearchResultAndCheckText(expectedText) { - const locator = this.page.locator('[data-test="logs-search-search-result"]').getByRole('heading'); - await locator.waitFor(); // Wait for the element to be visible - await expect(locator).toContainText(expectedText); -} - -async executeQueryWithKeyboardShortcut() { - // Press Cmd+Enter (Mac) or Ctrl+Enter (Windows/Linux) - await this.page.keyboard.press(process.platform === "darwin" ? "Meta+Enter" : "Control+Enter"); -} - -async executeQueryWithKeyboardShortcutTest() { - // Set up date/time filter - await this.page.locator('[data-test="date-time-btn"]').click({ force: true }); - await this.page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - - // Ensure the query editor is visible and clickable before typing - const queryEditor = this.page.locator('[data-test="logs-search-bar-query-editor"]'); - await expect(queryEditor).toBeVisible(); - await queryEditor.click(); - await this.page.keyboard.type("match_all('code')"); - - // Execute query using keyboard shortcut - await this.executeQueryWithKeyboardShortcut(); - - // Verify that the expected log table column is visible - await expect(this.page.locator('[data-test="log-table-column-0-source"]')).toBeVisible(); -} - -async executeQueryWithKeyboardShortcutAfterClickingElsewhere() { - // Set up date/time filter - await this.page.locator('[data-test="date-time-btn"]').click({ force: true }); - await this.page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - - // Click elsewhere on the screen first - await this.page.locator('[data-test="logs-search-bar"]').click(); - - // Ensure the query editor is visible and clickable before typing - const queryEditor = this.page.locator('[data-test="logs-search-bar-query-editor"]'); - await expect(queryEditor).toBeVisible(); - await queryEditor.click(); - await this.page.keyboard.type("match_all('code')"); - - // Execute query using keyboard shortcut - await this.executeQueryWithKeyboardShortcut(); - - // Verify that the expected log table column is visible - await expect(this.page.locator('[data-test="log-table-column-0-source"]')).toBeVisible(); -} - -async executeQueryWithKeyboardShortcutWithDifferentQuery() { - // Set up date/time filter - await this.page.locator('[data-test="date-time-btn"]').click({ force: true }); - await this.page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - - // Ensure the query editor is visible and clickable before typing - const queryEditor = this.page.locator('[data-test="logs-search-bar-query-editor"]'); - await expect(queryEditor).toBeVisible(); - await queryEditor.click(); - await this.page.keyboard.type("str_match_ignore_case(kubernetes_container_name, 'ziox')"); - - // Execute query using keyboard shortcut - await this.executeQueryWithKeyboardShortcut(); - - // Verify that the expected log table column is visible - await expect(this.page.locator('[data-test="log-table-column-0-source"]')).toBeVisible(); -} - -async executeQueryWithKeyboardShortcutWithSQLMode() { - // Set up date/time filter - await this.page.locator('[data-test="date-time-btn"]').click({ force: true }); - await this.page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - - // Enable SQL mode - await this.sqlModeToggle.click(); - - // Ensure the query editor is visible and clickable before typing - const queryEditor = this.page.locator('[data-test="logs-search-bar-query-editor"]'); - await expect(queryEditor).toBeVisible(); - await queryEditor.click(); - await this.page.keyboard.type('SELECT COUNT(_timestamp) AS xyz, _timestamp FROM "e2e_automate" Group by _timestamp ORDER BY _timestamp DESC'); - - // Execute query using keyboard shortcut - await this.executeQueryWithKeyboardShortcut(); - - // Verify that the expected log table column is visible - await expect(this.page.locator('[data-test="logs-search-result-bar-chart"]')).toBeVisible(); -} - -async executeQueryWithErrorHandling() { - // Fill query editor with invalid query - await this.page.locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox', { name: 'Editor content;Press Alt+F1' }).fill('match_all(\'invalid\')'); - - // Click refresh button and verify error - await this.page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await this.page.locator('[data-test="logs-search-error-message"]').click(); - - // Reset filters - await this.page.locator('[data-test="logs-search-bar-reset-filters-btn"]').click(); - - // Toggle histogram - await this.page.locator('[data-test="logs-search-bar-show-histogram-toggle-btn"] div').first().click(); - - // Click first line and refresh - await this.page.locator('.cm-line').first().click(); - await this.page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - - // Verify no data message - await this.page.getByText('warning No data found for').click(); - - // Click on result detail - await this.page.locator('[data-test="logs-search-result-detail-undefined"]').click(); -} - -// New methods for histogram query test -async executeHistogramQuery(query) { - await this.page.locator('[data-test="logs-search-bar-query-editor"]').locator('.cm-content').click(); - await this.page.keyboard.type(query); - await this.page.waitForTimeout(2000); -} - -async toggleHistogramAndExecute() { - await this.page.locator('[data-test="logs-search-bar-show-histogram-toggle-btn"] div').nth(2).click(); - await this.page.waitForTimeout(1000); - await this.page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); -} - -async verifyHistogramState() { - const isHistogramOff = await this.page.locator('[data-test="logs-search-bar-show-histogram-toggle-btn"]') - .evaluate(el => el.getAttribute('aria-checked') === 'false'); - expect(isHistogramOff).toBeTruthy(); -} - -async verifySearchPartitionResponse() { - const searchPartitionPromise = this.page.waitForResponse(response => - response.url().includes('/api/default/_search_partition') && - response.request().method() === 'POST' - ); - - const searchPartitionResponse = await searchPartitionPromise; - const searchPartitionData = await searchPartitionResponse.json(); - - expect(searchPartitionData).toHaveProperty('partitions'); - expect(searchPartitionData).toHaveProperty('histogram_interval'); - expect(searchPartitionData).toHaveProperty('order_by', 'asc'); - - return searchPartitionData; -} - -async captureSearchCalls() { - const searchCalls = []; - this.page.on('response', async response => { - if (response.url().includes('/api/default/_search') && - response.request().method() === 'POST') { - const requestData = await response.request().postDataJSON(); - searchCalls.push({ - start_time: requestData.query.start_time, - end_time: requestData.query.end_time, - sql: requestData.query.sql - }); - } - }); - await this.page.waitForTimeout(2000); - return searchCalls; -} - -async verifyStreamingModeResponse() { - const searchPromise = this.page.waitForResponse(response => - response.url().includes('/api/default/_search') && - response.request().method() === 'POST' - ); - - const searchResponse = await searchPromise; - expect(searchResponse.status()).toBe(200); - - const searchData = await searchResponse.json(); - expect(searchData).toBeDefined(); - expect(searchData.hits).toBeDefined(); -} - -async clickExplore() { - try { - // Wait for the explore button to be visible and clickable - await this.exploreButton.first().waitFor({ state: 'visible', timeout: 10000 }); - await this.exploreButton.first().waitFor({ state: 'attached', timeout: 10000 }); - - // Click the button and wait for any network requests to complete - await Promise.all([ - this.page.waitForLoadState('networkidle'), - this.exploreButton.first().click() - ]); - - // Wait for the results to load - await this.page.waitForTimeout(3000); - } catch (error) { - console.error('Error in clickExplore:', error); - throw error; - } -} - -async openTimestampMenu() { - try { - // Wait for the table to be visible first - await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { state: 'visible', timeout: 10000 }); - - // Wait for the timestamp column to be visible - await this.page.waitForSelector('[data-test="log-table-column-1-_timestamp"]', { state: 'visible', timeout: 10000 }); - - // Wait for the menu button to be visible and clickable - await this.timestampColumnMenu.waitFor({ state: 'visible', timeout: 10000 }); - - // Ensure the menu button is in viewport - await this.timestampColumnMenu.scrollIntoViewIfNeeded(); - - // Click the menu and wait for any network requests to complete - await Promise.all([ - this.page.waitForLoadState('networkidle'), - this.timestampColumnMenu.click({ force: true }) - ]); - - // Wait for the menu to open - await this.page.waitForTimeout(1000); - } catch (error) { - console.error('Error in openTimestampMenu:', error); - // Try alternative approach if first attempt fails - try { - await this.page.waitForTimeout(2000); // Give more time for the table to load - await this.timestampColumnMenu.click({ force: true }); - await this.page.waitForTimeout(1000); - } catch (retryError) { - console.error('Error in openTimestampMenu retry:', retryError); - throw retryError; - } - } -} - -async clickResultsPerPage() { - // Click the dropdown to open the options - await this.page.locator('[data-test="logs-search-search-result"]').getByText('arrow_drop_down').click(); - await this.page.getByText('10', { exact: true }).click(); - await this.page.waitForTimeout(2000); - await expect(this.page.locator('[data-test="logs-search-search-result"]')).toContainText('Showing 1 to 10 out of'); -} - -async selectResultsPerPageAndVerify(resultsPerPage, expectedText) { - - await this.page.getByText(resultsPerPage, { exact: true }).click(); - await this.page.waitForTimeout(2000); - await expect(this.page.locator('[data-test="logs-search-search-result"]')).toContainText(expectedText); -} - -async pageNotVisible() { - - const fastRewindElement = this.page.locator('[data-test="logs-search-result-records-per-page"]').getByText('50'); - await expect(fastRewindElement).not.toBeVisible(); -} - -async verifyLogCountOrdering(orderType) { - // Type and execute the query - const query = orderType === 'desc' - ? `SELECT MAX(_timestamp) as ts, count(_timestamp) as logcount,kubernetes_container_name FROM 'e2e_automate' where log is not null GROUP BY kubernetes_container_name order by logcount desc` - : `SELECT MAX(_timestamp) as ts, count(_timestamp) as logcount,kubernetes_container_name FROM 'e2e_automate' where log is not null GROUP BY kubernetes_container_name order by logcount asc`; - - await this.clearAndFillQueryEditor(query); - await this.page.waitForTimeout(2000); - - // Enable SQL mode if not already enabled - const sqlModeSwitch = this.page.getByRole('switch', { name: 'SQL Mode' }); - const isSqlEnabled = await sqlModeSwitch.isChecked(); - if (!isSqlEnabled) { - await sqlModeSwitch.click(); - await this.page.waitForTimeout(1000); - } - - // Run the query - await this.page.locator("[data-test='logs-search-bar-refresh-btn']").click({ force: true }); - await this.page.waitForTimeout(2000); - - // Get all table rows and verify order - const rows = await this.page.locator('[data-test^="logs-search-result-detail-"]').all(); - let previousValue = orderType === 'desc' ? Number.MAX_SAFE_INTEGER : Number.MIN_SAFE_INTEGER; - - for (const row of rows) { - const sourceCell = await row.locator('[data-test^="log-table-column-"][data-test$="-source"]').textContent(); - try { - const logcountMatch = sourceCell.match(/logcount":(\d+)/); - const currentValue = logcountMatch ? parseInt(logcountMatch[1]) : 0; - - if (orderType === 'desc') { - expect(currentValue).toBeLessThanOrEqual(previousValue); - } else { - expect(currentValue).toBeGreaterThanOrEqual(previousValue); - } - previousValue = currentValue; - } catch (error) { - console.error('Error parsing cell content:', sourceCell); - throw error; - } - } - - // Verify we have results - expect(rows.length).toBeGreaterThan(0); -} - -async verifyLogCountOrderingDescending() { - await this.verifyLogCountOrdering('desc'); -} - - async verifyLogCountOrderingAscending() { - await this.verifyLogCountOrdering('asc'); - } - - // String match ignore case methods - async searchWithStringMatchIgnoreCase(searchText) { - await this.page.locator(this.logsSearchBarQueryEditor).click(); - await this.page.keyboard.press(process.platform === "darwin" ? "Meta+A" : "Control+A"); - await this.page.keyboard.press("Backspace"); - await this.page.keyboard.type(`str_match_ignore_case('${searchText}')`); - await this.page.locator(this.searchBarRefreshButton).click(); - await this.page.waitForTimeout(3000); - await expect(this.page.locator(this.logTableColumnSource)).toBeVisible(); - } - - async setDateTimeTo15Minutes() { - await this.page.locator(this.dateTimeButton).click(); - await this.page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click(); - } -} diff --git a/tests/ui-testing/pages/logsPages/logsPage.js b/tests/ui-testing/pages/logsPages/logsPage.js new file mode 100644 index 0000000000..a21fe2899c --- /dev/null +++ b/tests/ui-testing/pages/logsPages/logsPage.js @@ -0,0 +1,1811 @@ +import { expect } from '@playwright/test'; +import { LogsQueryPage } from './logsQueryPage.js'; +import { LoginPage } from '../loginPage.js'; +import { IngestionPage } from '../ingestionPage.js'; +import { ManagementPage } from '../managementPage.js'; + +export class LogsPage { + constructor(page) { + this.page = page; + + // Initialize existing page objects + this.logsQueryPage = new LogsQueryPage(page); + this.loginPage = new LoginPage(page); + this.ingestionPage = new IngestionPage(page); + this.managementPage = new ManagementPage(page); + + // Locators + this.logsMenuItem = '[data-test="menu-link-\\/logs-item"]'; + this.homeButton = "[name ='home']"; + this.queryButton = "[data-test='logs-search-bar-refresh-btn']"; + this.queryEditor = '[data-test="logs-search-bar-query-editor"]'; + this.quickModeToggle = '[data-test="logs-search-bar-quick-mode-toggle-btn"]'; + this.sqlModeToggle = '[data-test="logs-search-bar-sql-mode-toggle-btn"]'; + this.sqlModeSwitch = { role: 'switch', name: 'SQL Mode' }; + this.dateTimeButton = '[data-test="date-time-btn"]'; + this.indexDropDown = '[data-test="log-search-index-list-select-stream"]'; + this.streamToggle = '[data-test="log-search-index-list-stream-toggle-default"] .q-toggle__inner'; + this.searchPartitionButton = '[data-test="logs-search-partition-btn"]'; + this.histogramToggle = '[data-test="logs-search-bar-show-histogram-toggle-btn"]'; + this.exploreButton = '[data-test="logs-search-explore-btn"]'; + this.timestampColumnMenu = '[data-test="log-table-column-1-_timestamp"] [data-test="table-row-expand-menu"]'; + this.resultText = '[data-test="logs-search-search-result"]'; + this.logTableColumnSource = '[data-test="log-table-column-0-source"]'; + this.logsSearchBarQueryEditor = '[data-test="logs-search-bar-query-editor"]'; + this.searchBarRefreshButton = '[data-cy="search-bar-refresh-button"] > .q-btn__content'; + this.relative15MinButton = '[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block'; + this.relative6WeeksButton = '[data-test="date-time-relative-6-w-btn"] > .q-btn__content'; + this.relative30SecondsButton = '[data-test="date-time-relative-30-s-btn"] > .q-btn__content > .block'; + this.absoluteTab = '[data-test="date-time-absolute-tab"]'; + this.scheduleText = '[data-test="date-time-btn"]'; + this.timeZoneDropdown = '[data-test="timezone-select"]'; + this.timeZoneOption = (zone) => `[data-test="timezone-option-${zone}"]`; + this.dateSelector = (day) => `[data-test="date-selector-${day}"]`; + this.monthSelector = (month) => `[data-test="month-selector-${month}"]`; + this.yearSelector = (year) => `[data-test="year-selector-${year}"]`; + this.startTimeField = '[data-test="start-time-field"]'; + this.endTimeField = '[data-test="end-time-field"]'; + this.startTimeInput = '[data-test="start-time-input"]'; + this.endTimeInput = '[data-test="end-time-input"]'; + this.showQueryToggle = '[data-test="logs-search-bar-show-query-toggle-btn"]'; + this.fieldListCollapseButton = '[data-test="logs-search-field-list-collapse-btn"]'; + this.savedViewsButton = '[data-test="logs-search-saved-views-btn"] > .q-btn-dropdown--current > .q-btn__content > :nth-child(1)'; + this.savedViewsExpand = '[data-test="logs-search-saved-views-btn"]'; + this.saveViewButton = 'button'; // filter by text in method + this.savedViewNameInput = '[data-test="add-alert-name-input"]'; + this.savedViewDialogSave = '[data-test="saved-view-dialog-save-btn"]'; + this.savedViewArrow = '[data-test="logs-search-saved-views-btn"] > .q-btn-dropdown__arrow-container > .q-btn__content > .q-icon'; + this.savedViewSearchInput = '[data-test="log-search-saved-view-field-search-input"]'; + this.confirmButton = '[data-test="confirm-button"]'; + this.streamsMenuItem = '[data-test="menu-link-\\/streams-item"]'; + this.searchStreamInput = '[placeholder="Search Stream"]'; + this.exploreButtonRole = { role: 'button', name: 'Explore' }; + this.resetFiltersButton = '[data-test="logs-search-bar-reset-filters-btn"]'; + this.includeExcludeFieldButton = ':nth-child(1) > [data-test="log-details-include-exclude-field-btn"] > .q-btn__content > .q-icon'; + this.includeFieldButton = '[data-test="log-details-include-field-btn"]'; + this.closeDialog = '[data-test="close-dialog"] > .q-btn__content'; + this.savedViewDialogSaveContent = '[data-test="saved-view-dialog-save-btn"] > .q-btn__content'; + this.savedViewByLabel = '.q-item__label'; + this.notificationMessage = '.q-notification__message'; + this.indexFieldSearchInput = '[data-cy="index-field-search-input"]'; + this.errorMessage = '[data-test="logs-search-error-message"]'; + this.warningElement = 'text=warning Query execution'; + this.logsTable = '[data-test="logs-search-result-logs-table"]'; + this.barChartCanvas = '[data-test="logs-search-result-bar-chart"] canvas'; + this.expandLabel = label => `Expand "${label}"`; + this.collapseLabel = label => `Collapse "${label}"`; + this.addStreamButton = '[data-test="log-stream-add-stream-btn"]'; + this.addStreamNameInput = '[data-test="add-stream-name-input"]'; + this.saveStreamButton = '[data-test="save-stream-btn"]'; + this.streamDetail = '[title="Stream Detail"]'; + this.schemaStreamIndexSelect = ':nth-child(2) > [data-test="schema-stream-index-select"]'; + this.fullTextSearch = '.q-virtual-scroll__content'; + this.schemaUpdateSettingsButton = '[data-test="schema-update-settings-button"]'; + this.colAutoButton = '.col-auto > .q-btn > .q-btn__content'; + this.exploreTitle = '[title="Explore"]'; + this.streamsSearchStreamInput = '[data-test="streams-search-stream-input"]'; + this.logSearchIndexListFieldSearchInput = '[data-test="log-search-index-list-field-search-input"]'; + this.expandCode = 'Expand "code"'; + this.logsDetailTableSearchAroundBtn = '[data-test="logs-detail-table-search-around-btn"]'; + this.logTableColumn3Source = '[data-test="log-table-column-3-source"]'; + this.histogramToggleDiv = '[data-test="logs-search-bar-show-histogram-toggle-btn"] div'; + + // Additional locators + this.fnEditor = '#fnEditor'; + this.searchListFirstTextLeft = '.search-list > :nth-child(1) > .text-left'; + this.liveModeToggleBtn = '[data-test="logs-search-bar-refresh-interval-btn-dropdown"]'; + this.liveMode5SecBtn = '[data-test="logs-search-bar-refresh-time-5"]'; + this.vrlToggleBtn = '[data-test="logs-search-bar-vrl-toggle-btn"]'; + this.vrlToggleButton = '[data-test="logs-search-bar-show-query-toggle-btn"] img'; + this.vrlEditor = '[data-test="logs-vrl-function-editor"]'; + this.relative6DaysBtn = '[data-test="date-time-relative-6-d-btn"] > .q-btn__content'; + this.menuLink = link => `[data-test="menu-link-${link}"]`; + this.searchAroundBtn = '[data-test="logs-search-bar-search-around-btn"]'; + this.pagination = '[data-test="logs-search-pagination"]'; + this.sqlPagination = '[data-test="logs-search-sql-pagination"]'; + this.sqlGroupOrderLimitPagination = '[data-test="logs-search-sql-group-order-limit-pagination"]'; + this.interestingFieldBtn = field => `[data-test="log-search-index-list-interesting-${field}-field-btn"]`; + this.logsSearchBarFunctionDropdownSave = '[data-test="logs-search-bar-function-dropdown"] button'; + this.savedFunctionNameInput = '[data-test="saved-function-name-input"]'; + this.qNotifyWarning = '#q-notify div'; + this.qPageContainer = '.q-page-container'; + this.cmContent = '.cm-content'; + this.cmLine = '.cm-line'; + this.searchFunctionInput = { placeholder: 'Search Function' }; + } + + + + // Reusable helper methods for code reuse + async expectQueryEditorContainsTextHelper(text) { + return await expect(this.page.locator(this.queryEditor)).toContainText(text); + } + + async clickMenuLinkByType(linkType) { + const linkMap = { + 'logs': this.logsMenuItem, + 'traces': '[data-test="menu-link-/traces-item"]', + 'streams': this.streamsMenuItem, + 'metrics': '[data-test="menu-link-\\/metrics-item"]', + 'pipeline': '[data-test="menu-link-\\/pipeline-item"]', + 'functions': '[data-test="menu-link-\\/functions-item"]' + }; + return await this.page.locator(linkMap[linkType]).click({ force: true }); + } + + async fillInputField(selector, text) { + return await this.page.locator(selector).fill(text); + } + + async clickElementByLabel(label, action = 'Expand') { + const labelText = action === 'Expand' ? this.expandLabel(label) : this.collapseLabel(label); + return await this.page.getByLabel(labelText).click(); + } + + async expectKubernetesPodContent(podType, ingesterNumber = '') { + const content = `kubernetes_${podType}${ingesterNumber ? `-ziox-ingester-${ingesterNumber}` : ''}`; + return await this.expectQueryEditorContainsTextHelper(content); + } + + // Navigation methods + async navigateToLogs(orgIdentifier) { + const logsUrl = '/web/logs'; // Using the same pattern as in test files + const orgId = orgIdentifier || process.env["ORGNAME"]; + await this.page.goto(`${logsUrl}?org_identifier=${orgId}`); + } + + async validateLogsPage() { + await expect(this.page).toHaveURL(/.*\/logs/); + } + + async logsPageDefaultMultiOrg() { + await this.page.goto('/logs'); + await expect(this.page).toHaveURL(/.*\/logs/); + } + + async logsPageURLValidation() { + await expect(this.page).toHaveURL(/.*\/logs/); + } + + // Stream and index selection methods + async selectIndexAndStream() { + await this.page.locator(this.indexDropDown).click(); + await this.page.locator(this.streamToggle).click(); + } + + async selectIndexAndStreamJoin() { + await this.page.locator('[data-test="logs-search-index-list"]').getByText('arrow_drop_down').click(); + await this.page.waitForTimeout(3000); + await this.page.locator('[data-test="log-search-index-list-stream-toggle-default"] div').first().click(); + await this.page.waitForTimeout(1000); + await this.page.locator('[data-test="logs-search-index-list"]').getByText('arrow_drop_down').click(); + } + + async selectIndexStreamDefault() { + await this.page.locator('[data-test="logs-search-index-list"]').getByText('arrow_drop_down').click(); + await this.page.waitForTimeout(3000); + await this.page.locator('[data-test="log-search-index-list-stream-toggle-default"] div').first().click(); + } + + async selectIndexStream(streamName) { + console.log(`[DEBUG] selectIndexStream: Starting selection for stream: ${streamName}`); + try { + await this.page.locator(this.indexDropDown).waitFor({ timeout: 10000 }); + await this.page.locator(this.indexDropDown).click(); + console.log(`[DEBUG] selectIndexStream: Clicked dropdown`); + await this.page.waitForTimeout(2000); + + await this.page.locator(this.streamToggle).waitFor({ timeout: 10000 }); + await this.page.locator(this.streamToggle).click(); + console.log(`[DEBUG] selectIndexStream: Successfully selected stream with default method`); + } catch (error) { + console.log(`[DEBUG] Failed to select stream with default method, trying alternative approach: ${error.message}`); + // Fallback to the old method + await this.selectIndexStreamOld(streamName); + } + } + + async selectStream(stream) { + await this.page.locator(this.indexDropDown).click(); + await this.page.getByText(stream, { exact: true }).first().click(); + } + + async selectIndexStreamOld(streamName) { + console.log(`[DEBUG] selectIndexStreamOld: Starting selection for stream: ${streamName}`); + try { + // Click the dropdown + await this.page.locator('[data-test="logs-search-index-list"]').getByText('arrow_drop_down').click(); + console.log(`[DEBUG] selectIndexStreamOld: Clicked dropdown`); + await this.page.waitForTimeout(2000); + + // Quick attempt to find and click the stream by text + console.log(`[DEBUG] selectIndexStreamOld: Trying to find stream by text: ${streamName}`); + await this.page.getByText(streamName, { exact: true }).first().click({ timeout: 5000 }); + console.log(`[DEBUG] selectIndexStreamOld: Successfully selected stream by text: ${streamName}`); + + } catch (error) { + console.log(`[DEBUG] selectIndexStreamOld: Failed to select stream ${streamName}: ${error.message}`); + + // Quick fallback: just select the first available stream + console.log(`[DEBUG] selectIndexStreamOld: Trying to select first available stream as fallback`); + try { + await this.page.locator('[data-test*="log-search-index-list-stream-toggle-"]').first().click({ timeout: 5000 }); + console.log(`[DEBUG] selectIndexStreamOld: Selected first available stream as fallback`); + } catch (fallbackError) { + console.log(`[DEBUG] selectIndexStreamOld: Fallback also failed: ${fallbackError.message}`); + // Don't throw error, just log it and continue + console.log(`[DEBUG] selectIndexStreamOld: Continuing without stream selection`); + } + } + } + + // Helper method to ensure query editor is ready + async ensureQueryEditorReady() { + // Wait for the query editor to be visible and ready + await this.page.locator(this.queryEditor).waitFor({ + state: 'visible', + timeout: 10000 + }); + + // Wait a moment for any UI updates + await this.page.waitForTimeout(1000); + } + + // Query execution methods + async selectRunQuery() { + // Ensure query editor is ready + await this.ensureQueryEditorReady(); + + // Wait for the query button to be visible and click it + await this.page.locator(this.queryButton).waitFor({ state: 'visible', timeout: 10000 }); + + // Add a small wait to ensure the button is fully ready + await this.page.waitForTimeout(1000); + + await this.page.locator(this.queryButton).click(); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async applyQuery() { + await this.page.locator(this.queryButton).click(); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async applyQueryButton(expectedUrl) { + await this.page.locator(this.queryButton).click(); + await expect(this.page).toHaveURL(expectedUrl); + } + + async clearAndRunQuery() { + await this.page.locator(this.queryEditor).click(); + await this.page.keyboard.press(process.platform === "darwin" ? "Meta+A" : "Control+A"); + await this.page.keyboard.press("Backspace"); + await this.page.locator(this.queryButton).click(); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async clearAndFillQueryEditor(query) { + await this.page.locator(this.queryEditor).click(); + await this.page.keyboard.press(process.platform === "darwin" ? "Meta+A" : "Control+A"); + await this.page.keyboard.press("Backspace"); + await this.page.keyboard.type(query); + } + + async typeQuery(query) { + await this.page.locator(this.queryEditor).click(); + await this.page.locator(this.queryEditor).press('ControlOrMeta+a'); + await this.page.keyboard.type(query); + } + + async executeQueryWithKeyboardShortcut() { + await this.page.keyboard.press(process.platform === "darwin" ? "Meta+Enter" : "Control+Enter"); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async executeQueryWithKeyboardShortcutTest() { + await this.page.locator(this.queryEditor).click(); + await this.page.keyboard.type("SELECT * FROM 'e2e_automate' LIMIT 10"); + await this.page.keyboard.press(process.platform === "darwin" ? "Meta+Enter" : "Control+Enter"); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async executeQueryWithKeyboardShortcutAfterClickingElsewhere() { + await this.page.locator(this.queryEditor).click(); + await this.page.keyboard.type("SELECT * FROM 'e2e_automate' LIMIT 10"); + await this.page.locator(this.homeButton).click(); + await this.page.keyboard.press(process.platform === "darwin" ? "Meta+Enter" : "Control+Enter"); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async executeQueryWithKeyboardShortcutWithDifferentQuery() { + await this.page.locator(this.queryEditor).click(); + await this.page.keyboard.press(process.platform === "darwin" ? "Meta+A" : "Control+A"); + await this.page.keyboard.press("Backspace"); + await this.page.keyboard.type("SELECT * FROM 'e2e_automate' WHERE log LIKE '%test%' LIMIT 5"); + await this.page.keyboard.press(process.platform === "darwin" ? "Meta+Enter" : "Control+Enter"); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async executeQueryWithKeyboardShortcutWithSQLMode() { + await this.page.locator(this.sqlModeToggle).first().click(); + await this.page.locator(this.queryEditor).click(); + await this.page.keyboard.type("SELECT * FROM 'e2e_automate' LIMIT 10"); + await this.page.keyboard.press(process.platform === "darwin" ? "Meta+Enter" : "Control+Enter"); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async executeQueryWithErrorHandling() { + await this.page.locator(this.queryEditor).click(); + await this.page.keyboard.type("INVALID QUERY"); + await this.page.locator(this.queryButton).click(); + } + + async executeHistogramQuery(query) { + await this.clearAndFillQueryEditor(query); + await this.page.locator(this.queryButton).click(); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async waitForSearchResultAndCheckText(expectedText) { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]'); + await expect(this.page.locator('[data-test="logs-search-result-logs-table"]')).toContainText(expectedText); + } + + // Time and date methods + async setTimeToPast30Seconds() { + await this.page.locator(this.dateTimeButton).click(); + await this.page.locator(this.relative30SecondsButton).click(); + } + + async verifyTimeSetTo30Seconds() { + await expect(this.page.locator(this.scheduleText)).toContainText('Past 30 Seconds'); + } + + async setDateTime() { + await this.page.locator(this.dateTimeButton).click(); + } + + async setDateTimeToToday() { + await this.page.locator(this.dateTimeButton).click(); + await this.page.locator(this.absoluteTab).click(); + } + + async setDateTimeTo15Minutes() { + await this.page.locator(this.dateTimeButton).click(); + await this.page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click(); + } + + async setAbsoluteDate(year, month, day, currentMonth, currentYear) { + await this.page.locator(this.dateTimeButton).click(); + await this.page.locator(this.absoluteTab).click(); + await this.page.locator(this.monthSelector(currentMonth)).click(); + await this.page.locator(this.yearSelector(currentYear)).click(); + await this.page.locator(this.dateSelector(day)).click(); + } + + async setStartAndEndTime(startTime, endTime) { + await this.page.locator(this.startTimeField).fill(startTime); + await this.page.locator(this.endTimeField).fill(endTime); + } + + async setTimeRange(startTime, endTime) { + await this.setStartAndEndTime(startTime, endTime); + } + + async verifySchedule(expectedTime) { + await expect(this.page.locator(this.scheduleText)).toContainText(expectedTime); + } + + async setTimeZone(zone) { + await this.page.locator(this.timeZoneDropdown).click(); + await this.page.locator(this.timeZoneOption(zone)).click(); + } + + async changeTimeZone() { + await this.setTimeZone('UTC'); + } + + async verifyDateTime(startTime, endTime) { + await expect(this.page.locator(this.startTimeInput)).toHaveValue(startTime); + await expect(this.page.locator(this.endTimeInput)).toHaveValue(endTime); + } + + async getScheduleText() { + return await this.page.locator(this.scheduleText).textContent(); + } + + // SQL Mode methods + async enableSQLMode() { + await this.page.locator(this.sqlModeToggle).first().click(); + } + + // Quick Mode methods + async verifyQuickModeToggle() { + await expect(this.page.locator(this.quickModeToggle)).toBeVisible(); + } + + async clickQuickModeToggle() { + await this.page.locator(this.quickModeToggle).click(); + } + + // Histogram methods + async toggleHistogram() { + await this.page.locator(this.histogramToggle).click(); + } + + async toggleHistogramAndExecute() { + await this.toggleHistogram(); + await this.page.locator(this.queryButton).click(); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async verifyHistogramState() { + const isHistogramOff = await this.page.locator(this.histogramToggle) + .evaluate(el => el.getAttribute('aria-checked') === 'false'); + expect(isHistogramOff).toBeTruthy(); + } + + // Error handling methods + async checkErrorVisible() { + await expect(this.page.locator(this.errorMessage)).toBeVisible(); + } + + async getErrorDetails() { + return await this.page.locator(this.errorMessage).textContent(); + } + + // Search partition methods + async clickRunQueryButton() { + await this.page.locator("[data-test='logs-search-bar-refresh-btn']").click({ force: true }); + } + + async verifySearchPartitionResponse() { + const searchPartitionPromise = this.page.waitForResponse(response => + response.url().includes('/api/default/_search_partition') && + response.request().method() === 'POST' + ); + + const searchPartitionResponse = await searchPartitionPromise; + const searchPartitionData = await searchPartitionResponse.json(); + + expect(searchPartitionData).toHaveProperty('partitions'); + expect(searchPartitionData).toHaveProperty('histogram_interval'); + expect(searchPartitionData).toHaveProperty('order_by', 'asc'); + + return searchPartitionData; + } + + async captureSearchCalls() { + const searchCalls = []; + + // Create the event listener function + const responseHandler = async response => { + if (response.url().includes('/api/default/_search') && + response.request().method() === 'POST') { + const requestData = await response.request().postDataJSON(); + searchCalls.push({ + start_time: requestData.query.start_time, + end_time: requestData.query.end_time, + sql: requestData.query.sql + }); + } + }; + + // Attach the event listener + this.page.on('response', responseHandler); + + try { + await this.page.waitForTimeout(2000); + return searchCalls; + } finally { + // Always remove the event listener to prevent memory leaks + this.page.removeListener('response', responseHandler); + } + } + + async verifyStreamingModeResponse() { + console.log("[DEBUG] Waiting for search response..."); + const searchPromise = this.page.waitForResponse(response => { + const url = response.url(); + const method = response.request().method(); + console.log(`[DEBUG] Response: ${method} ${url}`); + return url.includes('/api/default/_search') && method === 'POST'; + }); + + const searchResponse = await searchPromise; + console.log(`[DEBUG] Search response status: ${searchResponse.status()}`); + expect(searchResponse.status()).toBe(200); + + const searchData = await searchResponse.json(); + console.log("[DEBUG] Search response data:", JSON.stringify(searchData, null, 2)); + console.log("[DEBUG] searchData type:", typeof searchData); + console.log("[DEBUG] searchData keys:", Object.keys(searchData || {})); + expect(searchData).toBeDefined(); + + // Check if this is a partition response (non-streaming) or streaming response + if (searchData.partitions) { + console.log("[DEBUG] Received partition response (non-streaming mode)"); + expect(searchData.partitions).toBeDefined(); + expect(searchData.histogram_interval).toBeDefined(); + } else if (searchData.hits) { + console.log("[DEBUG] Received streaming response"); + expect(searchData.hits).toBeDefined(); + } else { + console.log("[DEBUG] Unexpected response structure:", JSON.stringify(searchData, null, 2)); + throw new Error(`Unexpected response structure: ${JSON.stringify(searchData)}`); + } + } + + // Explore and results methods + async clickExplore() { + try { + await this.page.locator(this.exploreButton).first().waitFor({ state: 'visible', timeout: 10000 }); + await this.page.locator(this.exploreButton).first().waitFor({ state: 'attached', timeout: 10000 }); + + await Promise.all([ + this.page.waitForLoadState('networkidle'), + this.page.locator(this.exploreButton).first().click() + ]); + + await this.page.waitForTimeout(3000); + } catch (error) { + console.error('Error in clickExplore:', error); + throw error; + } + } + + async openTimestampMenu() { + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { state: 'visible', timeout: 10000 }); + await this.page.waitForSelector('[data-test="log-table-column-1-_timestamp"]', { state: 'visible', timeout: 10000 }); + await this.timestampColumnMenu.waitFor({ state: 'visible', timeout: 10000 }); + await this.timestampColumnMenu.scrollIntoViewIfNeeded(); + + await Promise.all([ + this.page.waitForLoadState('networkidle'), + this.timestampColumnMenu.click({ force: true }) + ]); + + await this.page.waitForTimeout(1000); + } catch (error) { + console.error('Error in openTimestampMenu:', error); + try { + await this.page.waitForTimeout(2000); + await this.timestampColumnMenu.click({ force: true }); + await this.page.waitForTimeout(1000); + } catch (retryError) { + console.error('Error in openTimestampMenu retry:', retryError); + throw retryError; + } + } + } + + async clickResultsPerPage() { + await this.page.locator('[data-test="logs-search-search-result"]').getByText('arrow_drop_down').click(); + await this.page.getByText('10', { exact: true }).click(); + await this.page.waitForTimeout(2000); + await expect(this.page.locator('[data-test="logs-search-search-result"]')).toContainText('Showing 1 to 10 out of'); + } + + async selectResultsPerPageAndVerify(resultsPerPage, expectedText) { + await this.page.getByText(resultsPerPage, { exact: true }).click(); + await this.page.waitForTimeout(3000); // Increased wait time for UI update + + // Use flexible assertions based on the results per page + let expectedPattern; + switch (resultsPerPage) { + case '2': + expectedPattern = 'Showing 11 to 20 out of'; + break; + case '3': + expectedPattern = 'Showing 21 to 30 out of'; + break; + case '4': + expectedPattern = 'Showing 31 to'; + break; + default: + expectedPattern = expectedText; + } + + // Use a more flexible assertion that checks for the pattern rather than exact text + await expect(this.page.locator('[data-test="logs-search-search-result"]')).toContainText(expectedPattern); + } + + async pageNotVisible() { + const fastRewindElement = this.page.locator('[data-test="logs-search-result-records-per-page"]').getByText('50'); + await expect(fastRewindElement).not.toBeVisible(); + } + + // Validation methods + async validateResult() { + try { + // Wait for the logs table with a longer timeout for streaming mode + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 45000, // Increased timeout for streaming mode + state: 'visible' + }); + await expect(this.page.locator('[data-test="logs-search-result-logs-table"]')).toBeVisible(); + } catch (error) { + console.error('Error in validateResult:', error); + // Check if there's an error message visible + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + const errorText = await errorMessage.textContent(); + console.error('Error message found:', errorText); + throw new Error(`Query failed with error: ${errorText}`); + } + // Check if there's a "no data found" message + const noDataMessage = this.page.getByText('No data found'); + if (await noDataMessage.isVisible()) { + console.log('No data found for the query'); + return; // This is acceptable for some queries + } + throw error; + } + } + + async displayCountQuery() { + await this.clearAndFillQueryEditor("SELECT COUNT(*) as count FROM 'e2e_automate'"); + + // Ensure query editor is ready + await this.ensureQueryEditorReady(); + + // Wait for the query button to be visible and click it + await this.page.locator(this.queryButton).waitFor({ state: 'visible', timeout: 10000 }); + await this.page.locator(this.queryButton).click(); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + async displayTwoStreams() { + await this.clearAndFillQueryEditor("SELECT * FROM 'e2e_automate' UNION ALL SELECT * FROM 'e2e_automate'"); + + // Ensure query editor is ready + await this.ensureQueryEditorReady(); + + // Wait for the query button to be visible and click it + await this.page.locator(this.queryButton).waitFor({ state: 'visible', timeout: 10000 }); + await this.page.locator(this.queryButton).click(); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + } + + // Interesting fields methods + async clickInterestingFields() { + await this.fillIndexFieldSearchInput('kubernetes_pod_name'); + await this.page.locator('[data-test="log-search-index-list-interesting-kubernetes_pod_name-field-btn"]').first().click(); + } + + async validateInterestingFields() { + await expect(this.page.locator(this.queryEditor)).toContainText('kubernetes_pod_name'); + } + + async validateInterestingFieldsQuery() { + await expect(this.page.locator(this.queryEditor)).toContainText('kubernetes_pod_name'); + } + + async addRemoveInteresting() { + await this.clickInterestingFields(); + await this.page.locator('[data-test="log-search-index-list-interesting-kubernetes_pod_name-field-btn"]').first().click(); + } + + // Kubernetes methods + async kubernetesContainerName() { + await this.page.getByLabel('Expand "kubernetes_container_name"').click(); + await this.page.waitForTimeout(5000); + await this.page.locator('[data-test="logs-search-subfield-add-kubernetes_container_name-ziox"] [data-test="log-search-subfield-list-equal-kubernetes_container_name-field-btn"]').click(); + } + + async kubernetesContainerNameJoin() { + await this.page + .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') + .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a join "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name'); + await this.page.waitForTimeout(5000); + } + + async kubernetesContainerNameJoinLimit() { + await this.page + .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') + .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a left join "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name LIMIT 10'); + await this.page.waitForTimeout(5000); + } + + async kubernetesContainerNameJoinLike() { + await this.page + .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') + .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a join "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name WHERE a.kubernetes_container_name LIKE "%ziox%"'); + await this.page.waitForTimeout(5000); + } + + async kubernetesContainerNameLeftJoin() { + await this.page + .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') + .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a LEFT JOIN "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name'); + await this.page.waitForTimeout(5000); + } + + async kubernetesContainerNameRightJoin() { + await this.page + .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') + .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a RIGHT JOIN "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name'); + await this.page.waitForTimeout(5000); + } + + async kubernetesContainerNameFullJoin() { + await this.page + .locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox') + .fill('SELECT a.kubernetes_container_name , b.kubernetes_container_name FROM "default" as a FULL JOIN "e2e_automate" as b on a.kubernetes_container_name = b.kubernetes_container_name'); + await this.page.waitForTimeout(5000); + } + + // Log count ordering methods + async verifyLogCountOrdering(orderType) { + const query = orderType === 'desc' + ? `SELECT MAX(_timestamp) as ts, count(_timestamp) as logcount,kubernetes_container_name FROM 'e2e_automate' where log is not null GROUP BY kubernetes_container_name order by logcount desc` + : `SELECT MAX(_timestamp) as ts, count(_timestamp) as logcount,kubernetes_container_name FROM 'e2e_automate' where log is not null GROUP BY kubernetes_container_name order by logcount asc`; + + await this.clearAndFillQueryEditor(query); + await this.page.waitForTimeout(2000); + + const sqlModeSwitch = this.page.getByRole('switch', { name: 'SQL Mode' }); + const isSqlEnabled = await sqlModeSwitch.isChecked(); + if (!isSqlEnabled) { + await sqlModeSwitch.click(); + await this.page.waitForTimeout(1000); + } + + await this.page.locator("[data-test='logs-search-bar-refresh-btn']").click({ force: true }); + + // Wait for query execution and results to load + await this.page.waitForTimeout(3000); + + // Wait for either the logs table to appear or an error message + try { + await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', { + timeout: 15000, + state: 'visible' + }); + } catch (error) { + // If logs table doesn't appear, check for error message + const errorMessage = this.page.locator(this.errorMessage); + if (await errorMessage.isVisible()) { + console.log('Query completed with error message'); + } else { + // Wait a bit more for any UI updates + await this.page.waitForTimeout(2000); + } + } + + const rows = await this.page.locator('[data-test^="logs-search-result-detail-"]').all(); + let previousValue = orderType === 'desc' ? Number.MAX_SAFE_INTEGER : Number.MIN_SAFE_INTEGER; + + for (const row of rows) { + const sourceCell = await row.locator('[data-test^="log-table-column-"][data-test$="-source"]').textContent(); + try { + const logcountMatch = sourceCell.match(/logcount":(\d+)/); + const currentValue = logcountMatch ? parseInt(logcountMatch[1]) : 0; + + if (orderType === 'desc') { + expect(currentValue).toBeLessThanOrEqual(previousValue); + } else { + expect(currentValue).toBeGreaterThanOrEqual(previousValue); + } + previousValue = currentValue; + } catch (error) { + console.error('Error parsing cell content:', sourceCell); + throw error; + } + } + + expect(rows.length).toBeGreaterThan(0); + } + + async verifyLogCountOrderingDescending() { + await this.verifyLogCountOrdering('desc'); + } + + async verifyLogCountOrderingAscending() { + await this.verifyLogCountOrdering('asc'); + } + + // String match ignore case methods + async searchWithStringMatchIgnoreCase(searchText) { + await this.page.locator(this.logsSearchBarQueryEditor).click(); + await this.page.keyboard.press(process.platform === "darwin" ? "Meta+A" : "Control+A"); + await this.page.keyboard.press("Backspace"); + await this.page.keyboard.type(`str_match_ignore_case(kubernetes_labels_app, '${searchText}')`); + await this.page.locator(this.searchBarRefreshButton).click(); + + // Wait for search results to load + await this.page.waitForTimeout(3000); + + // Wait for the log table to be visible first + await this.page.locator('[data-test="logs-search-result-logs-table"]').waitFor({ state: 'visible', timeout: 10000 }); + + // Wait for the specific column to be visible + await this.page.locator(this.logTableColumnSource).waitFor({ state: 'visible', timeout: 10000 }); + + // Verify the column is visible + await expect(this.page.locator(this.logTableColumnSource)).toBeVisible(); + } + + // Organization methods + async selectOrganization() { + await this.page.locator('[data-test="navbar-organizations-select"]').click(); + await this.page.getByRole('option', { name: 'default', exact: true }).locator('div').nth(2).click(); + } + + // Copy share methods + async copyShare() { + await this.page.locator('[data-test="header-my-account-profile-icon"]').click(); + await this.page.getByText('Copy Share').click(); + } + + // Sign out methods + async signOut() { + await this.page.locator('[data-test="header-my-account-profile-icon"]').click(); + await this.page.getByText('Sign Out').click(); + } + + // LogsQueryPage methods - delegate to LogsQueryPage + async setDateTimeFilter() { + return await this.logsQueryPage.setDateTimeFilter(); + } + + async clickRefresh() { + return await this.logsQueryPage.clickRefresh(); + } + + async clickErrorMessage() { + return await this.logsQueryPage.clickErrorMessage(); + } + + async clickResetFilters() { + return await this.logsQueryPage.clickResetFilters(); + } + + async clickNoDataFound() { + return await this.logsQueryPage.clickNoDataFound(); + } + + async clickResultDetail() { + return await this.page.locator(this.resultText).click(); + } + + async isHistogramOn() { + return await this.logsQueryPage.isHistogramOn(); + } + + async ensureHistogramState(desiredState) { + return await this.logsQueryPage.ensureHistogramState(desiredState); + } + + // Login methods - delegate to LoginPage + async loginAsInternalUser() { + return await this.loginPage.loginAsInternalUser(); + } + + async login() { + return await this.loginPage.login(); + } + + // Ingestion methods - delegate to IngestionPage + async ingestLogs(orgId, streamName, logData) { + return await this.ingestionPage.ingestLogs(orgId, streamName, logData); + } + + // Management methods - delegate to ManagementPage + async navigateToManagement() { + return await this.managementPage.navigateToManagement(); + } + + // Additional methods needed for tests + async clickDateTimeButton() { + return await this.page.locator(this.dateTimeButton).click({ force: true }); + } + + async clickRelative15MinButton() { + return await this.page.locator(this.relative15MinButton).click({ force: true }); + } + + async clickRelative6WeeksButton() { + return await this.page.locator(this.relative6WeeksButton).click({ force: true }); + } + + async clickQueryEditor() { + return await this.page.locator(this.queryEditor).click(); + } + + async clickQueryEditorTextbox() { + return await this.page.locator(this.queryEditor).getByRole('textbox').click(); + } + + async fillQueryEditor(query) { + return await this.page.locator(this.queryEditor).getByRole('textbox').fill(query); + } + + async typeInQueryEditor(text) { + return await this.page.keyboard.type(text); + } + + async clickRefreshButton() { + return await this.page.locator(this.queryButton).click({ force: true }); + } + + async clickSearchBarRefreshButton() { + return await this.page.locator(this.searchBarRefreshButton).click({ force: true }); + } + + async waitForSearchBarRefreshButton() { + return await this.page.locator(this.searchBarRefreshButton).waitFor({ state: "visible" }); + } + + async clickSQLModeToggle() { + return await this.page.getByRole(this.sqlModeSwitch.role, { name: this.sqlModeSwitch.name }).locator('div').first().click(); + } + + async clickShowQueryToggle() { + return await this.page.locator(this.showQueryToggle).click({ force: true }); + } + + async clickFieldListCollapseButton() { + return await this.page.locator(this.fieldListCollapseButton).click(); + } + + async clickSavedViewsButton() { + return await this.page.locator(this.savedViewsButton).click({ force: true }); + } + + async clickSavedViewsExpand() { + return await this.page.locator(this.savedViewsExpand).getByLabel('Expand').click(); + } + + async clickSaveViewButton() { + return await this.page.locator(this.saveViewButton).filter({ hasText: 'savesaved_search' }).click(); + } + + async fillSavedViewName(name) { + return await this.fillInputField(this.savedViewNameInput, name); + } + + async clickSavedViewDialogSave() { + const saveButton = this.page.locator(this.savedViewDialogSave); + + // Wait for the button to be visible + await saveButton.waitFor({ state: 'visible', timeout: 10000 }); + + // Scroll the button into view if needed + await saveButton.scrollIntoViewIfNeeded(); + + // Wait a moment for the scroll to complete + await this.page.waitForTimeout(500); + + // Click the button with force option + return await saveButton.click({ force: true }); + } + + async clickSavedViewArrow() { + return await this.page.locator(this.savedViewArrow).click(); + } + + async clickSavedViewSearchInput() { + return await this.page.locator(this.savedViewSearchInput).click(); + } + + async fillSavedViewSearchInput(text) { + return await this.fillInputField(this.savedViewSearchInput, text); + } + + async clickSavedViewByTitle(title) { + return await this.page.getByTitle(title).click(); + } + + async clickDeleteButton() { + return await this.page.getByText('delete').click(); + } + + async clickConfirmButton() { + return await this.page.locator(this.confirmButton).click(); + } + + async clickStreamsMenuItem() { + return await this.page.locator(this.streamsMenuItem).click({ force: true }); + } + + async clickSearchStreamInput() { + return await this.page.locator(this.searchStreamInput).click(); + } + + async fillSearchStreamInput(text) { + return await this.fillInputField(this.searchStreamInput, text); + } + + async clickExploreButton() { + return await this.page.getByRole(this.exploreButtonRole.role, { name: this.exploreButtonRole.name }).first().click({ force: true }); + } + + async waitForSavedViewsButton() { + return await this.page.waitForSelector(this.savedViewsButton); + } + + async clickSavedViewByText(text) { + return await this.page.click(`:text("${text}")`); + } + + async waitForSavedViewText(text) { + return await this.page.waitForSelector(`:text("${text}")`); + } + + async clickDeleteSavedViewButton(savedViewName) { + const deleteButtonSelector = `[data-test="logs-search-bar-delete-${savedViewName}-saved-view-btn"]`; + return await this.page.locator(deleteButtonSelector).click(); + } + + async clickResetFiltersButton() { + return await this.page.locator(this.resetFiltersButton).click({ force: true }); + } + + async waitForQueryEditorTextbox() { + return await this.page.locator(this.queryEditor).getByRole('textbox').waitFor({ state: "visible" }); + } + + async getQueryEditorText() { + return await this.page.evaluate((selector) => { + const editor = document.querySelector(selector).querySelector('.cm-content'); + return editor ? editor.textContent : null; + }, this.queryEditor); + } + + async clickLogTableColumnSource() { + return await this.page.locator(this.logTableColumnSource).click(); + } + + async clickIncludeExcludeFieldButton() { + return await this.page.locator(this.includeExcludeFieldButton).click(); + } + + async clickIncludeFieldButton() { + return await this.page.locator(this.includeFieldButton).click(); + } + + async clickCloseDialog() { + return await this.page.locator(this.closeDialog).click(); + } + + async clickSavedViewDialogSaveContent() { + return await this.page.locator(this.savedViewDialogSaveContent).click(); + } + + async clickSavedViewByLabel(label) { + return await this.page.locator(this.savedViewByLabel).getByText(new RegExp(label)).first().click({ force: true }); + } + + async expectNotificationMessage(text) { + return await expect(this.page.locator(this.notificationMessage)).toContainText(text); + } + + async expectIndexFieldSearchInputVisible() { + return await expect(this.page.locator(this.indexFieldSearchInput)).toBeVisible(); + } + + async expectErrorMessageVisible() { + return await expect(this.page.locator(this.errorMessage)).toBeVisible(); + } + + async expectWarningElementHidden() { + const warningElement = this.page.locator(this.warningElement); + return await expect(warningElement).toBeHidden(); + } + + async expectTextVisible(text) { + return await expect(this.page.locator(`text=${text}`)).toBeVisible(); + } + + async expectExactTextVisible(text) { + await expect(this.page.getByText(text, { exact: true })).toBeVisible(); + } + + async expectLogsTableVisible() { + const table = this.page.locator(this.logsTable); + // Wait for the table to be visible with a timeout + await table.waitFor({ state: 'visible', timeout: 30000 }); + return await expect(table).toBeVisible(); + } + + async waitForSearchResults() { + // Wait for search results to appear by checking for the logs table + const table = this.page.locator(this.logsTable); + await table.waitFor({ state: 'visible', timeout: 30000 }); + + // Also wait for at least one row to be present + const firstRow = this.page.locator(this.logTableColumnSource); + await firstRow.waitFor({ state: 'visible', timeout: 30000 }); + + return true; + } + + async expectFieldRequiredVisible() { + return await expect(this.page.getByText(/Field is required/).first()).toBeVisible(); + } + + async expectErrorWhileFetchingNotVisible() { + return await expect(this.page.getByRole('heading', { name: 'Error while fetching' })).not.toBeVisible(); + } + + async clickBarChartCanvas() { + return await this.page.locator(this.barChartCanvas).click({ + position: { x: 182, y: 66 } + }); + } + + async fillIndexFieldSearchInput(text) { + return await this.fillInputField(this.logSearchIndexListFieldSearchInput, text); + } + + async clickExpandLabel(label) { + return await this.clickElementByLabel(label, 'Expand'); + } + + async clickCollapseLabel(label) { + return await this.clickElementByLabel(label, 'Collapse'); + } + + async expectErrorWhileFetchingFieldValuesNotVisible() { + const errorMessage = this.page.getByText('Error while fetching field values'); + return await expect(errorMessage).not.toBeVisible(); + } + + async clickText(text) { + return await this.page.getByText(text).click(); + } + + async clickSubfieldAddButton(field, value) { + // Remove trailing dash from value to avoid double dash + const cleanValue = value.endsWith('-') ? value.slice(0, -1) : value; + return await this.page.locator(`[data-test="logs-search-subfield-add-${field}-${cleanValue}-0"]`).getByText(value).click(); + } + + async expectSubfieldAddButtonVisible(field, value) { + // Remove trailing dash from value to avoid double dash + const cleanValue = value.endsWith('-') ? value.slice(0, -1) : value; + const targetElement = this.page.locator(`[data-test="logs-search-subfield-add-${field}-${cleanValue}-0"]`).getByText(value); + return await expect(targetElement).toBeVisible(); + } + + async clickAddStreamButton() { + const addButton = this.page.locator(this.addStreamButton); + + // Wait for the button to be visible + await addButton.waitFor({ state: 'visible', timeout: 10000 }); + + // Scroll the button into view if needed + await addButton.scrollIntoViewIfNeeded(); + + // Wait a moment for the scroll to complete + await this.page.waitForTimeout(500); + + // Click the button + return await addButton.click({ force: true }); + } + + async clickAddStreamNameInput() { + return await this.page.click(this.addStreamNameInput); + } + + async clickSaveStreamButton() { + const saveButton = this.page.locator(this.saveStreamButton); + + // Wait for the button to be visible + await saveButton.waitFor({ state: 'visible', timeout: 10000 }); + + // Scroll the button into view if needed + await saveButton.scrollIntoViewIfNeeded(); + + // Wait a moment for the scroll to complete + await this.page.waitForTimeout(500); + + // Click the button + return await saveButton.click({ force: true }); + } + + async waitForSaveStreamButton() { + return await this.page.locator(this.saveStreamButton).waitFor({ state: "visible" }); + } + + async scrollSaveStreamButtonIntoView() { + return await this.page.locator(this.saveStreamButton).scrollIntoViewIfNeeded(); + } + + async clickStreamDetail() { + return await this.page.locator(this.streamDetail).first().click({ force: true }); + } + + async clickSchemaStreamIndexSelect() { + return await this.page.locator(this.schemaStreamIndexSelect).click(); + } + + async clickFullTextSearch() { + const scope = this.page.locator(this.fullTextSearch); + return await scope.getByText(/Full text search/).first().click(); + } + + async clickSchemaUpdateSettingsButton() { + return await this.page.locator(this.schemaUpdateSettingsButton).click({ force: true }); + } + + async clickColAutoButton() { + return await this.page.locator(this.colAutoButton).click({ force: true }); + } + + async clickExploreTitle() { + return await this.page.locator(this.exploreTitle).first().click({ force: true }); + } + + async clickStreamsSearchStreamInput() { + return await this.page.click(this.streamsSearchStreamInput); + } + + async fillStreamsSearchStreamInput(text) { + return await this.page.keyboard.type(text); + } + + async selectAllText() { + return await this.page.keyboard.press(process.platform === "darwin" ? "Meta+A" : "Control+A"); + } + + async pressBackspace() { + return await this.page.keyboard.press("Backspace"); + } + + async expectSQLQueryMissingError() { + return await this.page.getByText("SQL query is missing or invalid. Please submit a valid SQL statement.").click(); + } + + async clickTableRowExpandMenu() { + return await this.page.locator(this.timestampColumnMenu).first().click({ force: true }); + } + + async clickVrlEditor() { + return await this.page.locator(this.vrlEditor).first().getByRole('textbox').fill('.a=2'); + } + + async waitForTimeout(milliseconds) { + return await this.page.waitForTimeout(milliseconds); + } + + async expectSearchListVisible() { + return await expect(this.page.locator(this.searchListFirstTextLeft)).toBeVisible(); + } + + async clickCloseDialogForce() { + return await this.page.locator(this.closeDialog).click({ force: true }); + } + + async clickLiveModeButton() { + return await this.page.locator(this.liveModeToggleBtn).click(); + } + + async clickLiveMode5Sec() { + return await this.page.locator(this.liveMode5SecBtn).click(); + } + + async clickVrlToggle() { + return await this.page.locator(this.vrlToggleButton).click(); + } + + async expectVrlFieldVisible() { + return await expect(this.page.locator(this.vrlEditor).first()).toBeVisible(); + } + + async expectVrlFieldNotVisible() { + return await expect(this.page.locator(this.vrlEditor).first()).not.toBeVisible(); + } + + async expectFnEditorNotVisible() { + return await expect(this.page.locator('#fnEditor').getByRole('textbox').locator('div')).not.toBeVisible(); + } + + async clickPast6DaysButton() { + return await this.page.locator(this.relative6DaysBtn).click(); + } + + async clickMenuLink(link) { + return await this.page.locator(this.menuLink(link)).click(); + } + + async expectSQLQueryVisible() { + return await expect(this.page.locator(this.queryEditor)).toContainText('SELECT * FROM'); + } + + async clickNavigateBack() { + return await this.page.goBack(); + } + + async expectLogTableColumnSourceVisibleAfterNavigation() { + const element = this.page.locator(this.logTableColumnSource); + // Wait for the element to be visible with a timeout + await element.waitFor({ state: 'visible', timeout: 30000 }); + return await expect(element).toBeVisible(); + } + + async clickSearchAroundButton() { + return await this.page.locator(this.searchAroundBtn).click(); + } + + async expectPaginationNotVisible() { + return await expect(this.page.locator(this.pagination)).not.toBeVisible(); + } + + async expectSQLPaginationNotVisible() { + return await expect(this.page.locator(this.sqlPagination)).not.toBeVisible(); + } + + async expectSQLGroupOrderLimitPaginationNotVisible() { + return await expect(this.page.locator(this.sqlGroupOrderLimitPagination)).not.toBeVisible(); + } + + async expectSearchBarRefreshButtonVisible() { + return await expect(this.page.locator(this.searchBarRefreshButton)).toBeVisible(); + } + + async expectQuickModeToggleVisible() { + return await expect(this.page.locator(this.quickModeToggle)).toBeVisible(); + } + + async clickInterestingFieldButton(field) { + return await this.page.locator(this.interestingFieldBtn(field)).first().click(); + } + + async expectInterestingFieldInEditor(field) { + return await expect(this.page.locator(this.queryEditor).getByText(new RegExp(field)).first()).toBeVisible(); + } + + async expectInterestingFieldInTable(field) { + return await expect(this.page.locator(this.logTableColumnSource).getByText(new RegExp(field)).first()).toBeVisible(); + } + + async expectQueryEditorVisible() { + return await expect(this.page.locator(this.queryEditor)).toBeVisible(); + } + + async expectQueryEditorContainsText(text) { + return await expect(this.page.locator(this.queryEditor)).toContainText(text); + } + + async expectQueryEditorEmpty() { + const text = await this.getQueryEditorText(); + return await expect(text).toEqual(""); + } + + async expectQueryEditorContainsSQLQuery() { + return await this.expectQueryEditorContainsTextHelper('SELECT COUNT(_timestamp) AS xyz, _timestamp FROM "e2e_automate" Group by _timestamp ORDER BY _timestamp DESC'); + } + + async expectQueryEditorContainsMatchAllQuery() { + return await this.expectQueryEditorContainsTextHelper("match_all('code')"); + } + + async expectQueryEditorContainsMatchAllRawQuery() { + return await this.expectQueryEditorContainsTextHelper("match_all_raw_ignore_case('provide_credentials')"); + } + + async expectQueryEditorContainsKubernetesQuery() { + return await this.expectQueryEditorContainsTextHelper("kubernetes"); + } + + async expectQueryEditorContainsVrlQuery() { + return await this.expectQueryEditorContainsTextHelper(".a=2"); + } + + async expectQueryEditorContainsSQLQueryMissingError() { + return await this.expectQueryEditorContainsTextHelper("SQL query is missing or invalid. Please submit a valid SQL statement."); + } + + async expectQueryEditorContainsValidViewName() { + return await this.expectQueryEditorContainsTextHelper("Please provide valid view name"); + } + + async expectQueryEditorContainsFieldRequired() { + return await this.expectQueryEditorContainsTextHelper("Field is required"); + } + + async expectQueryEditorContainsErrorWhileFetching() { + return await this.expectQueryEditorContainsTextHelper("Error while fetching"); + } + + async expectQueryEditorContainsErrorWhileFetchingFieldValues() { + return await this.expectQueryEditorContainsTextHelper("Error while fetching field values"); + } + + async expectQueryEditorContainsZioxIngester() { + return await this.expectQueryEditorContainsTextHelper("ziox-ingester-"); + } + + async expectQueryEditorContainsKubernetesPod(type, ingesterNumber) { + return await this.expectKubernetesPodContent(type, ingesterNumber); + } + + // Additional methods for logsPage spec + async clickMenuLinkItem(link) { + return await this.clickMenuLinkByType(link); + } + + async clickMenuLinkLogsItem() { + return await this.clickMenuLinkByType('logs'); + } + + async clickMenuLinkTracesItem() { + return await this.clickMenuLinkByType('traces'); + } + + async clickMenuLinkStreamsItem() { + return await this.clickMenuLinkByType('streams'); + } + + async clickMenuLinkMetricsItem() { + return await this.clickMenuLinkByType('metrics'); + } + + async clickMenuLinkPipelineItem() { + return await this.clickMenuLinkByType('pipeline'); + } + + async clickMenuLinkFunctionsItem() { + return await this.clickMenuLinkByType('functions'); + } + + async clickTabRealtime() { + return await this.page.locator('[data-test="tab-realtime"]').click(); + } + + async clickFunctionStreamTab() { + return await this.page.locator('[data-test="function-stream-tab"]').click(); + } + + async clickSearchFunctionInput() { + return await this.page.getByPlaceholder(this.searchFunctionInput.placeholder).click(); + } + + async fillSearchFunctionInput(text) { + return await this.page.getByPlaceholder(this.searchFunctionInput.placeholder).fill(text); + } + + async clickDeleteFunctionButton() { + return await this.page.getByRole('button', { name: 'Delete Function' }).click(); + } + + async clickFunctionDropdownSave() { + return await this.page.locator(this.logsSearchBarFunctionDropdownSave).filter({ hasText: 'save' }).click(); + } + + async clickSavedFunctionNameInput() { + return await this.page.locator(this.savedFunctionNameInput).click(); + } + + async fillSavedFunctionNameInput(text) { + return await this.fillInputField(this.savedFunctionNameInput, text); + } + + async expectFunctionNameNotValid() { + return await this.page.getByText('Function name is not valid.').click(); + } + + async expectWarningNoFunctionDefinition() { + return await this.page.locator(this.qNotifyWarning).filter({ hasText: 'warningNo function definition' }).nth(3).click(); + } + + async expectBarChartVisible() { + const barChart = this.page.locator(this.logsTable); + return await expect(barChart).toBeTruthy(); + } + + async expectUrlContainsLogs() { + return await expect(this.page.url()).toContain("logs"); + } + + async expectPageContainsText(text) { + const logsPage = this.page.locator(this.qPageContainer); + return await expect(logsPage).toContainText(text); + } + + async clickLogSearchIndexListFieldSearchInput() { + return await this.page.locator(this.logSearchIndexListFieldSearchInput).click(); + } + + async fillLogSearchIndexListFieldSearchInput(text) { + return await this.fillInputField(this.logSearchIndexListFieldSearchInput, text); + } + + async clickExpandCode() { + return await this.page.getByLabel(this.expandCode).click(); + } + + async clickLogsDetailTableSearchAroundBtn() { + return await this.page.locator(this.logsDetailTableSearchAroundBtn).click(); + } + + async expectLogTableColumnSourceVisible() { + const element = this.page.locator(this.logTableColumnSource); + // Wait for the element to be visible with a timeout + await element.waitFor({ state: 'visible', timeout: 30000 }); + return await expect(element).toBeVisible(); + } + + async clickLogTableColumn3Source() { + return await this.page.locator(this.logTableColumn3Source).getByText('{"_timestamp":').click(); + } + + async clickHistogramToggleDiv() { + return await this.page.locator(this.histogramToggleDiv).nth(2).click(); + } + + async expectQueryEditorContainsExpectedQuery(expectedQuery) { + const text = await this.page.evaluate((queryEditorSelector) => { + const editor = document.querySelector(queryEditorSelector).querySelector('.cm-content'); + return editor ? editor.textContent.trim() : null; + }, this.queryEditor); + console.log(text); + return await expect(text.replace(/\s/g, "")).toContain(expectedQuery.replace(/\s/g, "")); + } + + async expectQueryEditorContainsSelectFrom() { + return await this.page.locator(this.queryEditor) + .locator(this.cmContent) + .locator(this.cmLine) + .filter({ hasText: 'SELECT * FROM "e2e_automate"' }) + .nth(0); + } + + generateRandomString() { + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let result = ''; + for (let i = 0; i < 5; i++) { + result += characters.charAt(Math.floor(Math.random() * characters.length)); + } + return result; + } + + async expectQueryEditorNotContainsText(text) { + await expect(this.page.locator(this.queryEditor)).not.toContainText(text); + } + + async expectLogTableColumnSourceNotHaveText(text) { + await expect(this.page.locator(this.logTableColumnSource)).not.toHaveText(text); + } + + async selectStreamAndStreamTypeForLogs(stream) { + await this.page.locator('[data-test="log-search-index-list-select-stream"]').click(); + await this.page.waitForTimeout(2000); + await this.page.locator('[data-test="log-search-index-list-select-stream"]').fill(stream); + await this.page.waitForTimeout(2000); + await this.page.waitForSelector(`[data-test="log-search-index-list-stream-toggle-${stream}"] div`, { state: "visible" }); + await this.page.waitForTimeout(2000); + await this.page.locator(`[data-test="log-search-index-list-stream-toggle-${stream}"] div`).first().click(); + } +} \ No newline at end of file diff --git a/tests/ui-testing/pages/logsQueryPage.js b/tests/ui-testing/pages/logsPages/logsQueryPage.js similarity index 100% rename from tests/ui-testing/pages/logsQueryPage.js rename to tests/ui-testing/pages/logsPages/logsQueryPage.js diff --git a/tests/ui-testing/pages/streamsPages/streamsPage.js b/tests/ui-testing/pages/streamsPages/streamsPage.js index 0451286f42..1c00784c7e 100644 --- a/tests/ui-testing/pages/streamsPages/streamsPage.js +++ b/tests/ui-testing/pages/streamsPages/streamsPage.js @@ -1,6 +1,6 @@ import { expect } from '@playwright/test'; import { LoginPage } from '../loginPage.js'; -import { LogsPage } from '../logsPage.js'; +import { LogsPage } from '../logsPages/logsPage.js'; import { IngestionPage } from '../ingestionPage.js'; import { ManagementPage } from '../managementPage.js'; import { StreamPage } from '../streamPage.js'; @@ -194,4 +194,9 @@ export class StreamsPage { const errorDetailsButton = this.page.locator('[data-test="logs-page-histogram-error-details-btn"]'); await expect(errorDetailsButton).not.toBeVisible(); } + + // Validation method for 'No data found for histogram.' + async expectNoDataFoundForHistogram() { + await expect(this.page.getByText('warning No data found for histogram.')).toBeVisible(); + } } \ No newline at end of file diff --git a/tests/ui-testing/playwright-tests/Logs/logshistogram.spec.js b/tests/ui-testing/playwright-tests/Logs/logshistogram.spec.js new file mode 100644 index 0000000000..850e45583c --- /dev/null +++ b/tests/ui-testing/playwright-tests/Logs/logshistogram.spec.js @@ -0,0 +1,207 @@ +import { test, expect } from "../baseFixtures.js"; +import logData from "../../cypress/fixtures/log.json"; +import { LogsPage } from '../../pages/logsPages/logsPage.js'; +import logsdata from "../../../test-data/logs_data.json"; + +test.describe.configure({ mode: 'parallel' }); + +async function login(page) { + await page.goto(process.env["ZO_BASE_URL"]); + await page.waitForTimeout(1000); + if (await page.getByText('Login as internal user').isVisible()) { + await page.getByText('Login as internal user').click(); + } + + await page.locator('[data-cy="login-user-id"]').fill(process.env["ZO_ROOT_USER_EMAIL"]); + await page.locator("label").filter({ hasText: "Password *" }).click(); + await page.locator('[data-cy="login-password"]').fill(process.env["ZO_ROOT_USER_PASSWORD"]); + await page.locator('[data-cy="login-sign-in"]').click(); +} + +async function ingestion(page) { + const orgId = process.env["ORGNAME"]; + const streamName = "e2e_automate"; + const basicAuthCredentials = Buffer.from( + `${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}` + ).toString('base64'); + + const headers = { + "Authorization": `Basic ${basicAuthCredentials}`, + "Content-Type": "application/json", + }; + const response = await page.evaluate(async ({ url, headers, orgId, streamName, logsdata }) => { + const fetchResponse = await fetch(`${url}/api/${orgId}/${streamName}/_json`, { + method: 'POST', + headers: headers, + body: JSON.stringify(logsdata) + }); + return await fetchResponse.json(); + }, { + url: process.env.INGESTION_URL, + headers: headers, + orgId: orgId, + streamName: streamName, + logsdata: logsdata + }); + console.log(response); +} + +test.describe("Logs Histogram testcases", () => { + let logsPage; + + test.beforeEach(async ({ page }) => { + await login(page); + logsPage = new LogsPage(page); + await page.waitForTimeout(5000); + await ingestion(page); + await page.waitForTimeout(2000); + + await page.goto( + `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` + ); + const allsearch = page.waitForResponse("**/api/default/_search**"); + await logsPage.selectStream("e2e_automate"); + }); + + test("Verify error handling and no results found with histogram", { + tag: ['@histogram', '@all', '@logs'] + }, async ({ page }) => { + // Check if histogram is off and toggle it on if needed + const isHistogramOn = await logsPage.isHistogramOn(); + if (!isHistogramOn) { + await logsPage.toggleHistogram(); + } + + // Type invalid query and verify error + await logsPage.typeQuery("match_all('invalid')"); + await logsPage.setDateTimeFilter(); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefresh(); + await logsPage.clickErrorMessage(); + await logsPage.clickResetFilters(); + + // Type SQL query and verify no results + await logsPage.typeQuery("SELECT count(*) FROM 'e2e_automate' where code > 500"); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefresh(); + await logsPage.waitForTimeout(2000); + await logsPage.clickNoDataFound(); + await logsPage.clickResultDetail(); + }); + + test("Verify error handling with histogram toggle off and on", { + tag: ['@histogram', '@all', '@logs'] + }, async ({ page }) => { + // Check if histogram is on and toggle it off + const isHistogramOn = await logsPage.isHistogramOn(); + if (isHistogramOn) { + await logsPage.toggleHistogram(); + } + + // Type invalid query and verify error + await logsPage.typeQuery("match_all('invalid')"); + await logsPage.setDateTimeFilter(); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefresh(); + await logsPage.clickErrorMessage(); + await logsPage.clickResetFilters(); + + // Toggle histogram back on + await logsPage.toggleHistogram(); + + // Type SQL query and verify no results + await logsPage.typeQuery("SELECT count(*) FROM 'e2e_automate' where code > 500"); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefresh(); + await logsPage.waitForTimeout(2000); + await logsPage.clickNoDataFound(); + await logsPage.clickResultDetail(); + }); + + test("Verify histogram toggle persistence after multiple queries", { + tag: ['@histogram', '@all', '@logs'] + }, async ({ page }) => { + // Start with histogram on + const isHistogramOn = await logsPage.isHistogramOn(); + if (!isHistogramOn) { + await logsPage.toggleHistogram(); + } + + // Run first query + await logsPage.typeQuery("SELECT * FROM 'e2e_automate' LIMIT 10"); + await logsPage.setDateTimeFilter(); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefresh(); + await logsPage.waitForTimeout(2000); + + // Toggle histogram off + await logsPage.toggleHistogram(); + await logsPage.enableSQLMode(); + await logsPage.waitForTimeout(1000); + await logsPage.enableSQLMode(); + + // Run second query + await logsPage.typeQuery("SELECT count(*) FROM 'e2e_automate'"); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefresh(); + await logsPage.waitForTimeout(2000); + + // Verify histogram stays off + await logsPage.verifyHistogramState(); + }); + + test("Verify histogram toggle with empty query", { + tag: ['@histogram', '@all', '@logs'] + }, async ({ page }) => { + // Start with histogram off + const isHistogramOn = await logsPage.isHistogramOn(); + if (isHistogramOn) { + await logsPage.toggleHistogram(); + } + + // Clear query and refresh + await logsPage.typeQuery(""); + await logsPage.setDateTimeFilter(); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefresh(); + await logsPage.waitForTimeout(2000); + + // Toggle histogram on + await logsPage.toggleHistogram(); + + // Verify histogram state + const isHistogramOnAfterToggle = await logsPage.isHistogramOn(); + expect(isHistogramOnAfterToggle).toBeTruthy(); + }); + + test("Verify histogram toggle with complex query", { + tag: ['@histogram', '@all', '@logs'] + }, async ({ page }) => { + // Start with histogram on + const isHistogramOn = await logsPage.isHistogramOn(); + if (!isHistogramOn) { + await logsPage.toggleHistogram(); + } + + // Run complex query + await logsPage.typeQuery("SELECT * FROM 'e2e_automate' WHERE timestamp > '2024-01-01' AND code < 400 GROUP BY code ORDER BY count(*) DESC LIMIT 5"); + await logsPage.setDateTimeFilter(); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefresh(); + await logsPage.waitForTimeout(2000); + + // Toggle histogram off and verify + await logsPage.toggleHistogram(); + const isHistogramOff = await logsPage.isHistogramOn(); + expect(!isHistogramOff).toBeTruthy(); + + // Run another query and verify histogram stays off + await logsPage.typeQuery("SELECT count(*) FROM 'e2e_automate'"); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefresh(); + await logsPage.waitForTimeout(2000); + + const isHistogramStillOff = await logsPage.isHistogramOn(); + expect(!isHistogramStillOff).toBeTruthy(); + }); +}); \ No newline at end of file diff --git a/tests/ui-testing/playwright-tests/Logs/logspage.spec.js b/tests/ui-testing/playwright-tests/Logs/logspage.spec.js new file mode 100644 index 0000000000..106090f790 --- /dev/null +++ b/tests/ui-testing/playwright-tests/Logs/logspage.spec.js @@ -0,0 +1,467 @@ +import { test, expect } from "../baseFixtures"; +import logData from "../../cypress/fixtures/log.json"; +import logsdata from "../../../test-data/logs_data.json"; +import { LogsPage } from '../../pages/logsPages/logsPage.js'; + +test.describe.configure({ mode: "parallel" }); + +async function login(page) { + await page.goto(process.env["ZO_BASE_URL"]); + if (await page.getByText('Login as internal user').isVisible()) { + await page.getByText('Login as internal user').click(); +} + + console.log("ZO_BASE_URL", process.env["ZO_BASE_URL"]); + await page.waitForTimeout(1000); + await page + .locator('[data-cy="login-user-id"]') + .fill(process.env["ZO_ROOT_USER_EMAIL"]); + //Enter Password + await page + .locator('[data-cy="login-password"]') + .fill(process.env["ZO_ROOT_USER_PASSWORD"]); + await page.locator('[data-cy="login-sign-in"]').click(); + await page.waitForTimeout(4000); + await page.goto(process.env["ZO_BASE_URL"]); +} + +async function ingestion(page) { + const orgId = process.env["ORGNAME"]; + const streamName = "e2e_automate"; + const basicAuthCredentials = Buffer.from( + `${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}` + ).toString('base64'); + + const headers = { + "Authorization": `Basic ${basicAuthCredentials}`, + "Content-Type": "application/json", + }; + const response = await page.evaluate(async ({ url, headers, orgId, streamName, logsdata }) => { + const fetchResponse = await fetch(`${url}/api/${orgId}/${streamName}/_json`, { + method: 'POST', + headers: headers, + body: JSON.stringify(logsdata) + }); + return await fetchResponse.json(); + }, { + url: process.env.INGESTION_URL, + headers: headers, + orgId: orgId, + streamName: streamName, + logsdata: logsdata + }); + console.log(response); +} + +test.describe("Logs Page testcases", () => { + let logsPage; + // let logData; + function removeUTFCharacters(text) { + // console.log(text, "tex"); + // Remove UTF characters using regular expression + return text.replace(/[^\x00-\x7F]/g, " "); + } + async function applyQueryButton(page) { + // click on the run query button + // Type the value of a variable into an input field + const search = page.waitForResponse(logData.applyQuery); + await page.waitForTimeout(3000); + await page.locator("[data-test='logs-search-bar-refresh-btn']").click({ + force: true, + }); + // get the data from the search variable + await expect.poll(async () => (await search).status()).toBe(200); + // await search.hits.FIXME_should("be.an", "array"); + } + // tebefore(async function () { + // // logData("log"); + // // const data = page; + // // logData = data; + + // console.log("--logData--", logData); + // }); + test.beforeEach(async ({ page }) => { + await login(page); + logsPage = new LogsPage(page); + await page.waitForTimeout(1000) + await ingestion(page); + await page.waitForTimeout(2000) + + await page.goto( + `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` + ); + const allsearch = page.waitForResponse("**/api/default/_search**"); + await logsPage.selectStream("e2e_automate"); + await applyQueryButton(page); + // const streams = page.waitForResponse("**/api/default/streams**"); + }); + + test("should click run query after SQL toggle on but without any query", { + tag: ['@sqlQueryLogs', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.waitForTimeout(3000); + await logsPage.clickRefreshButton(); + await logsPage.clickSQLModeToggle(); + await logsPage.clickQueryEditor(); + await logsPage.selectAllText(); + await logsPage.pressBackspace(); + await logsPage.waitForTimeout(3000); + await logsPage.clickRefreshButton(); + await logsPage.expectSQLQueryMissingError(); + }); + + test("should be able to enter valid text in VRL and run query", { + tag: ['@vrlQueryLogs', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative6WeeksButton(); + await applyQueryButton(page); + + await logsPage.clickVrlEditor(); + await logsPage.waitForTimeout(1000); + await applyQueryButton(page); + await logsPage.expectWarningElementHidden(); + + await logsPage.clickTableRowExpandMenu(); + await logsPage.expectTextVisible(".a=2"); + await logsPage.expectLogsTableVisible(); + await logsPage.clickRefreshButton(); + }); + + test("should hide and display again after clicking the arrow", { + tag: ['@hideAndDisplayLogs', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative6WeeksButton(); + await logsPage.clickShowQueryToggle(); + await logsPage.clickFieldListCollapseButton(); + await logsPage.waitForTimeout(1000); + await logsPage.clickFieldListCollapseButton(); + await logsPage.expectIndexFieldSearchInputVisible(); + }); + + test("should verify if special characters allowed in saved views name", { + tag: ['@savedViewsSpecialCharacters', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative6WeeksButton(); + await logsPage.clickShowQueryToggle(); + await logsPage.clickSavedViewsButton(); + await logsPage.fillSavedViewName("e2e@@@@@"); + await logsPage.waitForTimeout(2000); + await logsPage.clickSavedViewDialogSave(); + await logsPage.expectNotificationMessage("Please provide valid view name"); + }); + + test("should display error when user directly clicks on OK without adding name", { + tag: ['@savedViewsValidation', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.clickRefreshButton(); + await logsPage.clickSavedViewsExpand(); + await logsPage.clickSaveViewButton(); + await logsPage.clickSavedViewDialogSave(); + }); + + test("should display the details of logs results on graph", { + tag: ['@logsResultsGraph', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative6WeeksButton(); + await applyQueryButton(page); + await logsPage.waitForTimeout(5000); + await logsPage.expectSearchListVisible(); + await logsPage.waitForTimeout(2000); + await logsPage.clickLogTableColumnSource(); + await logsPage.waitForTimeout(1000); + await logsPage.clickCloseDialogForce(); + await logsPage.expectSearchListVisible(); + }); + + test("should click on live mode on button and select 5 sec, switch off, and then click run query", { + tag: ['@liveMode', '@all', '@logs'] + }, async ({ + page, + }) => { + await page.route("**/logData.ValueQuery", (route) => route.continue()); + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative6WeeksButton(); + await logsPage.clickLiveModeButton(); + await logsPage.clickLiveMode5Sec(); + await logsPage.expectNotificationMessage("Live mode is enabled"); + await logsPage.clickLiveModeButton(); + await logsPage.clickLiveMode5Sec(); + await applyQueryButton(page); + }); + + test("should click on VRL toggle and display the field, then disable toggle and make the VRL field disappear", { + tag: ['@vrlToggle', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.expectVrlFieldVisible(); + await logsPage.clickVrlToggle(); + await logsPage.expectFnEditorNotVisible(); + }); + + test("should switch from past 6 weeks to past 6 days on date-time UI", { + tag: ['@dateTimeUI', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative6WeeksButton(); + await logsPage.expectTextVisible("Past 6 Weeks"); + await applyQueryButton(page); + await logsPage.clickDateTimeButton(); + await logsPage.clickPast6DaysButton(); + await logsPage.expectTextVisible("Past 6 Days"); + await applyQueryButton(page); + }); + + test("should display SQL query on switching between Menu options & navigating to Logs again", { + tag: ['@sqlQueryPersistence', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.clickDateTimeButton(); + await logsPage.waitForTimeout(1000); + await logsPage.clickSQLModeToggle(); + const expectedQuery = 'SELECT * FROM "e2e_automate"'; + const text = await logsPage.getQueryEditorText(); + await expect(text.replace(/\s/g, "")).toContain(expectedQuery.replace(/\s/g, "")); + await logsPage.clickMenuLinkMetricsItem(); + await logsPage.clickMenuLinkLogsItem(); + await logsPage.waitForTimeout(2000); + await logsPage.expectQueryEditorContainsSelectFrom(); + }); + test("should display ingested logs - search logs, navigate on another tab, revisit logs page", { + tag: ['@ingestedLogsPersistence', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative15MinButton(); + await applyQueryButton(page); + await logsPage.clickMenuLinkTracesItem(); + await logsPage.waitForTimeout(100); + await logsPage.clickMenuLinkLogsItem(); + await logsPage.waitForTimeout(5000); + await logsPage.expectBarChartVisible(); + }); + + test.skip("should redirect to logs after clicking on stream explorer via stream page", { + tag: ['@streamExplorer', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.clickDateTimeButton(); + await logsPage.clickMenuLinkStreamsItem(); + await logsPage.waitForTimeout(1000); + await logsPage.clickMenuLinkStreamsItem(); + await logsPage.clickSearchStreamInput(); + await logsPage.fillSearchStreamInput("e2e"); + await logsPage.waitForTimeout(1000); + await logsPage.clickExploreButton(); + await logsPage.expectUrlContainsLogs(); + }); + + test('should display error when save function is clicked without any VRL function', { + tag: ['@functionValidation', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.clickFunctionDropdownSave(); + await logsPage.expectWarningNoFunctionDefinition(); + }); + + test('should create a function and then delete it', { + tag: ['@functionCRUD', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.clickRefreshButton(); + await logsPage.clickFunctionDropdownSave(); + await logsPage.clickVrlEditor(); + await logsPage.waitForTimeout(1000); + await logsPage.clickFunctionDropdownSave(); + await logsPage.clickSavedFunctionNameInput(); + const randomString = logsPage.generateRandomString(); + const functionName = 'e2efunction_' + randomString; + await logsPage.fillSavedFunctionNameInput(functionName); + await logsPage.clickSavedViewDialogSave(); + await logsPage.clickMenuLinkPipelineItem(); + await logsPage.clickTabRealtime(); + await logsPage.clickFunctionStreamTab(); + await logsPage.clickSearchFunctionInput(); + await logsPage.fillSearchFunctionInput(randomString); + await logsPage.clickDeleteFunctionButton(); + await logsPage.clickConfirmButton(); + }); + + test('should display click save directly while creating a function', { + tag: ['@functionSaveValidation', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(1000); + await logsPage.clickVrlEditor(); + await logsPage.waitForTimeout(1000); + await logsPage.clickFunctionDropdownSave(); + await logsPage.clickSavedViewDialogSave(); + await logsPage.expectFunctionNameNotValid(); + }); + + test('should display error on adding only blank spaces under function name', { + tag: ['@functionNameValidation', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(1000); + await logsPage.clickVrlEditor(); + await logsPage.waitForTimeout(1000); + await logsPage.clickFunctionDropdownSave(); + await logsPage.fillSavedFunctionNameInput(' '); + await logsPage.clickSavedViewDialogSave(); + await logsPage.expectFunctionNameNotValid(); + }); + + + test('should display error on adding invalid characters under function name', { + tag: ['@functionNameValidation', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(1000); + await logsPage.clickVrlEditor(); + await logsPage.waitForTimeout(1000); + await logsPage.clickFunctionDropdownSave(); + await logsPage.fillSavedFunctionNameInput('e2e@@@'); + await logsPage.clickSavedViewDialogSave(); + await logsPage.expectFunctionNameNotValid(); + }); + + test('should display added function on switching between tabs and again navigate to log', { + tag: ['@functionPersistence', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(1000); + await logsPage.clickVrlEditor(); + await logsPage.waitForTimeout(1000); + await logsPage.clickRefreshButton(); + await logsPage.clickMenuLinkMetricsItem(); + await logsPage.clickMenuLinkLogsItem(); + await logsPage.clickMenuLinkLogsItem(); + await logsPage.expectPageContainsText(".a=2"); + }); + + test('should display bar chart when histogram toggle is on', { + tag: ['@histogramBarChart', '@histogram', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.clickLogSearchIndexListFieldSearchInput(); + await logsPage.fillLogSearchIndexListFieldSearchInput('code'); + await logsPage.waitForTimeout(4000); + await logsPage.clickExpandCode(); + await logsPage.waitForTimeout(4000); + await logsPage.clickRefreshButton(); + await logsPage.clickSQLModeToggle(); + await logsPage.clickRefreshButton(); + await logsPage.clickBarChartCanvas(); + await logsPage.clickSQLModeToggle(); + await logsPage.clickRefreshButton(); + await logsPage.clickBarChartCanvas(); + await logsPage.clickHistogramToggleDiv(); + }); + + test('should display search around in histogram mode', { + tag: ['@searchAroundHistogram', '@histogram', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(1000); + await logsPage.clickLogTableColumnSource(); + await logsPage.clickLogsDetailTableSearchAroundBtn(); + await logsPage.waitForTimeout(2000); + await logsPage.expectLogTableColumnSourceVisible(); + }); + + + test.skip('should display results for search around after adding function', async ({ page }) => { + await logsPage.waitForTimeout(1000); + await logsPage.clickVrlEditor(); + await logsPage.waitForTimeout(1000); + await logsPage.clickRefreshButton(); + await logsPage.clickLogTableColumn3Source(); + await logsPage.clickLogsDetailTableSearchAroundBtn(); + await logsPage.waitForTimeout(1000); + await logsPage.expectLogTableColumnSourceVisible(); + }); + + test('should display search around in SQL mode', { + tag: ['@searchAroundSQL', '@sqlMode', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(1000); + await logsPage.clickSQLModeToggle(); + await logsPage.clickLogTableColumnSource(); + await logsPage.clickLogsDetailTableSearchAroundBtn(); + await logsPage.waitForTimeout(2000); + await logsPage.expectLogTableColumnSourceVisible(); + }); + + test("should display results for search around with limit query", { + tag: ['@searchAroundLimit', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(2000); + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative15MinButton(); + await logsPage.clickQueryEditor(); + await logsPage.typeInQueryEditor("match_all('code') limit 5"); + await logsPage.waitForTimeout(2000); + await logsPage.clickSQLModeToggle(); + await logsPage.waitForTimeout(2000); + await logsPage.clickLogTableColumnSource(); + await logsPage.clickLogsDetailTableSearchAroundBtn(); + await logsPage.waitForTimeout(2000); + await logsPage.expectLogTableColumnSourceVisible(); + }); + + test("should not display pagination for limit query", { + tag: ['@paginationLimit', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(2000); + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative15MinButton(); + await logsPage.clickQueryEditor(); + await logsPage.typeInQueryEditor("match_all('code') limit 5"); + await logsPage.waitForTimeout(2000); + await logsPage.clickSQLModeToggle(); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefreshButton(); + await logsPage.waitForTimeout(2000); + await logsPage.expectPaginationNotVisible(); + }); + + test("should not display pagination for SQL limit query", { + tag: ['@paginationSQLLimit', '@sqlMode', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(2000); + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative15MinButton(); + await logsPage.clickQueryEditor(); + await logsPage.typeInQueryEditor('SELECT * FROM "e2e_automate" ORDER BY _timestamp DESC limit 5'); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefreshButton(); + await logsPage.waitForTimeout(2000); + await logsPage.expectPaginationNotVisible(); + }); + + test("should not display pagination for SQL group/order/limit query", { + tag: ['@paginationSQLGroupOrder', '@sqlMode', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(2000); + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative15MinButton(); + await logsPage.clickQueryEditor(); + await logsPage.typeInQueryEditor('SELECT * FROM "e2e_automate" WHERE code < 400 GROUP BY code ORDER BY count(*) DESC LIMIT 5'); + await logsPage.waitForTimeout(2000); + await logsPage.clickRefreshButton(); + await logsPage.waitForTimeout(2000); + await logsPage.expectPaginationNotVisible(); + }); +}); diff --git a/tests/ui-testing/playwright-tests/Logs/logsqueries.spec.js b/tests/ui-testing/playwright-tests/Logs/logsqueries.spec.js new file mode 100644 index 0000000000..dd6e08f934 --- /dev/null +++ b/tests/ui-testing/playwright-tests/Logs/logsqueries.spec.js @@ -0,0 +1,334 @@ +import { test, expect } from "../baseFixtures"; +import logData from "../../cypress/fixtures/log.json"; +import logsdata from "../../../test-data/logs_data.json"; +import { LogsPage } from '../../pages/logsPages/logsPage.js'; + +test.describe.configure({ mode: 'parallel' }); +async function login(page) { + await page.goto(process.env["ZO_BASE_URL"]); + await page.waitForTimeout(4000); + await page.goto(process.env["ZO_BASE_URL"]); + if (await page.getByText('Login as internal user').isVisible()) { + await page.getByText('Login as internal user').click(); +} + await page + .locator('[data-cy="login-user-id"]') + .fill(process.env["ZO_ROOT_USER_EMAIL"]); + //Enter Password + await page + .locator('[data-cy="login-password"]') + .fill(process.env["ZO_ROOT_USER_PASSWORD"]); + await page.locator('[data-cy="login-sign-in"]').click(); + await page.waitForTimeout(4000); + await page.goto(process.env["ZO_BASE_URL"]); +} + +async function ingestion(page) { + const orgId = process.env["ORGNAME"]; + const streamName = "e2e_automate"; + const basicAuthCredentials = Buffer.from( + `${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}` + ).toString('base64'); + + const headers = { + "Authorization": `Basic ${basicAuthCredentials}`, + "Content-Type": "application/json", + }; + const response = await page.evaluate(async ({ url, headers, orgId, streamName, logsdata }) => { + const fetchResponse = await fetch(`${url}/api/${orgId}/${streamName}/_json`, { + method: 'POST', + headers: headers, + body: JSON.stringify(logsdata) + }); + return await fetchResponse.json(); + }, { + url: process.env.INGESTION_URL, + headers: headers, + orgId: orgId, + streamName: streamName, + logsdata: logsdata + }); + console.log(response); +} +test.describe("Logs Queries testcases", () => { + let logsPage; + // let logData; + function removeUTFCharacters(text) { + // console.log(text, "tex"); + // Remove UTF characters using regular expression + return text.replace(/[^\x00-\x7F]/g, " "); + } + async function applyQueryButton(page) { + // click on the run query button + // Type the value of a variable into an input field + const search = page.waitForResponse(logData.applyQuery); + await page.waitForTimeout(3000); + await page.locator("[data-test='logs-search-bar-refresh-btn']").click({ + force: true, + }); + // get the data from the search variable + await expect.poll(async () => (await search).status()).toBe(200); + // await search.hits.FIXME_should("be.an", "array"); + } + + test.beforeEach(async ({ page }) => { + await login(page); + logsPage = new LogsPage(page); + await page.waitForTimeout(1000) + await ingestion(page); + await page.waitForTimeout(2000) + + await page.goto( + `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` + ); + const allsearch = page.waitForResponse("**/api/default/_search**"); + await logsPage.selectStream("e2e_automate"); + await applyQueryButton(page); + // const streams = page.waitForResponse("**/api/default/streams**"); + }); + + test("should display quick mode toggle button", { + tag: ['@quickModeLogs', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.expectQuickModeToggleVisible(); + }); + + test.skip("should add timestamp to editor save this view and switch", { + tag: ['@timestampViewLogs', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(3000); + await logsPage.clickLogTableColumnSource(); + await logsPage.clickIncludeExcludeFieldButton(); + await logsPage.clickIncludeFieldButton(); + await logsPage.clickCloseDialog(); + await logsPage.clickSavedViewsButton(); + await logsPage.fillSavedViewName("e2etimestamp"); + await logsPage.clickSavedViewDialogSaveContent(); + await logsPage.clickSavedViewArrow(); + await logsPage.clickSavedViewByLabel(/timestamp/); + await logsPage.waitForTimeout(3000); + await logsPage.clickSavedViewsExpand(); + await logsPage.clickSavedViewSearchInput(); + await logsPage.fillSavedViewSearchInput('e2e'); + await logsPage.clickSavedViewByTitle('e2etimestamp'); + await logsPage.clickSavedViewsExpand(); + await logsPage.clickSavedViewSearchInput(); + await logsPage.clickSavedViewByTitle('e2etimestamp'); + await logsPage.clickDeleteButton(); + await logsPage.clickConfirmButton(); + }); + + test("should redirect to logs after clicking on stream explorer via stream page", { + tag: ['@streamExplorer', '@all', '@logs'] + }, async ({ page }) => { + // Generate a random saved view name + const randomSavedViewName = `streamslog${Math.random().toString(36).substring(2, 10)}`; + + // Interactions with the page + await logsPage.clickRefreshButton(); + await logsPage.clickSavedViewsExpand(); + await logsPage.clickSaveViewButton(); + await logsPage.fillSavedViewName(randomSavedViewName); // Use the random name + await logsPage.clickSavedViewDialogSave(); + await logsPage.waitForTimeout(5000); + await logsPage.clickStreamsMenuItem(); + await logsPage.clickSearchStreamInput(); + await logsPage.fillSearchStreamInput('e2e'); + await logsPage.waitForTimeout(1000); + await logsPage.clickExploreButton(); + await logsPage.waitForTimeout(5000); + await logsPage.waitForSavedViewsButton(); + await logsPage.clickSavedViewsExpand(); + await logsPage.clickSavedViewSearchInput(); + await logsPage.fillSavedViewSearchInput(randomSavedViewName); // Use the random name here + await logsPage.waitForTimeout(3000); + await logsPage.waitForSavedViewText(randomSavedViewName); + await logsPage.clickSavedViewByText(randomSavedViewName); + await logsPage.clickSavedViewsExpand(); + await logsPage.clickSavedViewSearchInput(); + await logsPage.clickSavedViewByTitle(randomSavedViewName); // Use the random name here + + // Dynamic delete button selector using the random saved view name + await logsPage.clickDeleteSavedViewButton(randomSavedViewName); + await logsPage.clickConfirmButton(); // Confirm deletion + }); + + test("should reset the editor on clicking reset filter button", { + tag: ['@resetFilters', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative15MinButton(); + await logsPage.clickQueryEditorTextbox(); + await logsPage.typeInQueryEditor("match_all_raw_ignore_case('provide_credentials')"); + await logsPage.waitForSearchBarRefreshButton(); + await logsPage.clickRefreshButton(); + await logsPage.clickResetFiltersButton(); + await logsPage.waitForQueryEditorTextbox(); + await logsPage.expectQueryEditorEmpty(); + }); + + test("should add invalid query and display error", { + tag: ['@invalidQueryLogs', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(2000); + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative15MinButton(); + await logsPage.clickQueryEditor(); + await logsPage.typeInQueryEditor("kubernetes"); + await logsPage.waitForTimeout(2000); + await logsPage.clickSearchBarRefreshButton(); + await logsPage.expectErrorMessageVisible(); + }); + + test("should not display error if match all case added in log query search", { + tag: ['@matchAllLogs', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.clickDateTimeButton(); + await logsPage.clickRelative15MinButton(); + + await logsPage.expectQueryEditorVisible(); + await logsPage.clickQueryEditor(); + await logsPage.typeInQueryEditor("match_all('code')"); + + await logsPage.expectSearchBarRefreshButtonVisible(); + await logsPage.clickSearchBarRefreshButton(); + + await logsPage.expectLogTableColumnSourceVisible(); + }); + + + + test("should change stream settings and click on search stream", { + tag: ['@streamSettings', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.clickStreamsMenuItem(); + await logsPage.waitForTimeout(3000); + await logsPage.clickStreamsSearchStreamInput(); + await logsPage.fillStreamsSearchStreamInput("e2e_automate"); + await logsPage.waitForTimeout(2000); + await logsPage.clickStreamDetail(); + await logsPage.clickSchemaStreamIndexSelect(); + await logsPage.clickFullTextSearch(); + await logsPage.clickSchemaUpdateSettingsButton(); + await logsPage.waitForTimeout(3000); + await logsPage.clickColAutoButton(); + await logsPage.waitForTimeout(3000); + await logsPage.clickExploreTitle(); + await logsPage.expectLogTableColumnSourceVisible(); + }); + + + test("should display error if blank spaces added under stream name and clicked create stream ", { + tag: ['@streamValidation', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.clickStreamsMenuItem(); + await logsPage.clickAddStreamButton(); + await logsPage.clickAddStreamNameInput(); + await logsPage.typeInQueryEditor(" "); + await logsPage.clickSaveStreamButton(); + await logsPage.expectFieldRequiredVisible(); + }); + + + + test("should display error if create stream is clicked without adding name", { + tag: ['@streamValidation', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.clickStreamsMenuItem(); + await logsPage.clickAddStreamButton(); + await logsPage.waitForSaveStreamButton(); + await logsPage.scrollSaveStreamButtonIntoView(); + await logsPage.clickSaveStreamButton(); + await logsPage.expectFieldRequiredVisible(); + }); + + test("should display enter count query", { + tag: ['@countQuery', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.clickQueryEditorTextbox(); + await logsPage.typeInQueryEditor('SELECT COUNT(_timestamp) AS xyz, _timestamp FROM "e2e_automate" Group by _timestamp ORDER BY _timestamp DESC'); + await logsPage.waitForTimeout(4000); + await logsPage.clickSQLModeToggle(); + await logsPage.expectSearchBarRefreshButtonVisible(); + await logsPage.waitForTimeout(3000); + await logsPage.clickRefreshButton(); + await logsPage.waitForTimeout(4000); + await logsPage.expectErrorWhileFetchingNotVisible(); + await logsPage.clickBarChartCanvas(); + }); + + test("should display values API text successfully and error to not be displayed", { + tag: ['@valuesAPI', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.fillIndexFieldSearchInput('kubernetes_pod_name'); + await logsPage.clickExpandLabel('kubernetes_pod_name'); + await logsPage.expectErrorWhileFetchingFieldValuesNotVisible(); + await logsPage.clickText('ziox-ingester-'); + await logsPage.clickRefreshButton(); + await logsPage.clickCollapseLabel('kubernetes_pod_name'); + await logsPage.clickExpandLabel('kubernetes_pod_name'); + await logsPage.expectSubfieldAddButtonVisible('kubernetes_pod_name', 'ziox-ingester-'); + await logsPage.clickSubfieldAddButton('kubernetes_pod_name', 'ziox-ingester-'); + }); + + test("should display results in selected time", { + tag: ['@timeSelection', '@all', '@logs'] + }, async ({ + page, + }) => { + + await logsPage.setDateTimeToToday(); + + + }); + + test("should display results if stringmatch ignorecase lowercase added in log query search", { + tag: ['@stringMatchIgnoreLowerCase', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.selectStream('e2e_automate'); + await logsPage.setDateTimeTo15Minutes(); + await logsPage.searchWithStringMatchIgnoreCase('ziox'); + }); + + test("should display results if stringmatch ignorecase uppercase added in log query search", { + tag: ['@stringMatchIgnoreUpperCase', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.selectStream('e2e_automate'); + await logsPage.setDateTimeTo15Minutes(); + await logsPage.searchWithStringMatchIgnoreCase('Ziox'); + }); + + test("should trigger search results when pressing Cmd+Enter or Ctrl+Enter", { + tag: ['@keyboardShortcuts', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.executeQueryWithKeyboardShortcutTest(); + }); + + test("should execute query with keyboard shortcut (Cmd+Enter or Ctrl+Enter) after clicking elsewhere ", { + tag: ['@keyboardShortcuts', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.executeQueryWithKeyboardShortcutAfterClickingElsewhere(); + }); + + test("should execute different query with keyboard shortcut (Cmd+Enter or Ctrl+Enter)", { + tag: ['@keyboardShortcuts', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.executeQueryWithKeyboardShortcutWithDifferentQuery(); + }); + + test("should execute SQL query with keyboard shortcut (Cmd+Enter or Ctrl+Enter)", { + tag: ['@keyboardShortcuts', '@sqlMode', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.executeQueryWithKeyboardShortcutWithSQLMode(); + }); + + test("should verify logcount ordering in ascending and descending order", { + tag: ['@logCountOrdering', '@all', '@logs'] + }, async ({ page }) => { + // Verify descending order + await logsPage.verifyLogCountOrderingDescending(); + + // Verify ascending order + await logsPage.verifyLogCountOrderingAscending(); + }); +}) \ No newline at end of file diff --git a/tests/ui-testing/playwright-tests/Logs/logsquickmode.spec.js b/tests/ui-testing/playwright-tests/Logs/logsquickmode.spec.js new file mode 100644 index 0000000000..669af4d2f9 --- /dev/null +++ b/tests/ui-testing/playwright-tests/Logs/logsquickmode.spec.js @@ -0,0 +1,204 @@ +import { test, expect } from "../baseFixtures"; +import logData from "../../cypress/fixtures/log.json"; +import logsdata from "../../../test-data/logs_data.json"; +import { LogsPage } from '../../pages/logsPages/logsPage.js'; + +test.describe.configure({ mode: 'parallel' }); + +async function login(page) { + await page.goto(process.env["ZO_BASE_URL"]); + if (await page.getByText('Login as internal user').isVisible()) { + await page.getByText('Login as internal user').click(); +} + + console.log("ZO_BASE_URL", process.env["ZO_BASE_URL"]); + await page.waitForTimeout(1000); + await page + .locator('[data-cy="login-user-id"]') + .fill(process.env["ZO_ROOT_USER_EMAIL"]); + //Enter Password + await page + .locator('[data-cy="login-password"]') + .fill(process.env["ZO_ROOT_USER_PASSWORD"]); + await page.locator('[data-cy="login-sign-in"]').click(); + await page.waitForTimeout(4000); + await page.goto(process.env["ZO_BASE_URL"]); +} + +async function ingestion(page) { + const orgId = process.env["ORGNAME"]; + const streamName = "e2e_automate"; + const basicAuthCredentials = Buffer.from( + `${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}` + ).toString('base64'); + + const headers = { + "Authorization": `Basic ${basicAuthCredentials}`, + "Content-Type": "application/json", + }; + const response = await page.evaluate(async ({ url, headers, orgId, streamName, logsdata }) => { + const fetchResponse = await fetch(`${url}/api/${orgId}/${streamName}/_json`, { + method: 'POST', + headers: headers, + body: JSON.stringify(logsdata) + }); + return await fetchResponse.json(); + }, { + url: process.env.INGESTION_URL, + headers: headers, + orgId: orgId, + streamName: streamName, + logsdata: logsdata + }); + console.log(response); +} + + + +test.describe("Logs Quickmode testcases", () => { + let logsPage; + // let logData; + function removeUTFCharacters(text) { + // console.log(text, "tex"); + // Remove UTF characters using regular expression + return text.replace(/[^\x00-\x7F]/g, " "); + } + async function applyQueryButton(page) { + const search = page.waitForResponse(logData.applyQuery); + await page.waitForTimeout(3000); + await page.locator("[data-test='logs-search-bar-refresh-btn']").click({ + force: true, + }); + // get the data from the search variable + await expect.poll(async () => (await search).status()).toBe(200); + // await search.hits.FIXME_should("be.an", "array"); + } + + test.beforeEach(async ({ page }) => { + await login(page); + logsPage = new LogsPage(page); + await page.waitForTimeout(1000); + await ingestion(page); + await page.waitForTimeout(2000); + + await page.goto( + `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` + ); + const allsearch = page.waitForResponse("**/api/default/_search**"); + await logsPage.selectStream("e2e_automate"); + + await applyQueryButton(page); + + // Enable quick mode toggle if it's not already enabled + const toggleButton = await logsPage.page.$('[data-test="logs-search-bar-quick-mode-toggle-btn"] > .q-toggle__inner'); + // Evaluate the class attribute to determine if the toggle is in the off state + const isSwitchedOff = await toggleButton.evaluate(node => node.classList.contains('q-toggle__inner--falsy')); + if (isSwitchedOff) { + await toggleButton.click(); + } + }); + test("should click on interesting fields icon and display query in editor", { + tag: ['@interestingFieldsLogs', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.fillIndexFieldSearchInput("kubernetes_pod_id"); + await logsPage.waitForTimeout(2000); + await logsPage.clickInterestingFieldButton("kubernetes_pod_id"); + await logsPage.clickSQLModeToggle(); + await logsPage.waitForTimeout(2000); + await logsPage.expectInterestingFieldInEditor("kubernetes_pod_id"); + }); + test("should display quick mode toggle button", { + tag: ['@quickModeLogs', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.expectQuickModeToggleVisible(); + }); + + test("should click on interesting fields icon in histogram mode and run query", { + tag: ['@interestingFieldsHistogramModeLogs', '@histogram', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.fillIndexFieldSearchInput("kubernetes_pod_id"); + await logsPage.waitForTimeout(2000); + await logsPage.clickInterestingFieldButton("kubernetes_pod_id"); + await logsPage.clickSearchBarRefreshButton(); + await logsPage.waitForTimeout(2000); + await logsPage.expectInterestingFieldInTable("kubernetes_pod_id"); + }); + + test("should display error on entering random text in histogram mode when quick mode is on", { + tag: ['@errorHandlingHistogramModeLogs', '@histogram', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.waitForTimeout(2000); + await logsPage.clickQueryEditor(); + await logsPage.typeInQueryEditor("oooo"); + await logsPage.waitForTimeout(1000); + await logsPage.waitForSearchBarRefreshButton(); + await logsPage.clickSearchBarRefreshButton(); + await logsPage.waitForTimeout(2000); + await logsPage.expectErrorMessageVisible(); + }); + + test("should display selected interestesing field and order by - as default in editor", { + tag: ['@interestingFieldsSqlModeLogs', '@sqlMode', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.fillIndexFieldSearchInput("kubernetes_pod_id"); + await logsPage.waitForTimeout(2000); + await logsPage.clickInterestingFieldButton("kubernetes_pod_id"); + await logsPage.clickSQLModeToggle(); + await logsPage.waitForQueryEditorTextbox(); + await logsPage.expectQueryEditorVisible(); + }); + + test("should adding/removing interesting field removes it from editor and results too", { + tag: ['@interestingFieldsCRUD', '@all', '@logs'] + }, async ({ page }) => { + await logsPage.fillIndexFieldSearchInput("kubernetes_container_name"); + await logsPage.waitForTimeout(2000); + await logsPage.clickInterestingFieldButton("kubernetes_container_name"); + await logsPage.fillIndexFieldSearchInput("level"); + await logsPage.waitForTimeout(2000); + await logsPage.clickInterestingFieldButton("level"); + await logsPage.clickSQLModeToggle(); + await logsPage.clickSearchBarRefreshButton(); + await logsPage.expectLogTableColumnSourceVisible(); + await logsPage.clickInterestingFieldButton("level"); + await logsPage.expectQueryEditorNotContainsText("level"); + await logsPage.clickSearchBarRefreshButton(); + await logsPage.expectLogTableColumnSourceNotHaveText("source"); + }); + + test("should display order by in sql mode by default even after page reload", { + tag: ['@sqlModeOrderBy', '@sqlMode', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.fillIndexFieldSearchInput("kubernetes_pod_id"); + await logsPage.waitForTimeout(2000); + await logsPage.clickInterestingFieldButton("kubernetes_pod_id"); + await logsPage.clickSQLModeToggle(); + await logsPage.clickSearchBarRefreshButton(); + await logsPage.page.reload(); + await logsPage.waitForTimeout(2000); + await logsPage.expectQueryEditorContainsText('SELECT kubernetes_pod_id FROM "e2e_automate"'); + }); + + test("should display results without adding timestamp in quick mode", { + tag: ['@quickModeResults', '@all', '@logs'] + }, async ({ + page, + }) => { + await logsPage.fillIndexFieldSearchInput("kubernetes_pod_id"); + await logsPage.waitForTimeout(2000); + await logsPage.clickInterestingFieldButton("kubernetes_pod_id"); + await logsPage.clickSQLModeToggle(); + await logsPage.waitForTimeout(2000); + await logsPage.clickSearchBarRefreshButton(); + await logsPage.waitForTimeout(2000); + await logsPage.expectExactTextVisible("source"); + }); +}); diff --git a/tests/ui-testing/playwright-tests/Streams/streaming.spec.js b/tests/ui-testing/playwright-tests/Streams/streaming.spec.js index 42d5224f09..34fefce9e9 100644 --- a/tests/ui-testing/playwright-tests/Streams/streaming.spec.js +++ b/tests/ui-testing/playwright-tests/Streams/streaming.spec.js @@ -14,18 +14,22 @@ test.describe("Streaming for logs", () => { await streamsPage.ingestion(); await streamsPage.ingestionJoin(); await streamsPage.goToManagement(); - await page.waitForTimeout(5000); + await page.waitForTimeout(3000); // Reduced from 5000 await streamsPage.checkStreaming(); }); - test("Run query after selecting two streams after enabling streaming", async ({ page }) => { + test("Run query after selecting two streams after enabling streaming", { + tag: ['@streaming', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); await streamsPage.displayTwoStreams(); await streamsPage.selectRunQuery(); }); - test("Enable Streaming for running query after selecting two streams and SQL Mode On", async ({ page }) => { + test("Enable Streaming for running query after selecting two streams and SQL Mode On", { + tag: ['@streaming', '@sqlMode', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); // await streamsPage.enableSQLMode(); @@ -33,7 +37,9 @@ test.describe("Streaming for logs", () => { await streamsPage.displayTwoStreams(); }); - test("Enable Streaming for running query after selecting two streams, selecting field and SQL Mode On", async ({ page }) => { + test("Enable Streaming for running query after selecting two streams, selecting field and SQL Mode On", { + tag: ['@streaming', '@sqlMode', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); await streamsPage.kubernetesContainerName(); @@ -42,26 +48,35 @@ test.describe("Streaming for logs", () => { await streamsPage.validateResult(); }); - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering join queries", async ({ page }) => { + test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering join queries", { + tag: ['@streaming', '@sqlMode', '@joins', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); await streamsPage.kubernetesContainerNameJoin(); // await streamsPage.enableSQLMode(); await streamsPage.selectRunQuery(); + await page.waitForTimeout(3000); // Wait for query results await streamsPage.displayCountQuery(); + await page.waitForTimeout(3000); // Wait for query results await streamsPage.validateResult(); }); - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering join limit", async ({ page }) => { + test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering join limit", { + tag: ['@streaming', '@sqlMode', '@joins', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); await streamsPage.kubernetesContainerNameJoinLimit(); // await streamsPage.enableSQLMode(); await streamsPage.selectRunQuery(); + await page.waitForTimeout(3000); // Wait for query results await streamsPage.validateResult(); }); - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering join like", async ({ page }) => { + test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering join like", { + tag: ['@streaming', '@sqlMode', '@joins', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); await streamsPage.kubernetesContainerNameJoinLike(); @@ -70,7 +85,9 @@ test.describe("Streaming for logs", () => { await streamsPage.validateResult(); }); - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering Left join queries", async ({ page }) => { + test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering Left join queries", { + tag: ['@streaming', '@sqlMode', '@joins', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); await streamsPage.kubernetesContainerNameLeftJoin(); @@ -79,7 +96,9 @@ test.describe("Streaming for logs", () => { await streamsPage.validateResult(); }); - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering Right join queries", async ({ page }) => { + test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering Right join queries", { + tag: ['@streaming', '@sqlMode', '@joins', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); await streamsPage.kubernetesContainerNameRightJoin(); @@ -88,7 +107,9 @@ test.describe("Streaming for logs", () => { await streamsPage.validateResult(); }); - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering Full join queries", async ({ page }) => { + test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering Full join queries", { + tag: ['@streaming', '@sqlMode', '@joins', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); await streamsPage.kubernetesContainerNameFullJoin(); @@ -97,7 +118,9 @@ test.describe("Streaming for logs", () => { await streamsPage.validateResult(); }); - test("Enable Streaming for clicking on interesting field icon and display field in editor", async ({ page }) => { + test("Enable Streaming for clicking on interesting field icon and display field in editor", { + tag: ['@streaming', '@interestingFields', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); await streamsPage.enableSQLMode(); @@ -107,7 +130,9 @@ test.describe("Streaming for logs", () => { await streamsPage.validateInterestingFields(); }); - test("Enable Streaming for clicking on interesting field icon and display query in editor", async ({ page }) => { + test("Enable Streaming for clicking on interesting field icon and display query in editor", { + tag: ['@streaming', '@interestingFields', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); await streamsPage.enableSQLMode(); @@ -117,7 +142,9 @@ test.describe("Streaming for logs", () => { await streamsPage.validateInterestingFieldsQuery(); }); - test("Enable Streaming for Adding or removing interesting field removes it from editor and results too", async ({ page }) => { + test("Enable Streaming for Adding or removing interesting field removes it from editor and results too", { + tag: ['@streaming', '@interestingFields', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexAndStreamJoin(); // await streamsPage.enableSQLMode(); @@ -127,7 +154,9 @@ test.describe("Streaming for logs", () => { await streamsPage.addRemoveInteresting(); }); - test("Streaming enabled histogram is disabled and run query, results appear and then user switches on Histogram, getting error", async ({ page }) => { + test("Streaming enabled histogram is disabled and run query, results appear and then user switches on Histogram, getting error", { + tag: ['@streaming', '@histogram', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexStreamDefault(); await streamsPage.selectRunQuery(); @@ -145,13 +174,15 @@ test.describe("Streaming for logs", () => { await expect(errorDetailsButton).not.toBeVisible(); }); - test("No Histogram should be displayed if Data is not available", async ({ page }) => { + test("No Histogram should be displayed if Data is not available", { + tag: ['@streaming', '@histogram', '@all', '@streams'] + }, async ({ page }) => { await streamsPage.navigateToLogs(); await streamsPage.selectIndexStreamDefault(); await streamsPage.enableSQLMode(); await streamsPage.clearAndFillQueryEditor('SELECT count(_timestamp) FROM "default" where code = 201'); await page.waitForTimeout(1000); await streamsPage.selectRunQuery(); - await streamsPage.waitForSearchResultAndCheckText('warning No data found for histogram.'); + await streamsPage.expectNoDataFoundForHistogram(); }); }); \ No newline at end of file diff --git a/tests/ui-testing/playwright-tests/Streams/streamname.spec.js b/tests/ui-testing/playwright-tests/Streams/streamname.spec.js index bfd93ee951..095088455a 100644 --- a/tests/ui-testing/playwright-tests/Streams/streamname.spec.js +++ b/tests/ui-testing/playwright-tests/Streams/streamname.spec.js @@ -26,7 +26,9 @@ test.describe("Stream name casing preservation tests", () => { await page.waitForTimeout(5000); }); - test("should preserve stream name casing after ingestion and show in stream explorer", async ({ page }) => { + test("should preserve stream name casing after ingestion and show in stream explorer", { + tag: ['@streamName', '@casing', '@all', '@streams'] + }, async ({ page }) => { const orgId = process.env["ORGNAME"]; const headers = getHeaders(); diff --git a/tests/ui-testing/playwright-tests/changeOrg.spec.js b/tests/ui-testing/playwright-tests/changeOrg.spec.js index 05e330b9ed..984dbfd95e 100644 --- a/tests/ui-testing/playwright-tests/changeOrg.spec.js +++ b/tests/ui-testing/playwright-tests/changeOrg.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "./baseFixtures.js"; import { LoginPage } from '../pages/loginPage.js'; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; import { IngestionPage } from '../pages/ingestionPage.js'; import { HomePage } from "../pages/homePage.js"; import { MetricsPage } from "../pages/metricsPage.js"; @@ -91,10 +91,8 @@ test.describe("Change Organisation", () => { multiOrgIdentifier = await createOrgPage.createOrg(newOrgName); await ingestionPage.ingestionMultiOrg(multiOrgIdentifier); await homePage.homePageOrg(newOrgName); - await logsPage.navigateToLogs(); + await logsPage.navigateToLogs(multiOrgIdentifier); await homePage.homeURLContains(multiOrgIdentifier); - - }); test("Metrics Page default validation", async ({ page }) => { diff --git a/tests/ui-testing/playwright-tests/dashboards/dashboard-folder.spec.js b/tests/ui-testing/playwright-tests/dashboards/dashboard-folder.spec.js index a908884a5f..32b4e13d32 100644 --- a/tests/ui-testing/playwright-tests/dashboards/dashboard-folder.spec.js +++ b/tests/ui-testing/playwright-tests/dashboards/dashboard-folder.spec.js @@ -39,7 +39,7 @@ test.describe("dashboard folder testcases", () => { await orgNavigation; }); - test.skip("Should create and delete a unique folder, and verify it's deleted", async ({ + test("Should create and delete a unique folder, and verify it's deleted" ,async ({ page, }) => { const dashboardPage = new DashboardListPage(page); diff --git a/tests/ui-testing/playwright-tests/dashboards/dashboardtype.spec.js b/tests/ui-testing/playwright-tests/dashboards/dashboardtype.spec.js index 9d0fb8d3c8..8dc890f889 100644 --- a/tests/ui-testing/playwright-tests/dashboards/dashboardtype.spec.js +++ b/tests/ui-testing/playwright-tests/dashboards/dashboardtype.spec.js @@ -17,8 +17,8 @@ const randomDashboardName = test.describe.configure({ mode: "parallel" }); -// Refactored test cases using Page Object Model +// Refactored test cases using Page Object Model test.describe("dashboard UI testcases", () => { test.beforeEach(async ({ page }) => { await login(page); diff --git a/tests/ui-testing/playwright-tests/dashboards/visualization-vrl.spec.js b/tests/ui-testing/playwright-tests/dashboards/visualization-vrl.spec.js index 53fc1b1990..38cbbd5b82 100644 --- a/tests/ui-testing/playwright-tests/dashboards/visualization-vrl.spec.js +++ b/tests/ui-testing/playwright-tests/dashboards/visualization-vrl.spec.js @@ -1,7 +1,7 @@ import { test, expect } from "../baseFixtures"; -import LogsVisualise from "../../pages/dashboardPages/visualise"; -import { login } from "../utils/dashLogin"; -import { ingestion } from "../utils/dashIngestion"; +import LogsVisualise from "../../pages/dashboardPages/visualise.js"; +import { login } from "../utils/dashLogin.js"; +import { ingestion } from "../utils/dashIngestion.js"; import logData from "../../cypress/fixtures/log.json"; test.describe.configure({ mode: "parallel" }); @@ -25,7 +25,6 @@ test.describe("visualization VRL testcases", () => { ); const logsVisualise = new LogsVisualise(page); - await selectStreamAndStreamTypeForLogs(page, logData.Stream); await logsVisualise.logsApplyQueryButton(); }); @@ -421,4 +420,4 @@ test.describe("visualization VRL testcases", () => { // Assertion: Fail the test if an error was detected expect(errorDetected).toBe(false); }); -}); +}); \ No newline at end of file diff --git a/tests/ui-testing/playwright-tests/dashboards/visualize.spec.js b/tests/ui-testing/playwright-tests/dashboards/visualize.spec.js index c5d84bf97b..bcd474c86f 100644 --- a/tests/ui-testing/playwright-tests/dashboards/visualize.spec.js +++ b/tests/ui-testing/playwright-tests/dashboards/visualize.spec.js @@ -636,4 +636,4 @@ test.describe("logs testcases", () => { await dashboardCreate.backToDashboardList(); await deleteDashboard(page, randomDashboardName); }); -}); +}); \ No newline at end of file diff --git a/tests/ui-testing/playwright-tests/enrichment.spec.js b/tests/ui-testing/playwright-tests/enrichment.spec.js index d9ffedfe77..fabb737cdb 100644 --- a/tests/ui-testing/playwright-tests/enrichment.spec.js +++ b/tests/ui-testing/playwright-tests/enrichment.spec.js @@ -3,7 +3,7 @@ import logData from "../../ui-testing/cypress/fixtures/log.json"; // import { log } from "console"; import logsdata from "../../test-data/logs_data.json"; import PipelinePage from "../pages/pipelinePage"; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; // import { pipeline } from "stream"; // import fs from "fs"; import { v4 as uuidv4 } from "uuid"; @@ -59,7 +59,7 @@ async function ingestion(page) { console.log(response); } -const selectStreamAndStreamTypeForLogs = async (page, stream) => { +const selectStream = async (page, stream) => { await page.waitForTimeout(4000); await page .locator('[data-test="log-search-index-list-select-stream"]') @@ -116,7 +116,7 @@ test.describe("Enrichment data testcases", () => { `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` ); const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); + await logsPage.selectStream("e2e_automate"); await applyQueryButton(page); }); diff --git a/tests/ui-testing/playwright-tests/indexquery.spec.js b/tests/ui-testing/playwright-tests/indexquery.spec.js index 53c9c73852..fd684b0875 100644 --- a/tests/ui-testing/playwright-tests/indexquery.spec.js +++ b/tests/ui-testing/playwright-tests/indexquery.spec.js @@ -16,7 +16,7 @@ async function login(page) { await page.locator('[data-cy="login-sign-in"]').click(); } -const selectStreamAndStreamTypeForLogs = async (page, stream) => { +const selectStream = async (page, stream) => { await page.waitForTimeout(4000); await page.locator('[data-test="log-search-index-list-select-stream"]').click({ force: true }); await page.locator("div.q-item").getByText(`${stream}`).first().click({ force: true }); @@ -91,7 +91,7 @@ test.describe("Compare SQL query execution times", () => { console.log(response); await page.goto(`${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}`); - await selectStreamAndStreamTypeForLogs(page, logData.Stream); + await selectStream(page, logData.Stream); await applyQueryButton(page); }); diff --git a/tests/ui-testing/playwright-tests/join.spec.js b/tests/ui-testing/playwright-tests/join.spec.js index 4a85fec81e..d0241ca2cd 100644 --- a/tests/ui-testing/playwright-tests/join.spec.js +++ b/tests/ui-testing/playwright-tests/join.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "./baseFixtures"; import { LoginPage } from '../pages/loginPage'; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; import { IngestionPage } from '../pages/ingestionPage'; test.describe.configure({ mode: 'parallel' }); diff --git a/tests/ui-testing/playwright-tests/logshistogram.spec.js b/tests/ui-testing/playwright-tests/logshistogram.spec.js deleted file mode 100644 index 591e485a61..0000000000 --- a/tests/ui-testing/playwright-tests/logshistogram.spec.js +++ /dev/null @@ -1,204 +0,0 @@ -import { test, expect } from "./baseFixtures.js"; -import logData from "../cypress/fixtures/log.json"; -import { LogsPage } from '../pages/logsPage.js'; -import logsdata from "../../test-data/logs_data.json"; -import { LogsQueryPage } from '../pages/logsQueryPage.js'; - -test.describe.configure({ mode: 'parallel' }); - -async function login(page) { - await page.goto(process.env["ZO_BASE_URL"]); - await page.waitForTimeout(1000); - if (await page.getByText('Login as internal user').isVisible()) { - await page.getByText('Login as internal user').click(); - } - - await page.locator('[data-cy="login-user-id"]').fill(process.env["ZO_ROOT_USER_EMAIL"]); - await page.locator("label").filter({ hasText: "Password *" }).click(); - await page.locator('[data-cy="login-password"]').fill(process.env["ZO_ROOT_USER_PASSWORD"]); - await page.locator('[data-cy="login-sign-in"]').click(); -} - -async function ingestion(page) { - const orgId = process.env["ORGNAME"]; - const streamName = "e2e_automate"; - const basicAuthCredentials = Buffer.from( - `${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}` - ).toString('base64'); - - const headers = { - "Authorization": `Basic ${basicAuthCredentials}`, - "Content-Type": "application/json", - }; - const response = await page.evaluate(async ({ url, headers, orgId, streamName, logsdata }) => { - const fetchResponse = await fetch(`${url}/api/${orgId}/${streamName}/_json`, { - method: 'POST', - headers: headers, - body: JSON.stringify(logsdata) - }); - return await fetchResponse.json(); - }, { - url: process.env.INGESTION_URL, - headers: headers, - orgId: orgId, - streamName: streamName, - logsdata: logsdata - }); - console.log(response); -} - -test.describe("Logs Queries testcases", () => { - let logsPage; - let logsQueryPage; - - test.beforeEach(async ({ page }) => { - await login(page); - logsPage = new LogsPage(page); - await page.waitForTimeout(5000); - await ingestion(page); - await page.waitForTimeout(2000); - logsPage = new LogsPage(page); - logsQueryPage = new LogsQueryPage(page); - - await page.goto( - `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` - ); - const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); - }); - - test("Verify error handling and no results found with histogram", async ({ page }) => { - // Check if histogram is off and toggle it on if needed - const histogramToggle = page.locator('[data-test="logs-search-bar-show-histogram-toggle-btn"]'); - const isHistogramOn = await histogramToggle.evaluate(el => el.getAttribute('aria-checked') === 'true'); - if (!isHistogramOn) { - await logsPage.toggleHistogram(); - } - - // Type invalid query and verify error - await logsQueryPage.typeQuery("match_all('invalid')"); - await logsQueryPage.setDateTimeFilter(); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickRefresh(); - await logsQueryPage.clickErrorMessage(); - await logsQueryPage.clickResetFilters(); - - // Type SQL query and verify no results - await logsQueryPage.typeQuery("SELECT count(*) FROM 'e2e_automate' where code > 500"); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickRefresh(); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickNoDataFound(); - await logsQueryPage.clickResultDetail(); - }); - - test("Verify error handling with histogram toggle off and on", async ({ page }) => { - // Check if histogram is on and toggle it off - const histogramToggle = page.locator('[data-test="logs-search-bar-show-histogram-toggle-btn"]'); - const isHistogramOn = await histogramToggle.evaluate(el => el.getAttribute('aria-checked') === 'true'); - if (isHistogramOn) { - await logsPage.toggleHistogram(); - } - - // Type invalid query and verify error - await logsQueryPage.typeQuery("match_all('invalid')"); - await logsQueryPage.setDateTimeFilter(); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickRefresh(); - await logsQueryPage.clickErrorMessage(); - await logsQueryPage.clickResetFilters(); - - // Toggle histogram back on - await logsPage.toggleHistogram(); - - // Type SQL query and verify no results - await logsQueryPage.typeQuery("SELECT count(*) FROM 'e2e_automate' where code > 500"); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickRefresh(); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickNoDataFound(); - await logsQueryPage.clickResultDetail(); - }); - - test("Verify histogram toggle persistence after multiple queries", async ({ page }) => { - // Start with histogram on - const histogramToggle = page.locator('[data-test="logs-search-bar-show-histogram-toggle-btn"]'); - const isHistogramOn = await histogramToggle.evaluate(el => el.getAttribute('aria-checked') === 'true'); - if (!isHistogramOn) { - await logsPage.toggleHistogram(); - } - - // Run first query - await logsQueryPage.typeQuery("SELECT * FROM 'e2e_automate' LIMIT 10"); - await logsQueryPage.setDateTimeFilter(); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickRefresh(); - await logsQueryPage.waitForTimeout(2000); - - // Toggle histogram off - await logsPage.toggleHistogram(); - - // Run second query - await logsQueryPage.typeQuery("SELECT count(*) FROM 'e2e_automate'"); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickRefresh(); - await logsQueryPage.waitForTimeout(2000); - - // Verify histogram stays off - const isHistogramStillOff = await histogramToggle.evaluate(el => el.getAttribute('aria-checked') === 'false'); - expect(isHistogramStillOff).toBeTruthy(); - }); - - test("Verify histogram toggle with empty query", async ({ page }) => { - // Start with histogram off - const histogramToggle = page.locator('[data-test="logs-search-bar-show-histogram-toggle-btn"]'); - const isHistogramOn = await histogramToggle.evaluate(el => el.getAttribute('aria-checked') === 'true'); - if (isHistogramOn) { - await logsPage.toggleHistogram(); - } - - // Clear query and refresh - await logsQueryPage.typeQuery(""); - await logsQueryPage.setDateTimeFilter(); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickRefresh(); - await logsQueryPage.waitForTimeout(2000); - - // Toggle histogram on - await logsPage.toggleHistogram(); - - // Verify histogram state - const isHistogramOnAfterToggle = await histogramToggle.evaluate(el => el.getAttribute('aria-checked') === 'true'); - expect(isHistogramOnAfterToggle).toBeTruthy(); - }); - - test("Verify histogram toggle with complex query", async ({ page }) => { - // Start with histogram on - const histogramToggle = page.locator('[data-test="logs-search-bar-show-histogram-toggle-btn"]'); - const isHistogramOn = await histogramToggle.evaluate(el => el.getAttribute('aria-checked') === 'true'); - if (!isHistogramOn) { - await logsPage.toggleHistogram(); - } - - // Run complex query - await logsQueryPage.typeQuery("SELECT * FROM 'e2e_automate' WHERE timestamp > '2024-01-01' AND code < 400 GROUP BY code ORDER BY count(*) DESC LIMIT 5"); - await logsQueryPage.setDateTimeFilter(); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickRefresh(); - await logsQueryPage.waitForTimeout(2000); - - // Toggle histogram off and verify - await logsPage.toggleHistogram(); - const isHistogramOff = await histogramToggle.evaluate(el => el.getAttribute('aria-checked') === 'false'); - expect(isHistogramOff).toBeTruthy(); - - // Run another query and verify histogram stays off - await logsQueryPage.typeQuery("SELECT count(*) FROM 'e2e_automate'"); - await logsQueryPage.waitForTimeout(2000); - await logsQueryPage.clickRefresh(); - await logsQueryPage.waitForTimeout(2000); - - const isHistogramStillOff = await histogramToggle.evaluate(el => el.getAttribute('aria-checked') === 'false'); - expect(isHistogramStillOff).toBeTruthy(); - }); -}); \ No newline at end of file diff --git a/tests/ui-testing/playwright-tests/logspage.spec.js b/tests/ui-testing/playwright-tests/logspage.spec.js deleted file mode 100644 index b2a37a98c4..0000000000 --- a/tests/ui-testing/playwright-tests/logspage.spec.js +++ /dev/null @@ -1,582 +0,0 @@ -import { test, expect } from "./baseFixtures"; -import logData from "../../ui-testing/cypress/fixtures/log.json"; -import logsdata from "../../test-data/logs_data.json"; -import { LogsPage } from '../pages/logsPage.js'; - -test.describe.configure({ mode: "parallel" }); - -async function login(page) { - await page.goto(process.env["ZO_BASE_URL"]); - if (await page.getByText('Login as internal user').isVisible()) { - await page.getByText('Login as internal user').click(); -} - - console.log("ZO_BASE_URL", process.env["ZO_BASE_URL"]); - await page.waitForTimeout(1000); - await page - .locator('[data-cy="login-user-id"]') - .fill(process.env["ZO_ROOT_USER_EMAIL"]); - //Enter Password - await page - .locator('[data-cy="login-password"]') - .fill(process.env["ZO_ROOT_USER_PASSWORD"]); - await page.locator('[data-cy="login-sign-in"]').click(); - await page.waitForTimeout(4000); - await page.goto(process.env["ZO_BASE_URL"]); -} - -async function ingestion(page) { - const orgId = process.env["ORGNAME"]; - const streamName = "e2e_automate"; - const basicAuthCredentials = Buffer.from( - `${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}` - ).toString('base64'); - - const headers = { - "Authorization": `Basic ${basicAuthCredentials}`, - "Content-Type": "application/json", - }; - const response = await page.evaluate(async ({ url, headers, orgId, streamName, logsdata }) => { - const fetchResponse = await fetch(`${url}/api/${orgId}/${streamName}/_json`, { - method: 'POST', - headers: headers, - body: JSON.stringify(logsdata) - }); - return await fetchResponse.json(); - }, { - url: process.env.INGESTION_URL, - headers: headers, - orgId: orgId, - streamName: streamName, - logsdata: logsdata - }); - console.log(response); -} - -test.describe("Logs UI testcases", () => { - let logsPage; - // let logData; - function removeUTFCharacters(text) { - // console.log(text, "tex"); - // Remove UTF characters using regular expression - return text.replace(/[^\x00-\x7F]/g, " "); - } - async function applyQueryButton(page) { - // click on the run query button - // Type the value of a variable into an input field - const search = page.waitForResponse(logData.applyQuery); - await page.waitForTimeout(3000); - await page.locator("[data-test='logs-search-bar-refresh-btn']").click({ - force: true, - }); - // get the data from the search variable - await expect.poll(async () => (await search).status()).toBe(200); - // await search.hits.FIXME_should("be.an", "array"); - } - // tebefore(async function () { - // // logData("log"); - // // const data = page; - // // logData = data; - - // console.log("--logData--", logData); - // }); - test.beforeEach(async ({ page }) => { - await login(page); - logsPage = new LogsPage(page); - await page.waitForTimeout(1000) - await ingestion(page); - await page.waitForTimeout(2000) - - await page.goto( - `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` - ); - const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); - await applyQueryButton(page); - // const streams = page.waitForResponse("**/api/default/streams**"); - }); - - test("should click run query after SQL toggle on but without any query", async ({ - page, - }) => { - await page.waitForTimeout(3000); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page.locator('[data-test="logs-search-bar-query-editor"]').click(); - await page.keyboard.press( - process.platform === "darwin" ? "Meta+A" : "Control+A" - ); // Select all text - await page.keyboard.press("Backspace"); - await page.waitForTimeout(3000); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.getByText("SQL query is missing or invalid. Please submit a valid SQL statement.").click(); - }); - - test("should be able to enter valid text in VRL and run query", async ({ - page, - }) => { - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page - .locator('[data-test="date-time-relative-6-w-btn"] > .q-btn__content') - .click({ - force: true, - }); - await applyQueryButton(page); - - - await page.locator('#fnEditor').getByRole('textbox').fill('.a=2'); - await page.waitForTimeout(1000); - await applyQueryButton(page); - const warningElement = page.locator('text=warning Query execution'); - await expect(warningElement).toBeHidden() - - await page - .locator('[data-test="table-row-expand-menu"]') - .first() - .click({ force: true }); - await expect(page.locator("text=.a=2")).toBeVisible(); - await expect( - page.locator('[data-test="logs-search-result-logs-table"]') - ).toBeVisible(); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - }); - - test("should hide and display again after clicking the arrow", async ({ - page, - }) => { - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page - .locator('[data-test="date-time-relative-6-w-btn"] > .q-btn__content') - .click({ - force: true, - }); - await page - .locator('[data-test="logs-search-bar-show-query-toggle-btn"]') - .click({ force: true }); - await page.locator('[data-test="logs-search-field-list-collapse-btn"]').click(); - await page.waitForTimeout(1000) - await page.locator('[data-test="logs-search-field-list-collapse-btn"]').click(); - // await page - // .locator(".bg-primary > .q-btn__content > .q-icon") - // .click({ force: true }); - // await page.waitForTimeout(2000); - // await page - // .locator(".bg-primary > .q-btn__content > .q-icon") - // .click({ force: true }); - await expect( - page.locator('[data-cy="index-field-search-input"]') - ).toBeVisible(); - }); - - test("should verify if special characters allowed in saved views name", async ({ - page, - }) => { - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page - .locator('[data-test="date-time-relative-6-w-btn"] > .q-btn__content') - .click({ - force: true, - }); - await page - .locator('[data-test="logs-search-bar-show-query-toggle-btn"]') - .click({ force: true }); - await page - .locator( - '[data-test="logs-search-saved-views-btn"] > .q-btn-dropdown--current > .q-btn__content > :nth-child(1)' - ) - .click({ - force: true, - }); - await page.locator('[data-test="add-alert-name-input"]').type("e2e@@@@@"); - await page.waitForTimeout(2000); - await page - .locator('[data-test="saved-view-dialog-save-btn"]') - .click({ - force: true, - }); - await expect(page.locator(".q-notification__message")).toContainText( - "Please provide valid view name" - ); - }); - - test("should display error when user directly clicks on OK without adding name", async ({ - page, - }) => { - // Click on the date-time button - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page - .locator('[data-test="logs-search-saved-views-btn"]') - .getByLabel("Expand") - .click(); - await page - .locator("button") - .filter({ hasText: "savesaved_search" }) - .click(); - await page.locator('[data-test="add-alert-name-input"]'); - const saveButton = await page.locator( - '[data-test="saved-view-dialog-save-btn"]' - ); - await saveButton.scrollIntoViewIfNeeded(); - await saveButton.click({ force: true }); - // await expect(page.locator('.q-notification__message')).toContainText('Please provide valid view name'); - }); - - test("should display the details of logs results on graph", async ({ - page, - }) => { - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page - .locator('[data-test="date-time-relative-6-w-btn"] > .q-btn__content') - .click({ force: true }); - await applyQueryButton(page); - await page.waitForTimeout(5000); - await expect( - page.locator(".search-list > :nth-child(1) > .text-left") - ).toBeVisible(); - await page.waitForTimeout(2000); - await page.locator('[data-test="log-table-column-0-source"]').click(); - await page.waitForTimeout(1000); - await page.locator('[data-test="close-dialog"]').click({ - force: true, - }); - await expect( - page.locator(".search-list > :nth-child(1) > .text-left") - ).not.toBeHidden(); - }); - - test("should click on live mode on button and select 5 sec, switch off, and then click run query", async ({ - page, - }) => { - await page.route("**/logData.ValueQuery", (route) => route.continue()); - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - - await page - .locator('[data-test="date-time-relative-6-w-btn"] > .q-btn__content') - .click({ - force: true, - }); - await page - .locator(".q-pl-sm > .q-btn > .q-btn__content") - .click({ force: true }); - await page.locator('[data-test="logs-search-bar-refresh-time-5"]').click({ - force: true, - }); - await expect(page.locator(".q-notification__message")).toContainText( - "Live mode is enabled" - ); - await page - .locator(".q-pl-sm > .q-btn > .q-btn__content") - .click({ force: true }); - await page - .locator( - '[data-test="logs-search-off-refresh-interval"] > .q-btn__content' - ) - .click({ force: true }); - await applyQueryButton(page); - }); - - test("should click on VRL toggle and display the field, then disable toggle and make the VRL field disappear", async ({ - page, - }) => { - await expect(page.locator("#fnEditor")).toBeVisible(); - await page - .locator( - '[data-test="logs-search-bar-show-query-toggle-btn"] > .q-toggle__inner' - ) - .click({ force: true }); - await expect(page.locator("#fnEditor")).not.toBeVisible(); - }); - - test("should switch from past 6 weeks to past 6 days on date-time UI", async ({ - page, - }) => { - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page - .locator('[data-test="date-time-relative-6-w-btn"] > .q-btn__content') - .click({ force: true }); - await expect(page.locator('[data-test="date-time-btn"]')).toContainText( - "Past 6 Weeks" - ); - await applyQueryButton(page); - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page - .locator('[data-test="date-time-relative-6-d-btn"]') - .click({ force: true }); - await expect(page.locator('[data-test="date-time-btn"]')).toContainText( - "Past 6 Days" - ); - await applyQueryButton(page); - }); - test("should display SQL query on switching between Menu options & navigating to Logs again", async ({ - page, - }) => { - // Intercept the GET request, replace 'logData.ValueQuery' with your actual endpoint - await page.route("**/logData.ValueQuery", (route) => route.continue()); - - // Click on the date-time button - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - - await page.waitForTimeout(1000); - - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - - // Assert that the SQL query is visible - const expectedQuery = - 'SELECT * FROM "e2e_automate"'; - // const text = await page.locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox').textContent(); - // console.log(textval) - const text = await page.evaluate(() => { - const editor = document.querySelector('[data-test="logs-search-bar-query-editor"]').querySelector('.cm-content'); // Adjust selector if needed - return editor ? editor.textContent.trim() : null; - }); - - console.log(text); - await expect(text.replace(/\s/g, "")).toContain( - expectedQuery.replace(/\s/g, "") - ); - await page.locator('[data-test="menu-link-/-item"]').click({ force: true }); - await page - .locator('[data-test="menu-link-/logs-item"]') - .click({ force: true }); - await page.waitForTimeout(2000); - - await page - .locator('[data-test="logs-search-bar-query-editor"]') - .locator(".cm-content") - .locator(".cm-line") - .filter({ hasText: 'SELECT * FROM "e2e_automate"' }) - .nth(0); - }); - test("should display ingested logs - search logs, navigate on another tab, revisit logs page", async ({ - page, - }) => { - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page - .locator( - '[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block' - ) - .click({ force: true }); - await applyQueryButton(page); - await page - .locator('[data-test="menu-link-/traces-item"]') - .click({ force: true }); - await page.waitForTimeout(100); - await page - .locator('[data-test="menu-link-/logs-item"]') - .click({ force: true }); - await page.waitForTimeout(5000); - const barChart = await page.locator( - '[data-test="logs-search-result-bar-chart"]' - ); - await expect(barChart).toBeTruthy(); - }); - - test("should redirect to logs after clicking on stream explorer via stream page", async ({ - page, - }) => { - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page - .locator('[data-test="menu-link-/streams-item"]') - .click({ force: true }); - await page.waitForTimeout(1000); - await page - .locator('[data-test="menu-link-\\/streams-item"]') - .click({ force: true }); - await page.getByPlaceholder("Search Stream").click(); - await page.getByPlaceholder("Search Stream").fill("e2e"); - await page.waitForTimeout(1000); - await page - .getByRole("button", { name: "Explore" }) - .first() - .click({ force: true }); - await expect(page.url()).toContain("logs"); - }); - - test('should display error when save function is clicked without any VRL function', async ({ page }) => { - // await page.locator('[data-test="menu-link-\\/logs-item"]').click(); - await page.locator('[data-test="logs-search-bar-function-dropdown"] button').filter({ hasText: 'save' }).click(); - await page.locator('#q-notify div').filter({ hasText: 'warningNo function definition' }).nth(3).click(); - }); - - test('should create a function and then delete it', async ({ page }) => { - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.locator('[data-test="logs-search-bar-function-dropdown"] button').filter({ hasText: 'save' }).click(); - await page.locator('#fnEditor').getByRole('textbox').fill('.a=2'); - await page.waitForTimeout(1000); - await page.locator('[data-test="logs-search-bar-function-dropdown"] button').filter({ hasText: 'save' }).click(); - await page.locator('[data-test="saved-function-name-input"]').click(); - await page.locator('[data-test="saved-function-name-input"]').fill('e2efunction'); - await page.locator('[data-test="saved-view-dialog-save-btn"]').click(); - // await page.locator('[data-test="menu-link-\\/functions-item"]').click(); - await page.locator('[data-test="menu-link-\\/pipeline-item"]').click(); - await page.locator('[data-test="tab-realtime"]').click(); - - await page.locator('[data-test="function-stream-tab"]').click(); - await page.getByPlaceholder('Search Function').click(); - await page.getByPlaceholder('Search Function').fill('e2e'); - await page.getByRole('button', { name: 'Delete Function' }).click(); - await page.locator('[data-test="confirm-button"]').click(); - }); - - test('should display click save directly while creating a function', async ({ page }) => { - await page.waitForTimeout(1000); - await page.locator('#fnEditor').getByRole('textbox').fill('.a=2'); - await page.waitForTimeout(1000); - await page.locator('[data-test="logs-search-bar-function-dropdown"] button').filter({ hasText: 'save' }).click(); - await page.locator('[data-test="saved-view-dialog-save-btn"]').click(); - await page.getByText('Function name is not valid.').click(); - }); - - test('should display error on adding only blank spaces under function name', async ({ page }) => { - await page.waitForTimeout(1000); - await page.locator('#fnEditor').getByRole('textbox').fill('.a=2'); - await page.waitForTimeout(1000); - await page.locator('[data-test="logs-search-bar-function-dropdown"] button').filter({ hasText: 'save' }).click(); - await page.locator('[data-test="saved-function-name-input"]').fill(' '); - await page.locator('[data-test="saved-view-dialog-save-btn"]').click(); - await page.getByText('Function name is not valid.').click(); - }); - - - test('should display error on adding invalid characters under function name', async ({ page }) => { - await page.waitForTimeout(1000); - await page.locator('#fnEditor').getByRole('textbox').fill('.a=2'); - await page.waitForTimeout(1000); - await page.locator('[data-test="logs-search-bar-function-dropdown"] button').filter({ hasText: 'save' }).click(); - await page.locator('[data-test="saved-function-name-input"]').fill('e2e@@@'); - await page.locator('[data-test="saved-view-dialog-save-btn"]').click(); - await page.getByText('Function name is not valid.').click(); - }); - - test('should display added function on switching between tabs and again navigate to log', async ({ page }) => { - await page.waitForTimeout(1000); - await page.locator('#fnEditor').getByRole('textbox').fill('.a=2'); - await page.waitForTimeout(1000); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.locator('[data-test="menu-link-\\/metrics-item"]').click(); - await page.locator('[data-test="menu-link-\\/logs-item"]').click(); - await page.locator('[data-test="menu-link-/logs-item"]').click({ force: true }); - // Assert that ".a=2" is visible - const logsPage = await page.locator('.q-page-container'); - await expect(logsPage).toContainText(".a=2"); - - }); - - test('should display bar chart when histogram toggle is on', async ({ page }) => { - await page.locator('[data-test="log-search-index-list-field-search-input"]').click(); - await page.locator('[data-test="log-search-index-list-field-search-input"]').fill('code'); - await page.waitForTimeout(4000); - await page.getByLabel('Expand "code"').click(); - await page.waitForTimeout(4000); - // await page.locator('[data-test="logs-search-subfield-add-code-200"] [data-test="log-search-subfield-list-equal-code-field-btn"]').click(); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.locator('[data-test="logs-search-result-bar-chart"] canvas').click({ - }); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.locator('[data-test="logs-search-result-bar-chart"] canvas').click({ - }); - await page.locator('[data-test="logs-search-bar-show-histogram-toggle-btn"] div').nth(2).click(); - }); - - test('should display search around in histogram mode', async ({ page }) => { - await page.waitForTimeout(1000); - await page.locator('[data-test="log-table-column-0-source"]').click(); - await page.locator('[data-test="logs-detail-table-search-around-btn"]').click(); - await page.waitForTimeout(2000); - const element = await page.locator('[data-test="log-table-column-0-source"]'); - const isVisible = await element.isVisible(); - expect(isVisible).toBeTruthy(); - - }); - - - test.skip('should display results for search around after adding function', async ({ page }) => { - await page.waitForTimeout(1000); - await page.locator('#fnEditor').getByRole('textbox').click(); - await page.locator('#fnEditor').getByRole('textbox').fill('.a=1'); - await page.waitForTimeout(1000); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.locator('[data-test="log-table-column-3-source"]').getByText('{"_timestamp":').click(); - await page.locator('[data-test="logs-detail-table-search-around-btn"]').click(); - await page.waitForTimeout(1000); - const element = await page.locator('[data-test="log-table-column-0-source"]'); - const isVisible = await element.isVisible(); - expect(isVisible).toBeTruthy(); - - }); - - test('should display search around in SQL mode', async ({ page }) => { - await page.waitForTimeout(1000); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page.locator('[data-test="log-table-column-0-source"]').click(); - await page.locator('[data-test="logs-detail-table-search-around-btn"]').click(); - await page.waitForTimeout(2000) - const element = await page.locator('[data-test="log-table-column-0-source"]'); - const isVisible = await element.isVisible(); - expect(isVisible).toBeTruthy(); - - }); - - test("should display results for search around with limit query", async ({ page }) => { - await page.waitForTimeout(2000); - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - await page.click('[data-test="logs-search-bar-query-editor"]') - await page.keyboard.type("match_all('code') limit 5"); - await page.waitForTimeout(2000); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page.waitForTimeout(2000); - await page.locator('[data-test="log-table-column-0-source"]').click(); - await page.locator('[data-test="logs-detail-table-search-around-btn"]').click(); - await page.waitForTimeout(2000); - const element = await page.locator('[data-test="log-table-column-0-source"]'); - const isVisible = await element.isVisible(); - expect(isVisible).toBeTruthy(); - await expect(page.locator('[data-test="log-table-column-0-source"]')).toBeVisible(); - }); - - test("should not display pagination for limit query", async ({ page }) => { - await page.waitForTimeout(2000); - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - await page.click('[data-test="logs-search-bar-query-editor"]') - await page.keyboard.type("match_all('code') limit 5"); - await page.waitForTimeout(2000); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page.waitForTimeout(2000); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.waitForTimeout(2000); - const fastRewindElement = page.locator('[data-test="logs-search-result-records-per-page"]').getByText('50'); - await expect(fastRewindElement).not.toBeVisible(); - - }); - - test("should not display pagination for SQL limit query", async ({ page }) => { - await page.waitForTimeout(2000); - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - await page.click('[data-test="logs-search-bar-query-editor"]'); - await page.keyboard.type('SELECT * FROM "e2e_automate" ORDER BY _timestamp DESC limit 5'); - await page.waitForTimeout(2000); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.waitForTimeout(2000); - const fastRewindElement = page.locator('[data-test="logs-search-result-records-per-page"]').getByText('50'); - await expect(fastRewindElement).not.toBeVisible(); - }); - - test("should not display pagination for SQL group/order/limit query", async ({ page }) => { - await page.waitForTimeout(2000); - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - await page.click('[data-test="logs-search-bar-query-editor"]'); - await page.keyboard.type('SELECT * FROM "e2e_automate" WHERE code < 400 GROUP BY code ORDER BY count(*) DESC LIMIT 5'); - await page.waitForTimeout(2000); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.waitForTimeout(2000); - const fastRewindElement = page.locator('[data-test="logs-search-result-records-per-page"]').getByText('50'); - await expect(fastRewindElement).not.toBeVisible(); - }); -}); diff --git a/tests/ui-testing/playwright-tests/logsqueries.spec.js b/tests/ui-testing/playwright-tests/logsqueries.spec.js deleted file mode 100644 index a938343f6f..0000000000 --- a/tests/ui-testing/playwright-tests/logsqueries.spec.js +++ /dev/null @@ -1,331 +0,0 @@ -import { test, expect } from "./baseFixtures"; -import logData from "../../ui-testing/cypress/fixtures/log.json"; -import { LogsPage } from '../pages/logsPage.js'; -import logsdata from "../../test-data/logs_data.json"; - -test.describe.configure({ mode: 'parallel' }); - -async function login(page) { - await page.goto(process.env["ZO_BASE_URL"]); - await page.waitForTimeout(4000); - await page.goto(process.env["ZO_BASE_URL"]); - if (await page.getByText('Login as internal user').isVisible()) { - await page.getByText('Login as internal user').click(); -} - await page - .locator('[data-cy="login-user-id"]') - .fill(process.env["ZO_ROOT_USER_EMAIL"]); - //Enter Password - await page - .locator('[data-cy="login-password"]') - .fill(process.env["ZO_ROOT_USER_PASSWORD"]); - await page.locator('[data-cy="login-sign-in"]').click(); - await page.waitForTimeout(4000); - await page.goto(process.env["ZO_BASE_URL"]); -} - -async function ingestion(page) { - const orgId = process.env["ORGNAME"]; - const streamName = "e2e_automate"; - const basicAuthCredentials = Buffer.from( - `${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}` - ).toString('base64'); - - const headers = { - "Authorization": `Basic ${basicAuthCredentials}`, - "Content-Type": "application/json", - }; - const response = await page.evaluate(async ({ url, headers, orgId, streamName, logsdata }) => { - const fetchResponse = await fetch(`${url}/api/${orgId}/${streamName}/_json`, { - method: 'POST', - headers: headers, - body: JSON.stringify(logsdata) - }); - return await fetchResponse.json(); - }, { - url: process.env.INGESTION_URL, - headers: headers, - orgId: orgId, - streamName: streamName, - logsdata: logsdata - }); - console.log(response); -} -test.describe("Logs Queries testcases", () => { - let logsPage; - // let logData; - function removeUTFCharacters(text) { - // console.log(text, "tex"); - // Remove UTF characters using regular expression - return text.replace(/[^\x00-\x7F]/g, " "); - } - async function applyQueryButton(page) { - // click on the run query button - // Type the value of a variable into an input field - const search = page.waitForResponse(logData.applyQuery); - await page.waitForTimeout(3000); - await page.locator("[data-test='logs-search-bar-refresh-btn']").click({ - force: true, - }); - // get the data from the search variable - await expect.poll(async () => (await search).status()).toBe(200); - // await search.hits.FIXME_should("be.an", "array"); - } - - test.beforeEach(async ({ page }) => { - await login(page); - logsPage = new LogsPage(page); - await page.waitForTimeout(1000) - await ingestion(page); - await page.waitForTimeout(2000) - logsPage = new LogsPage(page); - - await page.goto( - `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` - ); - const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); - await applyQueryButton(page); - // const streams = page.waitForResponse("**/api/default/streams**"); - }); - - test("should display quick mode toggle button", async ({ page }) => { - await expect( - page.locator('[data-test="logs-search-bar-quick-mode-toggle-btn"]') - ).toBeVisible(); - }); - - test.skip("should add timestamp to editor save this view and switch", async ({ page }) => { - await page.waitForTimeout(3000); - await page.locator('[data-test="log-table-column-0-source"]').click(); - - await page.locator(':nth-child(1) > [data-test="log-details-include-exclude-field-btn"] > .q-btn__content > .q-icon').click(); - await page.locator('[data-test="log-details-include-field-btn"]').click(); - await page.locator('[data-test="close-dialog"] > .q-btn__content').click(); - await page.locator('[data-test="logs-search-saved-views-btn"] > .q-btn-dropdown--current > .q-btn__content > :nth-child(1)').click(); - await page.locator('[data-test="add-alert-name-input"]').fill("e2etimestamp"); - await page.locator('[data-test="saved-view-dialog-save-btn"] > .q-btn__content').click(); - await page.locator('[data-test="logs-search-saved-views-btn"] > .q-btn-dropdown__arrow-container > .q-btn__content > .q-icon').click(); - await page.locator('.q-item__label').getByText(/timestamp/).first().click({ force: true }); - await page.waitForTimeout(3000); - await page.locator('[data-test="logs-search-saved-views-btn"]').getByLabel('Expand').click(); - await page.locator('[data-test="log-search-saved-view-field-search-input"]').click(); - await page.locator('[data-test="log-search-saved-view-field-search-input"]').fill('e2e'); - await page.getByTitle('e2etimestamp').click(); - await page.locator('[data-test="logs-search-saved-views-btn"]').getByLabel('Expand').click(); - await page.locator('[data-test="log-search-saved-view-field-search-input"]').click(); - await page.getByTitle('e2etimestamp').click(); - // await page.locator('[data-test="logs-search-saved-views-btn"]').getByLabel('Expand').click(); - await page.getByText('delete').click(); - await page.locator('[data-test="confirm-button"]').click(); - }); - - test("should redirect to logs after clicking on stream explorer via stream page", async ({ page }) => { - // Generate a random saved view name - const randomSavedViewName = `streamslog${Math.random().toString(36).substring(2, 10)}`; - - // Interactions with the page - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.locator('[data-test="logs-search-saved-views-btn"]').getByLabel('Expand').click(); - await page.locator('button').filter({ hasText: 'savesaved_search' }).click(); - await page.locator('[data-test="add-alert-name-input"]').click(); - await page.locator('[data-test="add-alert-name-input"]').fill(randomSavedViewName); // Use the random name - await page.locator('[data-test="saved-view-dialog-save-btn"]').click({ force: true }); - await page.waitForTimeout(5000); - await page.locator('[data-test="menu-link-\\/streams-item"]').click({ force: true }); - await page.getByPlaceholder('Search Stream').click(); - await page.getByPlaceholder('Search Stream').fill('e2e'); - await page.waitForTimeout(1000); - await page.getByRole('button', { name: 'Explore' }).first().click({ force: true }); - await page.waitForTimeout(5000); - await page.waitForSelector('[data-test="logs-search-saved-views-btn"]'); - await page.locator('[data-test="logs-search-saved-views-btn"]').getByLabel('Expand').click(); - await page.locator('[data-test="log-search-saved-view-field-search-input"]').click({ force: true }); - await page.locator('[data-test="log-search-saved-view-field-search-input"]').fill(randomSavedViewName); // Use the random name here - await page.waitForTimeout(3000); - await page.waitForSelector(`:text("${randomSavedViewName}")`); - await page.click(`:text("${randomSavedViewName}")`); - await page.locator('[data-test="logs-search-saved-views-btn"]').getByLabel('Expand').click(); - await page.locator('[data-test="log-search-saved-view-field-search-input"]').click(); - await page.getByTitle(randomSavedViewName).click(); // Use the random name here - - // Dynamic delete button selector using the random saved view name - const deleteButtonSelector = `[data-test="logs-search-bar-delete-${randomSavedViewName}-saved-view-btn"]`; - await page.locator(deleteButtonSelector).click(); // Click delete - await page.locator('[data-test="confirm-button"]').click(); // Confirm deletion - }); - - test("should reset the editor on clicking reset filter button", async ({ page }) => { - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - await page.locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox').click(); - await page.keyboard.type("match_all_raw_ignore_case('provide_credentials')"); - await page.locator('[data-cy="search-bar-refresh-button"] > .q-btn__content').waitFor({ state: "visible" }); - await page.locator("[data-test='logs-search-bar-refresh-btn']").click({ force: true }); - await page.locator('[data-test="logs-search-bar-reset-filters-btn"]').click({ force: true }); - await page.locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox').waitFor({ state: "visible" }); - const text = await page.evaluate(() => { - const editor = document.querySelector('[data-test="logs-search-bar-query-editor"]').querySelector('.cm-content'); - return editor ? editor.textContent : null; - }); - await expect(text).toEqual(""); - }); - - test("should add invalid query and display error", async ({ page }) => { - // Type the value of a variable into an input field - - await page.waitForTimeout(2000); - await page.locator( - '[data-test="date-time-btn"]').click({ force: true }); await page.locator( - - '[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - await page.click('[data-test="logs-search-bar-query-editor"]') - await page.keyboard.type("kubernetes"); - await page.waitForTimeout(2000); - await page.locator('[data-cy="search-bar-refresh-button"] > .q-btn__content').click({ force: true }) - await expect(page.locator('[data-test="logs-search-error-message"]')).toBeVisible(); - }); - - test("should not display error if match all case added in log query search", async ({ page }) => { - // Type the value of a variable into an input field - await page.locator('[data-test="date-time-btn"]').click({ force: true }); - await page.locator('[data-test="date-time-relative-15-m-btn"] > .q-btn__content > .block').click({ force: true }); - - // Ensure the query editor is visible and clickable before typing - const queryEditor = page.locator('[data-test="logs-search-bar-query-editor"]'); - await expect(queryEditor).toBeVisible(); - await queryEditor.click(); - await page.keyboard.type("match_all('code')"); - - // Ensure the refresh button is visible and clickable before clicking - const refreshButton = page.locator('[data-cy="search-bar-refresh-button"] > .q-btn__content'); - await expect(refreshButton).toBeVisible(); - await refreshButton.click({ force: true }); - - // Verify that the expected log table column is visible - await expect(page.locator('[data-test="log-table-column-0-source"]')).toBeVisible(); - }); - - - - test("should change stream settings and click on search stream", async ({ page }) => { - // Type the value of a variable into an input field - await page.locator('[data-test="menu-link-/streams-item"]').click({ force: true }); - await page.waitForTimeout(3000); - await page.click('[data-test="streams-search-stream-input"]') - await page.keyboard.type("e2e_automate"); - await page.waitForTimeout(2000); - await page.locator("[title=\"Stream Detail\"]").first().click({ force: true }); - await page.locator(':nth-child(2) > [data-test="schema-stream-index-select"]').click(); - const scope = page.locator(".q-virtual-scroll__content"); - await scope.getByText(/Full text search/).first().click(); - await page.locator('[data-test="schema-update-settings-button"]').click({ force: true }); - await page.waitForTimeout(3000); - await page.locator(".col-auto > .q-btn > .q-btn__content").click({ force: true }); - await page.waitForTimeout(3000); - await page.locator("[title=\"Explore\"]").first().click({ force: true }); - await expect(page.locator('[data-test="log-table-column-0-source"]')).toBeVisible(); - }); - - - test("should display error if blank spaces added under stream name and clicked create stream ", async ({ page }) => { - await page.locator('[data-test="menu-link-/streams-item"]').click({ force: true }); - await page.locator('[data-test="log-stream-add-stream-btn"]').click({ force: true }); - await page.click('[data-test="add-stream-name-input"]') - await page.keyboard.type(" "); - await page.locator('[data-test="save-stream-btn"]').click({ force: true }); - await expect(page.getByText(/Field is required/).first()).toBeVisible(); - }); - - - - test("should display error if create stream is clicked without adding name", async ({ page }) => { - await page.locator('[data-test="menu-link-/streams-item"]').click({ force: true }); - await page.locator('[data-test="log-stream-add-stream-btn"]').click({ force: true }); - await page.locator('[data-test="save-stream-btn"]').waitFor({ state: "visible" }); - await page.locator('[data-test="save-stream-btn"]').scrollIntoViewIfNeeded(); - await page.locator('[data-test="save-stream-btn"]').click({ force: true }); - await expect(page.getByText(/Field is required/).first()).toBeVisible(); - }); - - test("should display enter count query", async ({ page }) => { - await page.locator('[data-test="logs-search-bar-query-editor"]').getByRole('textbox').click(); - // await page.click('.cm-lines') - await page.keyboard.type('SELECT COUNT(_timestamp) AS xyz, _timestamp FROM "e2e_automate" Group by _timestamp ORDER BY _timestamp DESC'); - await page.waitForTimeout(4000); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await expect(page.locator( - '[data-cy="search-bar-refresh-button"] > .q-btn__content')).toBeVisible(); await page.waitForTimeout( - 3000); await page.locator( - "[data-test='logs-search-bar-refresh-btn']").click({ - - force: true - }); - await page.waitForTimeout(4000); - await expect(page.getByRole('heading', { name: 'Error while fetching' })).not.toBeVisible(); - await page.locator('[data-test="logs-search-result-bar-chart"] canvas').click({ - position: { - x: 182, - y: 66 - } - }); - - }); - - test("should display values API text successfully and error to not be displayed", async ({ page }) => { - await page.locator('[data-test="log-search-index-list-field-search-input"]').fill('kubernetes_pod_name'); - await page.getByLabel('Expand "kubernetes_pod_name"').click(); - const errorMessage = page.getByText('Error while fetching field values'); - await expect(errorMessage).not.toBeVisible(); - await page.getByText('ziox-ingester-').click(); - await page.locator('[data-test="logs-search-bar-refresh-btn"]').click(); - await page.getByLabel('Collapse "kubernetes_pod_name"').click(); - await page.getByLabel('Expand "kubernetes_pod_name"').click(); - const targetElement = page.locator('[data-test="logs-search-subfield-add-kubernetes_pod_name-ziox-ingester-0"]').getByText('ziox-ingester-'); - await expect(targetElement).toBeVisible(); // Assertion to ensure visibility - await targetElement.click() - }); - - test("should display results in selected time", async ({ - page, - }) => { - - await logsPage.setDateTimeToToday(); - - - }); - - test("should display results if stringmatch ignorecase lowercase added in log query search", async ({ page }) => { - await logsPage.setDateTimeTo15Minutes(); - await logsPage.searchWithStringMatchIgnoreCase('ziox'); - }); - - test("should display results if stringmatch ignorecase uppercase added in log query search", async ({ page }) => { - await logsPage.setDateTimeTo15Minutes(); - await logsPage.searchWithStringMatchIgnoreCase('Ziox'); - }); - - test("should trigger search results when pressing Cmd+Enter or Ctrl+Enter", async ({ page }) => { - await logsPage.executeQueryWithKeyboardShortcutTest(); - }); - - test("should execute query with keyboard shortcut (Cmd+Enter or Ctrl+Enter) after clicking elsewhere ", async ({ page }) => { - await logsPage.executeQueryWithKeyboardShortcutAfterClickingElsewhere(); - }); - - test("should execute different query with keyboard shortcut (Cmd+Enter or Ctrl+Enter)", async ({ page }) => { - await logsPage.executeQueryWithKeyboardShortcutWithDifferentQuery(); - }); - - test("should execute SQL query with keyboard shortcut (Cmd+Enter or Ctrl+Enter)", async ({ page }) => { - await logsPage.executeQueryWithKeyboardShortcutWithSQLMode(); - }); - - test("should verify logcount ordering in ascending and descending order", async ({ page }) => { - // Verify descending order - await logsPage.verifyLogCountOrderingDescending(); - - // Verify ascending order - await logsPage.verifyLogCountOrderingAscending(); - }); -}) \ No newline at end of file diff --git a/tests/ui-testing/playwright-tests/logsquickmode.spec.js b/tests/ui-testing/playwright-tests/logsquickmode.spec.js deleted file mode 100644 index 42b1734a5f..0000000000 --- a/tests/ui-testing/playwright-tests/logsquickmode.spec.js +++ /dev/null @@ -1,315 +0,0 @@ -import { test, expect } from "./baseFixtures"; -import logData from "../../ui-testing/cypress/fixtures/log.json"; -import logsdata from "../../test-data/logs_data.json"; -import { LogsPage } from '../pages/logsPage.js'; - -test.describe.configure({ mode: 'parallel' }); - -async function login(page) { - await page.goto(process.env["ZO_BASE_URL"]); - if (await page.getByText('Login as internal user').isVisible()) { - await page.getByText('Login as internal user').click(); -} - - console.log("ZO_BASE_URL", process.env["ZO_BASE_URL"]); - await page.waitForTimeout(1000); - await page - .locator('[data-cy="login-user-id"]') - .fill(process.env["ZO_ROOT_USER_EMAIL"]); - //Enter Password - await page - .locator('[data-cy="login-password"]') - .fill(process.env["ZO_ROOT_USER_PASSWORD"]); - await page.locator('[data-cy="login-sign-in"]').click(); - await page.waitForTimeout(4000); - await page.goto(process.env["ZO_BASE_URL"]); -} - -async function ingestion(page) { - const orgId = process.env["ORGNAME"]; - const streamName = "e2e_automate"; - const basicAuthCredentials = Buffer.from( - `${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}` - ).toString('base64'); - - const headers = { - "Authorization": `Basic ${basicAuthCredentials}`, - "Content-Type": "application/json", - }; - const response = await page.evaluate(async ({ url, headers, orgId, streamName, logsdata }) => { - const fetchResponse = await fetch(`${url}/api/${orgId}/${streamName}/_json`, { - method: 'POST', - headers: headers, - body: JSON.stringify(logsdata) - }); - return await fetchResponse.json(); - }, { - url: process.env.INGESTION_URL, - headers: headers, - orgId: orgId, - streamName: streamName, - logsdata: logsdata - }); - console.log(response); -} - - - -test.describe("Logs Quickmode testcases", () => { - let logsPage; - // let logData; - function removeUTFCharacters(text) { - // console.log(text, "tex"); - // Remove UTF characters using regular expression - return text.replace(/[^\x00-\x7F]/g, " "); - } - async function applyQueryButton(page) { - // click on the run query button - // Type the value of a variable into an input field - const search = page.waitForResponse(logData.applyQuery); - await page.waitForTimeout(3000); - await page.locator("[data-test='logs-search-bar-refresh-btn']").click({ - force: true, - }); - // get the data from the search variable - await expect.poll(async () => (await search).status()).toBe(200); - // await search.hits.FIXME_should("be.an", "array"); - } - - test.beforeEach(async ({ page }) => { - await login(page); - logsPage = new LogsPage(page); - await page.waitForTimeout(1000) - await ingestion(page); - await page.waitForTimeout(2000) - - await page.goto( - `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` - ); - const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); - - await applyQueryButton(page); - - // Get the toggle button element - const toggleButton = await page.$('[data-test="logs-search-bar-quick-mode-toggle-btn"] > .q-toggle__inner'); - // Evaluate the class attribute to determine if the toggle is in the off state - const isSwitchedOff = await toggleButton.evaluate(node => node.classList.contains('q-toggle__inner--falsy')); - // If the toggle is switched off, click on it to switch it on - if (isSwitchedOff) { - await toggleButton.click(); - } - // const streams = page.waitForResponse("**/api/default/streams**"); - }); - test("should click on interesting fields icon and display query in editor", async ({ - page, - }) => { - await page - .locator('[data-cy="index-field-search-input"]') - .fill("kubernetes_pod_id"); - await page.waitForTimeout(2000); - await page - .locator( - '[data-test="log-search-index-list-interesting-kubernetes_pod_id-field-btn"]' - ) - .first() - .click(); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page.waitForTimeout(2000); - await expect( - page - .locator('[data-test="logs-search-bar-query-editor"]') - .getByText(/kubernetes_pod_id/) - .first() - ).toBeVisible(); - }); - test("should display quick mode toggle button", async ({ page }) => { - await expect( - page.locator('[data-test="logs-search-bar-quick-mode-toggle-btn"]') - ).toBeVisible(); - }); - - test("should click on interesting fields icon in histogram mode and run query", async ({ - page, - }) => { - await page - .locator('[data-cy="index-field-search-input"]') - .fill("kubernetes_pod_id"); - await page.waitForTimeout(2000); - await page - .locator( - '[data-test="log-search-index-list-interesting-kubernetes_pod_id-field-btn"]' - ) - .first() - .click(); - await page - .locator('[data-cy="search-bar-refresh-button"] > .q-btn__content') - .click(); - await page.waitForTimeout(2000); - await expect( - page - .locator('[data-test="log-table-column-0-source"]') - .getByText(/kubernetes_pod_id/) - // .getByText(/_timestamp/) - .first() - ).toBeVisible(); - }); - - test("should display error on entering random text in histogram mode when quick mode is on", async ({ page }) => { - await page.waitForTimeout(2000) - // Click on the Monaco Editor to focus it - await page.click('[data-test="logs-search-bar-query-editor"]'); - // Type into the Monaco Editor - await page.keyboard.type("oooo"); - await page.waitForTimeout(1000) - await page.waitForSelector('[data-cy="search-bar-refresh-button"] > .q-btn__content', { visible: true, timeout: 5000 }); - - // Click on the refresh button - await page.click('[data-cy="search-bar-refresh-button"] > .q-btn__content', { force: true }); - - await page.waitForTimeout(2000) - // Wait for the error message to appear and ensure it is visible - await expect(page.locator('[data-test="logs-search-error-message"]').first()).toBeVisible({ timeout: 10000 }); - }); - - test("should display selected interestesing field and order by - as default in editor", async ({ - page, - }) => { - await page - .locator('[data-cy="index-field-search-input"]') - .fill("kubernetes_pod_id"); - await page.waitForTimeout(2000); - await page - .locator( - '[data-test="log-search-index-list-interesting-kubernetes_pod_id-field-btn"]' - ) - .first() - .click(); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page.waitForSelector('[data-test="logs-search-bar-query-editor"]'); - await expect( - page.locator('[data-test="logs-search-bar-query-editor"]') - ).toBeVisible(); - - - }); - - test("should adding/removing interesting field removes it from editor and results too", async ({ - page, - }) => { - await page - .locator('[data-cy="index-field-search-input"]') - .fill("kubernetes_container_name"); - await page.waitForTimeout(2000); - await page - .locator( - '[data-test="log-search-index-list-interesting-kubernetes_container_name-field-btn"]' - ) - .first() - .click(); - await page.locator('[data-cy="index-field-search-input"]').clear(); - await page - .locator('[data-cy="index-field-search-input"]') - .fill("level"); - await page.waitForTimeout(2000); - await page - .locator( - '[data-test="log-search-index-list-interesting-level-field-btn"]' - ) - .last() - .click({ - force: true, - }); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page - .locator('[data-cy="search-bar-refresh-button"] > .q-btn__content') - .click({ - force: true, - }); - await expect( - page - .locator('[data-test="log-table-column-0-source"]') - // .locator('text=_timestamp') - ).toBeVisible(); - await page - .locator( - '[data-test="log-search-index-list-interesting-level-field-btn"]' - ) - .last() - .click({ - force: true, - }); - await expect( - page.locator('[data-test="logs-search-bar-query-editor"]') - ).not.toHaveText(/level/); - await page - .locator('[data-cy="search-bar-refresh-button"] > .q-btn__content') - .click(); - await expect( - page.locator('[data-test="log-table-column-1-source"]') - ).not.toHaveText(/source/); - }); - - test("should display order by in sql mode by default even after page reload", async ({ - page, - }) => { - await page - .locator('[data-cy="index-field-search-input"]') - .fill("kubernetes_pod_id"); - await page.waitForTimeout(2000); - await page - .locator( - '[data-test="log-search-index-list-interesting-kubernetes_pod_id-field-btn"]' - ) - .last() - .click({ - force: true, - }); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page - .locator('[data-cy="search-bar-refresh-button"] > .q-btn__content') - .click({ - force: true, - }); - await page.reload(); - await page.waitForTimeout(2000); - await expect( - page - .locator('[data-test="logs-search-bar-query-editor"]') - .locator( - 'text=SELECT kubernetes_pod_id FROM "e2e_automate"' - ) - ).toBeVisible(); - }); - - test("should display results without adding timestamp in quick mode", async ({ - page, - }) => { - - await page.locator('[data-cy="index-field-search-input"]').clear(); - await page - .locator('[data-cy="index-field-search-input"]') - .fill("kubernetes_pod_id"); - await page.waitForTimeout(2000); - await page - .locator( - '[data-test="log-search-index-list-interesting-kubernetes_pod_id-field-btn"]' - ) - .last() - .click({ - force: true, - }); - await page.getByRole('switch', { name: 'SQL Mode' }).locator('div').nth(2).click(); - await page.waitForTimeout(2000); - await page - .locator('[data-cy="search-bar-refresh-button"] > .q-btn__content') - .click({ - force: true, - }); - await page.waitForTimeout(2000); - await expect( - page - .locator('[data-test="log-search-result-table-th-source"]') - ).toHaveText(/source/); - }); -}); diff --git a/tests/ui-testing/playwright-tests/multiselect-stream.spec.js b/tests/ui-testing/playwright-tests/multiselect-stream.spec.js index 78687901cb..0bde7085cb 100644 --- a/tests/ui-testing/playwright-tests/multiselect-stream.spec.js +++ b/tests/ui-testing/playwright-tests/multiselect-stream.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "./baseFixtures"; import logData from "../../ui-testing/cypress/fixtures/log.json"; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; test.describe.configure({ mode: "parallel" }); @@ -97,7 +97,7 @@ test.describe("Stream multiselect testcases", () => { `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` ); const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); + await logsPage.selectStream("e2e_automate"); await applyQueryButton(page); await logsPage.clickQuickModeToggle(); diff --git a/tests/ui-testing/playwright-tests/pagination.spec.js b/tests/ui-testing/playwright-tests/pagination.spec.js index c90ab01e78..d7f1d3d541 100644 --- a/tests/ui-testing/playwright-tests/pagination.spec.js +++ b/tests/ui-testing/playwright-tests/pagination.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "./baseFixtures.js"; import { LoginPage } from '../pages/loginPage.js'; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; import { IngestionPage } from '../pages/ingestionPage.js'; import { ManagementPage } from '../pages/managementPage.js'; @@ -39,13 +39,15 @@ test.describe("Pagination for logs", () => { await logsPage.selectIndexStream(streamName); console.log(streamName); await logsPage.typeQuery(`SELECT * FROM "${streamName}" WHERE match_all("2022-12-27T14:11:27Z INFO zinc_enl")`); - await page.waitForTimeout(2000); + await page.waitForTimeout(3000); // Wait for query preparation await logsPage.selectRunQuery(); - await page.waitForTimeout(2000); + await page.waitForTimeout(3000); // Wait for query results await logsPage.clickResultsPerPage(); - await logsPage.selectResultsPerPageAndVerify('2', 'Showing 11 to 20 out of 39'); - await logsPage.selectResultsPerPageAndVerify('3', 'Showing 21 to 30 out of 39'); - await logsPage.selectResultsPerPageAndVerify('4', 'Showing 31 to 39 out of 39'); + await logsPage.selectResultsPerPageAndVerify('2', 'Showing 11 to 20 out of'); + await page.waitForTimeout(1000); // Wait for pagination change + await logsPage.selectResultsPerPageAndVerify('3', 'Showing 21 to 30 out of'); + await page.waitForTimeout(1000); // Wait for pagination change + await logsPage.selectResultsPerPageAndVerify('4', 'Showing 31 to'); }); test("HTTP Pagination for running query to validate WHERE match_all('zin*')", async ({ page }) => { @@ -103,9 +105,9 @@ test.describe("Pagination for logs", () => { await logsPage.selectRunQuery(); await page.waitForTimeout(2000); await logsPage.clickResultsPerPage(); - await logsPage.selectResultsPerPageAndVerify('2', 'Showing 11 to 20 out of 39'); - await logsPage.selectResultsPerPageAndVerify('3', 'Showing 21 to 30 out of 39'); - await logsPage.selectResultsPerPageAndVerify('4', 'Showing 31 to 39 out of 39'); + await logsPage.selectResultsPerPageAndVerify('2', 'Showing 11 to 20 out of'); + await logsPage.selectResultsPerPageAndVerify('3', 'Showing 21 to 30 out of'); + await logsPage.selectResultsPerPageAndVerify('4', 'Showing 31 to'); }); test("Enable Streaming for running query to validate WHERE match_all('zin*')", async ({ page }) => { diff --git a/tests/ui-testing/playwright-tests/pipeline-core.spec.js b/tests/ui-testing/playwright-tests/pipeline-core.spec.js index 7b0635da1c..56898b3141 100644 --- a/tests/ui-testing/playwright-tests/pipeline-core.spec.js +++ b/tests/ui-testing/playwright-tests/pipeline-core.spec.js @@ -2,7 +2,7 @@ import { test, expect } from "./baseFixtures"; import logData from "../../ui-testing/cypress/fixtures/log.json"; import logsdata from "../../test-data/logs_data.json"; import PipelinePage from "../pages/pipelinePage"; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; test.describe.configure({ mode: "parallel" }); @@ -111,7 +111,7 @@ test.describe("Core Pipeline Tests", () => { await page.goto( `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` ); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); + await logsPage.selectStream("e2e_automate"); await applyQueryButton(page); }); diff --git a/tests/ui-testing/playwright-tests/pipelines.spec.js b/tests/ui-testing/playwright-tests/pipelines.spec.js index 034e6a3e0e..82956b3e99 100644 --- a/tests/ui-testing/playwright-tests/pipelines.spec.js +++ b/tests/ui-testing/playwright-tests/pipelines.spec.js @@ -3,7 +3,7 @@ import logData from "../../ui-testing/cypress/fixtures/log.json"; // import { log } from "console"; import logsdata from "../../test-data/logs_data.json"; import PipelinePage from "../pages/pipelinePage"; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; test.describe.configure({ mode: "parallel" }); @@ -176,7 +176,7 @@ test.describe("Pipeline testcases", () => { `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` ); const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); + await logsPage.selectStream("e2e_automate"); await applyQueryButton(page); }); diff --git a/tests/ui-testing/playwright-tests/region.spec.js b/tests/ui-testing/playwright-tests/region.spec.js index 889bbe18d1..5468470ddc 100644 --- a/tests/ui-testing/playwright-tests/region.spec.js +++ b/tests/ui-testing/playwright-tests/region.spec.js @@ -25,7 +25,7 @@ async function login(page) { } -const selectStreamAndStreamTypeForLogs = async (page,stream) => {await page.waitForTimeout( +const selectStream = async (page,stream) => {await page.waitForTimeout( 4000);await page.locator( '[data-test="log-search-index-list-select-stream"]').click({ force: true });await page.locator( "div.q-item").getByText(`${stream}`).first().click({ force: true }); @@ -99,7 +99,7 @@ test.describe("Region testcases", () => { `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` ); const allsearch = page.waitForResponse("**/api/default/_search**"); - await selectStreamAndStreamTypeForLogs(page,logData.Stream); + await selectStream(page,logData.Stream); await applyQueryButton(page); const searchBarRegionBtn = await page.locator('[data-test="logs-search-bar-region-btn"]'); if (!(await searchBarRegionBtn.isVisible())) { diff --git a/tests/ui-testing/playwright-tests/remotepipeline.spec.js b/tests/ui-testing/playwright-tests/remotepipeline.spec.js index 3a5cf28003..0b973b7538 100644 --- a/tests/ui-testing/playwright-tests/remotepipeline.spec.js +++ b/tests/ui-testing/playwright-tests/remotepipeline.spec.js @@ -89,7 +89,7 @@ async function ingestion(page) { console.log(response); } -const selectStreamAndStreamTypeForLogs = async (page, stream) => { +const selectStream = async (page, stream) => { await page.waitForTimeout(4000); await page .locator('[data-test="log-search-index-list-select-stream"]') @@ -243,7 +243,7 @@ test.describe("Pipeline testcases", () => { `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` ); const allsearch = page.waitForResponse("**/api/default/_search**"); - await selectStreamAndStreamTypeForLogs(page, logData.Stream); + await selectStream(page, logData.Stream); await applyQueryButton(page); //this only be called when no authorization token is present so that the remote will destination will be the same as the environment if (AuthorizationToken.length == 0) { diff --git a/tests/ui-testing/playwright-tests/sanity.spec.js b/tests/ui-testing/playwright-tests/sanity.spec.js index c71ebca010..f8a37c6129 100644 --- a/tests/ui-testing/playwright-tests/sanity.spec.js +++ b/tests/ui-testing/playwright-tests/sanity.spec.js @@ -2,7 +2,7 @@ import { test, expect } from './baseFixtures'; import logData from "../../ui-testing/cypress/fixtures/log.json"; import logsdata from "../../test-data/logs_data.json"; import { toZonedTime } from "date-fns-tz"; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; test.describe.configure({ mode: "parallel" }); const folderName = `Folder ${Date.now()}`; @@ -89,7 +89,7 @@ test.describe("Sanity testcases", () => { `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` ); const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); + await logsPage.selectStream("e2e_automate"); await applyQueryButton(page); // const streams = page.waitForResponse("**/api/default/streams**"); }); diff --git a/tests/ui-testing/playwright-tests/sanity2.spec.js b/tests/ui-testing/playwright-tests/sanity2.spec.js index 42608c812f..441502e65b 100644 --- a/tests/ui-testing/playwright-tests/sanity2.spec.js +++ b/tests/ui-testing/playwright-tests/sanity2.spec.js @@ -2,7 +2,7 @@ import { test, expect } from './baseFixtures'; import logData from "../cypress/fixtures/log.json"; import logsdata from "../../test-data/logs_data.json"; import { toZonedTime } from "date-fns-tz"; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; test.describe.configure({ mode: "parallel" }); const folderName = `Folder ${Date.now()}`; @@ -89,7 +89,7 @@ test.describe("Sanity testcases", () => { `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` ); const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); + await logsPage.selectStream("e2e_automate"); await applyQueryButton(page); // const streams = page.waitForResponse("**/api/default/streams**"); }); diff --git a/tests/ui-testing/playwright-tests/schema.spec.js b/tests/ui-testing/playwright-tests/schema.spec.js index a9c2d28071..cad20ce6e7 100644 --- a/tests/ui-testing/playwright-tests/schema.spec.js +++ b/tests/ui-testing/playwright-tests/schema.spec.js @@ -1,7 +1,7 @@ import { test, expect } from "./baseFixtures"; import logData from "../../ui-testing/cypress/fixtures/log.json"; import logsdata from "../../test-data/logs_data.json"; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; test.describe.configure({ mode: 'parallel' }); const streamName = `stream${Date.now()}`; @@ -82,7 +82,7 @@ test.describe("Schema testcases", () => { `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` ); const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); + await logsPage.selectStream("e2e_automate"); await applyQueryButton(page); }); diff --git a/tests/ui-testing/playwright-tests/schemaload.spec.js b/tests/ui-testing/playwright-tests/schemaload.spec.js index d404a55ca3..4fe545047c 100644 --- a/tests/ui-testing/playwright-tests/schemaload.spec.js +++ b/tests/ui-testing/playwright-tests/schemaload.spec.js @@ -1,6 +1,6 @@ import { test, expect } from './baseFixtures'; import logData from "../../ui-testing/cypress/fixtures/log.json"; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; test.describe.configure({ mode: "parallel" }); diff --git a/tests/ui-testing/playwright-tests/searchpartition.spec.js b/tests/ui-testing/playwright-tests/searchpartition.spec.js index 4bcefaa125..64c2fff109 100644 --- a/tests/ui-testing/playwright-tests/searchpartition.spec.js +++ b/tests/ui-testing/playwright-tests/searchpartition.spec.js @@ -1,7 +1,7 @@ import { test, expect } from './baseFixtures.js'; import logData from "../cypress/fixtures/log.json"; import logsdata from "../../test-data/logs_data.json"; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; test.describe.configure({ mode: "parallel" }); @@ -95,6 +95,7 @@ test.describe("Search Partition Tests", () => { expect(matchingCall.sql).toContain('SELECT histogram(_timestamp'); } } else { + await logsPage.clickRunQueryButton(); await logsPage.verifyStreamingModeResponse(); } diff --git a/tests/ui-testing/playwright-tests/secondsPrecisionAdded.spec.js b/tests/ui-testing/playwright-tests/secondsPrecisionAdded.spec.js index b395339b83..f6b3657ac7 100644 --- a/tests/ui-testing/playwright-tests/secondsPrecisionAdded.spec.js +++ b/tests/ui-testing/playwright-tests/secondsPrecisionAdded.spec.js @@ -1,7 +1,7 @@ // Implementation test.spec.js import { test, expect } from "./baseFixtures"; import { LoginPage } from '../pages/loginPage.js'; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; import { startTimeValue, endTimeValue } from '../pages/CommonLocator.js'; diff --git a/tests/ui-testing/playwright-tests/streaming.spec.js.backup b/tests/ui-testing/playwright-tests/streaming.spec.js.backup deleted file mode 100644 index 739fb62dbf..0000000000 --- a/tests/ui-testing/playwright-tests/streaming.spec.js.backup +++ /dev/null @@ -1,220 +0,0 @@ -import { test, expect } from "./baseFixtures.js"; -import { LoginPage } from '../pages/loginPage.js'; -import { LogsPage } from '../pages/logsPage.js'; -import { IngestionPage } from '../pages/ingestionPage.js'; -import { ManagementPage } from '../pages/managementPage.js'; - - - -test.describe.configure({ mode: 'parallel' }); - -test.describe("Streaming for logs", () => { - let loginPage, logsPage, ingestionPage, managementPage; - - test.beforeEach(async ({ page }) => { - loginPage = new LoginPage(page); - ingestionPage = new IngestionPage(page); - logsPage = new LogsPage(page); - managementPage = new ManagementPage(page); - await loginPage.gotoLoginPage(); - await loginPage.loginAsInternalUser(); - await loginPage.login(); // Login as root user - await ingestionPage.ingestion(); - await ingestionPage.ingestionJoin(); - await managementPage.goToManagement(); - await page.waitForTimeout(5000); - await managementPage.checkStreaming(); - }); - - test("Run query after selecting two streams after enabling streaming", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - await logsPage.displayTwoStreams(); - await logsPage.selectRunQuery(); - - - }); - - test("Enable Streaming for running query after selecting two streams and SQL Mode On", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - // await logsPage.enableSQLMode(); - await logsPage.selectRunQuery(); - await logsPage.displayTwoStreams(); - - - }); - - test("Enable Streaming for running query after selecting two streams, selecting field and SQL Mode On", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - await logsPage.kubernetesContainerName(); - // await logsPage.enableSQLMode(); - await logsPage.selectRunQuery(); - await logsPage.validateResult(); - - - }); - - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering join queries", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - await logsPage.kubernetesContainerNameJoin(); - // await logsPage.enableSQLMode(); - await logsPage.selectRunQuery(); - await logsPage.displayCountQuery(); - await logsPage.validateResult(); - - - }); - - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering join limit", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - await logsPage.kubernetesContainerNameJoinLimit(); - // await logsPage.enableSQLMode(); - await logsPage.selectRunQuery(); - await logsPage.validateResult(); - - - }); - - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering join like", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - await logsPage.kubernetesContainerNameJoinLike(); - await logsPage.enableSQLMode(); - await logsPage.selectRunQuery(); - await logsPage.validateResult(); - - - - }); - - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering Left join queries", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - await logsPage.kubernetesContainerNameLeftJoin(); - await logsPage.enableSQLMode(); - await logsPage.selectRunQuery(); - await logsPage.validateResult(); - - - }); - - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering Right join queries", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - await logsPage.kubernetesContainerNameRightJoin(); - await logsPage.enableSQLMode(); - await logsPage.selectRunQuery(); - await logsPage.validateResult(); - - - }); - - test("Enable Streaming for running query after selecting two streams, SQL Mode On and entering Full join queries", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - await logsPage.kubernetesContainerNameFullJoin(); - // await logsPage.enableSQLMode(); - await logsPage.selectRunQuery(); - await logsPage.validateResult(); - - - }); - - test("Enable Streaming for clicking on interesting field icon and display field in editor", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - await logsPage.enableSQLMode(); - await logsPage.clickQuickModeToggle(); - await logsPage.selectRunQuery(); - await logsPage.clickInterestingFields(); - await logsPage.validateInterestingFields(); - }); - - test("Enable Streaming for clicking on interesting field icon and display query in editor", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - await logsPage.enableSQLMode(); - await logsPage.clickQuickModeToggle(); - await logsPage.selectRunQuery(); - await logsPage.clickInterestingFields(); - await logsPage.validateInterestingFieldsQuery(); - }); - - test("Enable Streaming for Adding or removing interesting field removes it from editor and results too", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexAndStreamJoin(); - // await logsPage.enableSQLMode(); - await logsPage.clickQuickModeToggle(); - await logsPage.selectRunQuery(); - await logsPage.clickInterestingFields(); - await logsPage.addRemoveInteresting(); - }); - - test("Streaming enabled histogram is disabled and run query, results appear and then user switches on Histogram, getting error", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexStreamDefault(); - await logsPage.selectRunQuery(); - await logsPage.toggleHistogram(); - await logsPage.selectRunQuery(); - - await logsPage.toggleHistogram(); - - // Check that the error message is not visible - const errorHeading = page.getByRole('heading', { name: 'Error while fetching' }); - await expect(errorHeading).not.toBeVisible(); - - // Ensure that the error details button is also not visible or disabled - const errorDetailsButton = page.locator('[data-test="logs-page-histogram-error-details-btn"]'); - await expect(errorDetailsButton).not.toBeVisible(); - - - }); - - test("No Histogram should be displayed if Data is not available", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexStreamDefault(); - await logsPage.enableSQLMode(); - await logsPage.clearAndFillQueryEditor('SELECT count(_timestamp) FROM "default" where code = 201'); - await page.waitForTimeout(1000); - await logsPage.selectRunQuery(); - await logsPage.waitForSearchResultAndCheckText('warning No data found for histogram.'); - - }); - - test("Histogram should be displayed if it is enabled again and data is available", async ({ page }) => { - - await logsPage.navigateToLogs(); - await logsPage.selectIndexStreamDefault(); - await logsPage.enableSQLMode(); - await logsPage.clearAndFillQueryEditor('SELECT count(_timestamp) FROM "default" where code = 200'); - await page.waitForTimeout(1000); - await logsPage.selectRunQuery(); - await expect(page.locator('[data-test="logs-search-result-bar-chart"] canvas')).toBeVisible(); - await logsPage.toggleHistogram(); - await logsPage.selectRunQuery(); - await expect(page.locator('[data-test="logs-search-result-bar-chart"] canvas')).not.toBeVisible(); - await logsPage.toggleHistogram(); - await logsPage.selectRunQuery(); - await expect(page.locator('[data-test="logs-search-result-bar-chart"] canvas')).toBeVisible(); - - }); - -}); diff --git a/tests/ui-testing/playwright-tests/streamname.spec.js.backup b/tests/ui-testing/playwright-tests/streamname.spec.js.backup deleted file mode 100644 index 96149ab0c8..0000000000 --- a/tests/ui-testing/playwright-tests/streamname.spec.js.backup +++ /dev/null @@ -1,64 +0,0 @@ -import { test, expect } from "./baseFixtures"; -import { LogsPage } from '../pages/logsPage.js'; -import { StreamPage } from '../pages/streamPage.js'; -import { getHeaders, getIngestionUrl, sendRequest } from '../utils/apiUtils.js'; - -test.describe.configure({ mode: "parallel" }); - -async function login(page) { - await page.goto(process.env["ZO_BASE_URL"]); - await page.waitForTimeout(1000); - if (await page.getByText('Login as internal user').isVisible()) { - await page.getByText('Login as internal user').click(); - } - - await page.locator('[data-cy="login-user-id"]').fill(process.env["ZO_ROOT_USER_EMAIL"]); - await page.locator("label").filter({ hasText: "Password *" }).click(); - await page.locator('[data-cy="login-password"]').fill(process.env["ZO_ROOT_USER_PASSWORD"]); - await page.locator('[data-cy="login-sign-in"]').click(); -} - -test.describe("Stream multiselect testcases", () => { - let logsPage; - let streamPage; - - test.beforeEach(async ({ page }) => { - await login(page); - logsPage = new LogsPage(page); - streamPage = new StreamPage(page); - await page.waitForTimeout(5000); - }); - - test("should preserve stream name casing after ingestion and show in stream explorer", async ({ page }) => { - const orgId = process.env["ORGNAME"]; - const headers = getHeaders(); - - const streams = [ - { name: "MyUpperStream1" }, - { name: "mylowerstream1" }, - ]; - - // Ingest data into streams - for (const stream of streams) { - const ingestionUrl = getIngestionUrl(orgId, stream.name); - const payload = { - level: "info", - job: "test", - log: `test message for stream ${stream.name}`, - e2e: "1", - }; - const response = await sendRequest(page, ingestionUrl, payload, headers); - console.log(`Ingested to ${stream.name}:`, response); - } - - // Validate streams in Stream Explorer - for (const stream of streams) { - await streamPage.navigateToStreamExplorer(); - await streamPage.searchStream(stream.name); - await streamPage.verifyStreamNameVisibility(stream.name); - await streamPage.exploreStream(); - await streamPage.verifyStreamExploration(); - await streamPage.goBack(); - } - }); -}); diff --git a/tests/ui-testing/playwright-tests/unflattened.spec.js b/tests/ui-testing/playwright-tests/unflattened.spec.js index bb6348bbfc..c841e8ad1a 100644 --- a/tests/ui-testing/playwright-tests/unflattened.spec.js +++ b/tests/ui-testing/playwright-tests/unflattened.spec.js @@ -2,7 +2,7 @@ import { test, expect } from "./baseFixtures"; import logData from "../../ui-testing/cypress/fixtures/log.json"; import logsdata from "../../test-data/logs_data.json"; import UnflattenedPage from "../pages/unflattened"; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; test.describe.configure({ mode: "parallel" }); const streamName = `stream${Date.now()}`; @@ -102,7 +102,7 @@ test.describe("Unflattened testcases", () => { `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` ); const allsearch = page.waitForResponse("**/api/default/_search**"); - await logsPage.selectStreamAndStreamTypeForLogs("e2e_automate"); + await logsPage.selectStream("e2e_automate"); await applyQueryButton(page); }); diff --git a/tests/ui-testing/playwright-tests/websocket.spec.js b/tests/ui-testing/playwright-tests/websocket.spec.js index b53ea67de5..5cf28c8089 100644 --- a/tests/ui-testing/playwright-tests/websocket.spec.js +++ b/tests/ui-testing/playwright-tests/websocket.spec.js @@ -1,6 +1,6 @@ import { test, expect } from "./baseFixtures"; import { LoginPage } from '../pages/loginPage'; -import { LogsPage } from '../pages/logsPage.js'; +import { LogsPage } from '../pages/logsPages/logsPage.js'; import { IngestionPage } from '../pages/ingestionPage'; import { ManagementPage } from '../pages/managementPage';