diff --git a/tests/ui-testing/package-lock.json b/tests/ui-testing/package-lock.json index dcb7331b14..006d5f79cd 100644 --- a/tests/ui-testing/package-lock.json +++ b/tests/ui-testing/package-lock.json @@ -10,6 +10,8 @@ "license": "ISC", "dependencies": { "@google-cloud/local-auth": "^2.1.0", + "date-fns": "^3.6.0", + "date-fns-tz": "^3.1.3", "dotenv": "^16.4.5", "googleapis": "^105.0.0", "pixelmatch": "^5.3.0", @@ -834,6 +836,23 @@ "node": ">=0.10" } }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/date-fns-tz": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.1.3.tgz", + "integrity": "sha512-ZfbMu+nbzW0mEzC8VZrLiSWvUIaI3aRHeq33mTe7Y38UctKukgqPR4nTDwcwS4d64Gf8GghnVsroBuMY3eiTeA==", + "peerDependencies": { + "date-fns": "^3.0.0" + } + }, "node_modules/dateformat": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", @@ -3872,6 +3891,17 @@ "assert-plus": "^1.0.0" } }, + "date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==" + }, + "date-fns-tz": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.1.3.tgz", + "integrity": "sha512-ZfbMu+nbzW0mEzC8VZrLiSWvUIaI3aRHeq33mTe7Y38UctKukgqPR4nTDwcwS4d64Gf8GghnVsroBuMY3eiTeA==", + "requires": {} + }, "dateformat": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", diff --git a/tests/ui-testing/package.json b/tests/ui-testing/package.json index ed713552de..ab495f8f52 100644 --- a/tests/ui-testing/package.json +++ b/tests/ui-testing/package.json @@ -18,6 +18,8 @@ }, "dependencies": { "@google-cloud/local-auth": "^2.1.0", + "date-fns": "^3.6.0", + "date-fns-tz": "^3.1.3", "dotenv": "^16.4.5", "googleapis": "^105.0.0", "pixelmatch": "^5.3.0", diff --git a/tests/ui-testing/playwright-tests/sanity.spec.js b/tests/ui-testing/playwright-tests/sanity.spec.js index 5d20f325c7..13735ffc7c 100644 --- a/tests/ui-testing/playwright-tests/sanity.spec.js +++ b/tests/ui-testing/playwright-tests/sanity.spec.js @@ -2,9 +2,11 @@ import { test, expect } from "@playwright/test"; import logData from "../../ui-testing/cypress/fixtures/log.json"; import { log } from "console"; import logsdata from "../../test-data/logs_data.json"; +import { toZonedTime } from "date-fns-tz"; test.describe.configure({ mode: "parallel" }); const folderName = `Folder ${Date.now()}`; +const dashboardName = `AutomatedDashboard${Date.now()}`; async function login(page) { await page.goto(process.env["ZO_BASE_URL"]); @@ -704,20 +706,44 @@ test.describe("Sanity testcases", () => { .click(); }); - test("should check JSON responses for successful:1 with timestamp 15 mins before", async ({ - page, - request, - }) => { - const orgId = process.env["ORGNAME"]; - const streamName = "e2e_automate"; + const getHeaders = () => { const basicAuthCredentials = Buffer.from( `${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}` ).toString("base64"); - const headers = { + return { Authorization: `Basic ${basicAuthCredentials}`, "Content-Type": "application/json", }; + }; + + // Helper function to get ingestion URL + const getIngestionUrl = (orgId, streamName) => { + return `${process.env.INGESTION_URL}/api/${orgId}/${streamName}/_json`; + }; + + // Helper function to send POST request + const sendRequest = async (page, url, payload, headers) => { + return await page.evaluate( + async ({ url, headers, payload }) => { + const response = await fetch(url, { + method: "POST", + headers: headers, + body: JSON.stringify(payload), + }); + return await response.json(); + }, + { url, headers, payload } + ); + }; + + test("should check JSON responses for successful:1 with timestamp 15 mins before", async ({ + page, + }) => { + const orgId = process.env["ORGNAME"]; + const streamName = "e2e_automate"; + const headers = getHeaders(); + const ingestionUrl = getIngestionUrl(orgId, streamName); // First payload const payload1 = [ @@ -741,32 +767,12 @@ test.describe("Sanity testcases", () => { }, ]; - // Function to send POST request - const sendRequest = async (url, payload) => { - return await page.evaluate( - async ({ url, headers, payload }) => { - const response = await fetch(url, { - method: "POST", - headers: headers, - body: JSON.stringify(payload), - }); - return await response.json(); - }, - { url, headers, payload } - ); - }; - - // URLs for the final requests - const ingestionUrl = `${process.env.INGESTION_URL}/api/${orgId}/${streamName}/_json`; - const url1 = ingestionUrl; - const url2 = ingestionUrl; - // Sending first request - const response1 = await sendRequest(url1, payload1); + const response1 = await sendRequest(page, ingestionUrl, payload1, headers); console.log(response1); // Sending second request - const response2 = await sendRequest(url2, payload2); + const response2 = await sendRequest(page, ingestionUrl, payload2, headers); console.log(response2); // Assertions @@ -776,18 +782,11 @@ test.describe("Sanity testcases", () => { test("should display error if timestamp past the ingestion time limit", async ({ page, - request, }) => { 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 headers = getHeaders(); + const ingestionUrl = getIngestionUrl(orgId, streamName); // First payload const payload1 = [ @@ -799,8 +798,8 @@ test.describe("Sanity testcases", () => { }, ]; - // Second payload with timestamp 15 minutes before - const timestamp = Date.now() - 6 * 60 * 60 * 1000; // 15 minutes before + // Second payload with timestamp 6 hours before + const timestamp = Date.now() - 6 * 60 * 60 * 1000; // 6 hours before const payload2 = [ { level: "info", @@ -811,32 +810,12 @@ test.describe("Sanity testcases", () => { }, ]; - // Function to send POST request - const sendRequest = async (url, payload) => { - return await page.evaluate( - async ({ url, headers, payload }) => { - const response = await fetch(url, { - method: "POST", - headers: headers, - body: JSON.stringify(payload), - }); - return await response.json(); - }, - { url, headers, payload } - ); - }; - - // URLs for the final requests - const ingestionUrl = `${process.env.INGESTION_URL}/api/${orgId}/${streamName}/_json`; - const url1 = ingestionUrl; - const url2 = ingestionUrl; - // Sending first request - const response1 = await sendRequest(url1, payload1); + const response1 = await sendRequest(page, ingestionUrl, payload1, headers); console.log(response1); // Sending second request - const response2 = await sendRequest(url2, payload2); + const response2 = await sendRequest(page, ingestionUrl, payload2, headers); console.log(response2); // Assertions @@ -844,7 +823,140 @@ test.describe("Sanity testcases", () => { expect(response2.status[0].successful).toBe(0); expect(response2.status[0].failed).toBe(1); expect(response2.status[0].error).toBe( - 'Too old data, only last 5 hours data can be ingested. Data discarded. You can adjust ingestion max time by setting the environment variable ZO_INGEST_ALLOWED_UPTO=' + "Too old data, only last 5 hours data can be ingested. Data discarded. You can adjust ingestion max time by setting the environment variable ZO_INGEST_ALLOWED_UPTO=" ); }); + + const formatDate = (date) => { + const year = String(date.getFullYear()); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + const hours = String(date.getHours()).padStart(2, "0"); + const minutes = String(date.getMinutes()).padStart(2, "0"); + const seconds = String(date.getSeconds()).padStart(2, "0"); + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; + }; + test("should compare time displayed in table dashboard after changing timezone and then delete it ", async ({ page }) => { + const orgId = process.env["ORGNAME"]; + const streamName = "e2e_tabledashboard"; + const headers = getHeaders(); + const ingestionUrl = getIngestionUrl(orgId, streamName); + const timestamp = parseInt(Date.now() / 10000) * 10000 - 10 * 60 * 1000; // 10 minutes before + // First payload + const payload1 = [ + { + level: "info", + job: "test", + log: "test message for openobserve", + e2e: "1", + _timestamp: timestamp, + }, + ]; + + // Sending first request + const response1 = await sendRequest(page, ingestionUrl, payload1, headers); + console.log(response1); + + await page.locator('[data-test="menu-link-\\/dashboards-item"]').click(); + await page.waitForTimeout(5000); + await page.locator('[data-test="dashboard-add"]').click(); + await page.waitForTimeout(5000); + await page.locator('[data-test="add-dashboard-name"]').click(); + + await page.locator('[data-test="add-dashboard-name"]').fill(dashboardName); + await page.locator('[data-test="dashboard-add-submit"]').click(); + await page.waitForTimeout(2000); + await page + .locator('[data-test="dashboard-if-no-panel-add-panel-btn"]') + .click(); + await page.waitForTimeout(3000); + await page.locator('[data-test="selected-chart-table-item"] img').click(); + await page.locator('[data-test="index-dropdown-stream"]').click(); + await page + .locator('[data-test="index-dropdown-stream"]') + .fill("e2e_tabledashboard"); + await page.getByRole("option", { name: "e2e_tabledashboard" }).click({force:true}); + await page.waitForTimeout(5000); + + await page + .locator( + '[data-test="field-list-item-logs-e2e_tabledashboard-e2e"] [data-test="dashboard-add-y-data"]' + ) + .click(); + await page + .locator( + '[data-test="field-list-item-logs-e2e_tabledashboard-job"] [data-test="dashboard-add-y-data"]' + ) + .click(); + await page + .locator( + '[data-test="field-list-item-logs-e2e_tabledashboard-_timestamp"] [data-test="dashboard-add-x-data"]' + ) + .click(); + await page.locator('[data-test="dashboard-apply"]').click(); + await page.locator('[data-test="dashboard-panel-name"]').click(); + await page.locator('[data-test="dashboard-panel-name"]').fill("sanitydash"); + await page.waitForTimeout(2000); + await page.locator('[data-test="dashboard-panel-save"]').click(); + await page.waitForTimeout(2000); + + // // Change timezone to Asia/Calcutta + await page.locator('[data-test="date-time-btn"]').click(); + await page.locator('[data-test="datetime-timezone-select"]').click(); + await page + .locator('[data-test="datetime-timezone-select"]') + .fill("Asia/Calcutta"); + await page.getByText("Asia/Calcutta", { exact: true }).click(); + await page.waitForTimeout(200); + + // NOTE: pass selected timezone + const calcuttaTime = toZonedTime(new Date(timestamp), "Asia/Calcutta"); + const displayedTimestampCalcutta = formatDate(calcuttaTime); + console.log(displayedTimestampCalcutta); + await page.waitForTimeout(2000); + // Verify the displayed time in Asia/Calcutta + const timeCellCalcutta = await page + .getByRole("cell", { name: displayedTimestampCalcutta }) + .textContent(); + expect(timeCellCalcutta).toBe(displayedTimestampCalcutta); + await page.waitForTimeout(1000); + // Change timezone to Europe/Zurich + await page.locator('[data-test="date-time-btn"]').click(); + await page.locator('[data-test="date-time-btn"]').click(); + await page.locator('[data-test="datetime-timezone-select"]').click(); + await page + .locator('[data-test="datetime-timezone-select"]') + .fill("Europe/Zurich"); + await page.getByText("Europe/Zurich", { exact: true }).click(); + await page.waitForTimeout(200); + + // Convert the timestamp to the required format in Europe/Zurich + const zurichTime = toZonedTime(new Date(timestamp), "Europe/Zurich"); + const displayedTimestampZurich = formatDate(zurichTime); + console.log(displayedTimestampZurich); + + // Verify the displayed time in Europe/Zurich + const timeCellZurich = await page + .getByRole("cell", { name: displayedTimestampZurich }) + .textContent(); + expect(timeCellZurich).toBe(displayedTimestampZurich); + await page.waitForTimeout(2000); + await page + .locator('[data-test="dashboard-edit-panel-sanitydash-dropdown"]') + .click(); + await page.locator('[data-test="dashboard-delete-panel"]').click(); + await page.locator('[data-test="confirm-button"]').click(); + await page + .locator("#q-notify div") + .filter({ hasText: "check_circlePanel deleted" }) + .nth(3) + .click(); + await page.locator('[data-test="dashboard-back-btn"]'); + await page.locator('[data-test="dashboard-back-btn"]').click(); + await page + .getByRole("row", { name: dashboardName }) + .locator('[data-test="dashboard-delete"]') + .click(); + await page.locator('[data-test="confirm-button"]').click(); + }); }); diff --git a/tests/ui-testing/playwright-tests/schema.spec.js b/tests/ui-testing/playwright-tests/schema.spec.js index 5e6fc9e9a1..f13aff572b 100644 --- a/tests/ui-testing/playwright-tests/schema.spec.js +++ b/tests/ui-testing/playwright-tests/schema.spec.js @@ -73,16 +73,9 @@ test.describe("Schema testcases", () => { 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"); + await expect.poll(async () => (await search).status()).toBe(200); } - // tebefore(async function () { - // // logData("log"); - // // const data = page; - // // logData = data; - - // console.log("--logData--", logData); - // }); + test.beforeEach(async ({ page }) => { await login(page); await page.waitForTimeout(5000) @@ -94,7 +87,6 @@ test.describe("Schema testcases", () => { const allsearch = page.waitForResponse("**/api/default/_search**"); await selectStreamAndStreamTypeForLogs(page,logData.Stream); await applyQueryButton(page); - // const streams = page.waitForResponse("**/api/default/streams**"); }); test('stream schema settings updated to be displayed under logs', async ({ page }) => { @@ -192,13 +184,10 @@ test.describe("Schema testcases", () => { await page.waitForTimeout(2000); await page.locator('button').filter({ hasText: 'close' }).click() await page.waitForTimeout(1000); - // await page.getByPlaceholder('Search Stream').click(); - // await page.getByPlaceholder('Search Stream').fill('e2e_automate'); await page.getByRole('button', { name: 'Stream Detail' }).first().click(); await page.locator('[data-test="tab-schemaFields"]').click(); await page.locator('[data-test="schema-stream-delete-kubernetes_annotations_kubectl_kubernetes_io_default_container-field-fts-key-checkbox"]').click(); await page.locator('[data-test="schema-stream-delete-kubernetes_annotations_kubernetes_io_psp-field-fts-key-checkbox"]').click(); - // await page.locator('[data-test="schema-stream-delete-oooo-field-fts-key-checkbox"]').click(); await page.locator('[data-test="schema-add-field-button"]').click(); await page.locator('[data-test="schema-update-settings-button"]').click();