test: Logs Page Major Overhaul (#7490)

### **User description**
Updated logs page, Updated playwright yml file, Updated all files
containing references of logs page, added folder structure to logs,
updated locators for failing test cases


___

### **PR Type**
Tests, Enhancement


___

### **Description**
- Introduce `LogsPage` POM class with locators and methods

- Refactor log specs to use new POM classes

- Add `LogsQueryPage` for query filtering logic

- Rename `selectStream` helper across tests


___

### **Changes diagram**

```mermaid
flowchart LR
  A["LogsPage POM"] --> B["logspage.spec.js"]
  A --> C["logsqueries.spec.js"]
  A --> D["logshistogram.spec.js"]
  A --> E["logsQueryPage POM"]
  F["Stream Helper"] --> G["indexquery.spec.js"]
```


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>2
files</summary><table>
<tr>
<td><strong>logsPage.js</strong><dd><code>Add comprehensive `LogsPage`
POM class</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-8045b343491d8943869c1af74cdafab204dc49c02a70294417e73f47d35e0b59">+1563/-0</a></td>

</tr>

<tr>
<td><strong>logsQueryPage.js</strong><dd><code>Add `LogsQueryPage` for
query filter tests</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-d4b122abaad43a49fa5d670610274e876342177176360077492e2e094dbc2cba">[link]</a>&nbsp;
&nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Tests</strong></td><td><details><summary>7
files</summary><table>
<tr>
<td><strong>logspage.spec.js</strong><dd><code>Add `logspage.spec.js`
using `LogsPage` POM</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-b1a64252adae01c5e8f7e758e3c820f5476260f60c44a4a57b4f15a05a59a85a">+509/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>logsqueries.spec.js</strong><dd><code>Refactor
`logsqueries.spec.js` to use `LogsPage`</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-c2055f6cef1580b15c5f94f5c8c2e496a6e921332b48bad943bb7c0630846a65">+136/-127</a></td>

</tr>

<tr>
<td><strong>logshistogram.spec.js</strong><dd><code>Refactor
`logshistogram.spec.js` for POM usage</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-d01da1c5a03b1d1c1c74e11f6e4ebe879def1ce87e407aa9a1afc8473040f4bc">+74/-63</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>indexquery.spec.js</strong><dd><code>Rename and use
`selectStream` helper</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-0fdb3410e34d127b97b20feda5f1c5f244f23af2d2d88c331ab753a1f434d3b1">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>region.spec.js</strong><dd><code>Rename `selectStream` in
region tests</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-b90cf78e7ef83f1fa7e5b8ebb9639604d26888afaa0b2083381de89131063ec8">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>enrichment.spec.js</strong><dd><code>Update import path to
`logsPages/logsPage.js`</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-1c26b9ac51f49e25aa8fe1ad6ae5376da50d27be032579c4194b62e5e798a76b">+3/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>sanity.spec.js</strong><dd><code>Update `LogsPage` import
and stream selection</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-53b3ede269fef5199fbaea935f79134b50ba4db51edc517e4b1701f2cbcc5130">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Additional
files</strong></td><td><details><summary>23 files</summary><table>
<tr>
  <td><strong>playwright.yml</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-7afcd2d8f7b49bda74843f209eefb7b2da45f7e7803bf2e4bd636699b76aa2d3">+4/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>logsPage.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-6af0f73f0523e6fccd38532cb454dc58c4ef1fe4ef5bc5a135ef3f0ee5371ef6">+0/-830</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>streamsPage.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-792df584eb1625d35fd1e33a5a37aa3ada28f15ec1e77a1921f1c56e50bf70d2">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>logsquickmode.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-81f2f36450c07435f1b0f3c33462c7dac98c0798250913ae5ed928f57ad82cdf">+58/-92</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>changeOrg.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-607c77ca637716a5b8d37ec25dbaf7dc91cddd7d981b72f9c460f54498d14351">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>dashboard-folder.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-bdb8f953e350e378f4196ea1b74fa60961dbe7e87ea34b77e551e77983ab0360">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>dashboardtype.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-40ee9b1480e11efe6a8fcbdd9c28e2881ef564783b43e12aaa86f2b3cc7d8bc6">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>visualization-vrl.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-4bfe28b08994ca0333edbe51bc99d3ddf05525387e90932d88681028e1947db4">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>visualize.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-d144f23552ec150db375c89e52c3a53ede9ff3fa5dcd6092694fbe0a308d22ec">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>join.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-e039a16bb79192216b3fb8ecfc745db63f48c43e73a9305ed6adb54c4a9dd683">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>logspage.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-950a38f6d66dbcf4f7cb39dc366ab25f533044718edee8199d7f819c5b06efe3">+0/-582</a>&nbsp;
</td>

</tr>

<tr>
  <td><strong>multiselect-stream.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-e2eb0d6de0ad04a42b73cce92a1c86e68213fed79bd7507ea00abfe18a2633c7">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>pagination.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-5e44451149ef320c6c78668ff2a42a152fdc7b0565838c8d7f7385f5d4809cb5">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>pipeline-core.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-e6249b045437e7f087b825dc0ee2d8ccebed0894d10c84b7bc9b12dca7a25754">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>pipelines.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-9b48f5edc53f2413789549b189d4a80f134a320dd5beebf96d738069eb43033a">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>remotepipeline.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-3b5a97115bd312e7490580fa00af21077ea5050915995bd133a7f5fd913e5394">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>sanity2.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-f1ab4c6d536ebc3b8ea7ff17d2954d86ef56b660dcfaa1bb39f8213a5bf92e22">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>schema.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-1212ad9c33ea14a5a660923b20c162380c9d8c27ffa64993ddfc827e4d82a208">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>schemaload.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-768d758450ec41815b1330503394239673698045f5c29e46fc05d7b475c037ea">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>searchpartition.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-557a8fcb7159dd28b9a8fd9c0657b5882297c650ef4f22a2d2213211a42b17ea">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>secondsPrecisionAdded.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-bd92ad86063b90d67a50098a8ba722ef9b232f950a7c53604ae898043af7abfb">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>unflattened.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-a5e0a62966202ad510f4be2cd89e91c1d34eaf48d179e5725d532f1d7fb92b4e">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>websocket.spec.js</strong></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7490/files#diff-1f356bcfb18ed299a284a4c81893d73612faf9bac3941430f30d7c1b2d105540">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr></tr></tbody></table>

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
This commit is contained in:
Shrinath Rao
2025-07-10 20:59:23 +05:30
committed by GitHub
parent 2de6a0684b
commit 6fc540cd25
39 changed files with 3132 additions and 2617 deletions
+4 -4
View File
@@ -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",
-830
View File
@@ -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();
}
}
File diff suppressed because it is too large Load Diff
@@ -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();
}
}
@@ -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();
});
});
@@ -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();
});
});
@@ -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();
});
})
@@ -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");
});
});
@@ -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();
});
});
@@ -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();
@@ -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 }) => {
@@ -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);
@@ -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);
@@ -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);
});
});
});
@@ -636,4 +636,4 @@ test.describe("logs testcases", () => {
await dashboardCreate.backToDashboardList();
await deleteDashboard(page, randomDashboardName);
});
});
});
@@ -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);
});
@@ -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);
});
@@ -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' });
@@ -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();
});
});
@@ -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();
});
});
@@ -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();
});
})
@@ -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/);
});
});
@@ -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();
@@ -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 }) => {
@@ -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);
});
@@ -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);
});
@@ -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())) {
@@ -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) {
@@ -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**");
});
@@ -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**");
});
@@ -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);
});
@@ -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" });
@@ -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();
}
@@ -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';
@@ -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();
});
});
@@ -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();
}
});
});
@@ -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);
});
@@ -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';