diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index f5b79320a3..4f238bcc90 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -97,7 +97,7 @@ jobs: "logsqueries.spec.js", "logsquickmode.spec.js", "multiselect-stream.spec.js", - "pipeline.spec.js", + "pipelines.spec.js", "dashboards/dashboardtype.spec.js", "dashboards/dashboard.spec.js", "dashboards/visualize.spec.js", diff --git a/tests/ui-testing/pages/pipelinePage.js b/tests/ui-testing/pages/pipelinePage.js new file mode 100644 index 0000000000..e372dd03b0 --- /dev/null +++ b/tests/ui-testing/pages/pipelinePage.js @@ -0,0 +1,273 @@ +const { expect } = require('@playwright/test') +class PipelinePage { + constructor(page) { + this.page = page; + // Locators + this.pipelineMenuLink = page.locator( + '[data-test="menu-link-\\/pipeline-item"]' + ); + this.addPipelineButton = page.locator( + '[data-test="pipeline-list-add-pipeline-btn"]' + ); + this.streamButton = page.getByRole("button", { name: "Stream" }).first(); + this.queryButton = page.getByRole("button", { name: "Query" }); + this.vueFlowPane = page.locator(".vue-flow__pane"); + this.logsDropdown = page.locator("div").filter({ hasText: /^logs$/ }); + this.logsOption = page + .getByRole("option", { name: "logs" }) + .locator("div") + .nth(2); + this.saveButton = page.locator('[data-test="input-node-stream-save-btn"]'); + this.selectStreamError = page.getByText("Please select Stream from the"); + this.savePipelineButton = page.locator( + '[data-test="add-pipeline-save-btn"]' + ); + this.pipelineNameRequiredMessage = page.getByText( + "Pipeline name is required" + ); + this.pipelineNameInput = page.getByLabel("Enter Pipeline Name"); + this.sourceNodeRequiredMessage = page.getByText("Source node is required"); + this.streamNameInput = page.getByLabel("Stream Name *"); + this.e2eAutomateOption = page.getByRole("option", { name: "e2e_automate" }); + this.inputNodeStreamSaveButton = page.locator( + '[data-test="input-node-stream-save-btn"]' + ); + this.destinationNodeRequiredMessage = page.getByText( + "Destination node is required" + ); + this.deleteButton = page.locator("button").filter({ hasText: "delete" }); + this.confirmDeleteButton = page.locator('[data-test="confirm-button"]'); + this.secondStreamButton = page.getByRole('button', { name: 'Stream' }).nth(1); + this.functionButton = page.getByRole('button', { name: 'Function' }) + this.conditionButton = page.getByRole('button', { name: 'Condition' }) + this.selectPreviousNodeDropdown = page.getByLabel('Select Previous Node'); + this.previousNodeDropdown = page.locator('[data-test="previous-node-dropdown-input-stream-node-option"]'); + this.previousNodeDropdownSecond = page.locator('[data-test="previous-node-dropdown-input-stream-node-option"]:last-child'); + this.createStreamToggle = page.locator('[data-test="create-stream-toggle"] div').nth(2); + this.saveStreamButton = page.locator('[data-test="save-stream-btn"]'); + this.inputNodeStreamSaveButton = page.locator('[data-test="input-node-stream-save-btn"]') + this.pipelineSearchInput = page.locator('[data-test="pipeline-list-search-input"]'); + this.confirmDeleteButton = page.locator('[data-test="confirm-button"]'); + this.deletionSuccessMessage = page.getByText('Pipeline deleted successfully') + this.sqlEditor = page.locator('[data-test="scheduled-pipeline-sql-editor"]'); + this.sqlQueryInput = page.locator('.view-lines'); + this.frequencyUnit = page.locator('[data-test="scheduled-pipeline-frequency-unit"]'); + this.saveQueryButton = page.locator('[data-test="stream-routing-query-save-btn"]'); + this.createFunctionToggle = page.locator('[data-test="create-function-toggle"] div').nth(2); + this.functionNameLabel = page.locator('[data-test="add-function-node-routing-section"]').getByLabel('Name'); + this.associateFunctionSaveButton = page.locator('[data-test="associate-function-save-btn"]'); + this.functionNameRequiredError = page.getByText('Function Name is required') + this.functionRequiredError = page.getByText('Function is required') + this.streamSelectionError = page.getByText('Please select Stream from the') + this.columnInput = page.getByPlaceholder('Column'); // Locator for the "Column" input field + this.columnOption = page.getByRole('option', { name: 'kubernetes_container_name' }) + this.fieldRequiredError = page.getByText('Field is required!') + +this.functionNameInput = page.locator('[data-test="add-function-node-routing-section"] input[aria-label="Name"]'); +this.addConditionSaveButton = page.locator('[data-test="add-condition-save-btn"]'); + + + + } + + async openPipelineMenu() { + await this.pipelineMenuLink.click(); + } + + async addPipeline() { + await this.addPipelineButton.waitFor({ state: 'visible' }); + await this.addPipelineButton.click(); + } + + async selectStream() { + await this.streamButton.click(); + } + + async dragStreamToTarget(streamElement, offset = { x: 0, y: 0 }) { + const targetBox = await this.vueFlowPane.boundingBox(); + const streamBox = await streamElement.boundingBox(); + targetBox.x += offset.x; + targetBox.y += offset.y; + if (streamBox && targetBox) { + await this.page.mouse.move(streamBox.x + streamBox.width / 2, streamBox.y + streamBox.height / 2); + await this.page.mouse.down(); + await this.page.mouse.move(targetBox.x + targetBox.width / 2, targetBox.y + targetBox.height / 2); + await this.page.mouse.up(); + } + } + + async selectLogs() { + await this.logsDropdown.click(); + await this.logsOption.click(); + } + + async saveStream() { + await this.saveButton.click(); + } + + async confirmStreamError() { + await this.selectStreamError.click(); + } + + async savePipeline() { + await this.savePipelineButton.click(); + } + + async confirmPipelineNameRequired() { + await this.pipelineNameRequiredMessage.click(); + } + + async enterPipelineName(pipelineName) { + await this.pipelineNameInput.click(); + await this.pipelineNameInput.fill(pipelineName); + } + + async confirmSourceNodeRequired() { + await this.sourceNodeRequiredMessage.click(); + } + async enterStreamName(streamName) { + await this.streamNameInput.fill(streamName); + await this.streamNameInput.press("Enter"); + } + + async selectStreamOption() { + await this.e2eAutomateOption.click(); + } + + async saveInputNodeStream() { + await this.inputNodeStreamSaveButton.click(); + } + + async confirmDestinationNodeRequired() { + await this.destinationNodeRequiredMessage.click(); + } + async deletePipeline() { + await this.deleteButton.click(); + } + + async confirmDelete() { + await this.confirmDeleteButton.click(); + } + + async selectAndDragSecondStream() { + await this.secondStreamButton.click(); + await this.dragStreamToTarget(this.secondStreamButton,{ x: 80, y: 80 }); + } + + + async selectAndDragFunction() { + await this.secondStreamButton.click(); + await this.dragStreamToTarget(this.functionButton, { x: 50, y: 50 }); + } + + + async selectPreviousNode() { + await this.selectPreviousNodeDropdown.click(); + } + + async selectPreviousNodeDrop() { + await this.previousNodeDropdownSecond.click(); + } + + // Method to toggle the create stream option + async toggleCreateStream() { + await this.createStreamToggle.click(); + } + + async clickSaveStream() { + await this.saveStreamButton.click(); + } + + // Method to click the input node stream save button + async clickInputNodeStreamSave() { + await this.inputNodeStreamSaveButton.click(); + } + async searchPipeline(pipelineName) { + await this.pipelineSearchInput.click(); + await this.pipelineSearchInput.fill(pipelineName); + } + + async confirmDeletePipeline() { + await this.confirmDeleteButton.click(); + } + + // Method to verify deletion success message + async verifyPipelineDeleted() { + await this.deletionSuccessMessage.click(); + } + + + async selectStream() { + await this.queryButton.click(); + } + async clickSqlEditor() { + await this.sqlEditor.click(); + } + + // Method to type the SQL query + async typeSqlQuery(query) { + await this.sqlQueryInput.click(); + await this.page.keyboard.type(query); + } + + // Method to select the frequency unit dropdown + async selectFrequencyUnit() { + await this.frequencyUnit.click(); + } + + // Method to save the query + async saveQuery() { + await this.saveQueryButton.click(); + } + + + async selectFunction() { + await this.functionButton.click(); + } + + async toggleCreateFunction() { + await this.createFunctionToggle.click(); +} + +async clickFunctionLabel(name) { + // Click the label and then fill in the input that appears + await this.functionNameLabel.click(); +} +async saveFunction() { + await this.associateFunctionSaveButton.click(); +} + +async enterFunctionName(name) { + await this.functionNameInput.fill(name); +} + +async assertFunctionNameRequiredErrorVisible() { + await expect(this.functionNameRequiredError).toBeVisible(); +} + +async assertFunctionRequiredErrorVisible() { + await expect(this.functionRequiredError).toBeVisible(); +} +async assertStreamSelectionErrorVisible() { + await expect(this.streamSelectionError).toBeVisible(); +} + +async selectAndDragCondition() { + await this.dragStreamToTarget(this.conditionButton, { x: 50, y: 50 }); +} +async fillColumnAndSelectOption(columnName) { + await this.columnInput.click(); + await this.columnInput.fill(columnName); + await this.columnOption.click(); +} +async saveCondition() { + await this.addConditionSaveButton.click(); +} +async verifyFieldRequiredError() { + await this.fieldRequiredError.waitFor({ state: 'visible' }); + await this.fieldRequiredError.click(); +} + +} + +export default PipelinePage; diff --git a/tests/ui-testing/playwright-tests/pipeline.spec.js b/tests/ui-testing/playwright-tests/pipeline.spec.js deleted file mode 100644 index dcec251053..0000000000 --- a/tests/ui-testing/playwright-tests/pipeline.spec.js +++ /dev/null @@ -1,389 +0,0 @@ -import { test, expect } from "./baseFixtures"; -import logData from "../../ui-testing/cypress/fixtures/log.json"; -import logsdata from "../../test-data/logs_data.json"; - -test.describe.configure({ mode: 'parallel' }); - -const randomPipelineName = `Pipeline${Math.floor(Math.random() * 1000)}`; -const randomFunctionName = `Pipeline${Math.floor(Math.random() * 1000)}`; - -async function login(page) { - await page.goto(process.env["ZO_BASE_URL"]); - // await page.getByText('Login as internal user').click(); - await page.waitForTimeout(1000); - await page - .locator('[data-cy="login-user-id"]') - .fill(process.env["ZO_ROOT_USER_EMAIL"]); - //Enter Password - 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(); - // await page.waitForTimeout(4000); - // await page.goto(process.env["ZO_BASE_URL"]); -} - - -const selectStreamAndStreamTypeForLogs = 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 }); -}; -async function deletePipeline(page, randomPipelineName) { - // Click the back button - await page.locator('[data-test="add-pipeline-back-btn"]').click(); - await page.locator('[data-test="confirm-button"]').click(); - await page.waitForTimeout(2000); - - // Search for the pipeline - await page.locator('[data-test="pipeline-list-search-input"]').click(); - await page.locator('[data-test="pipeline-list-search-input"]').fill(randomPipelineName); - - // Delete the pipeline - await page.locator(`[data-test="pipeline-list-${randomPipelineName}-delete-pipeline"]`).click(); - await page.locator('[data-test="confirm-button"]').click(); -} -test.describe("Pipeline testcases", () => { - // 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); - await page.waitForTimeout(5000) - - // ("ingests logs via API", () => { - 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 logsdata = {}; // Fill this with your actual data - - // Making a POST request using fetch API - 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); - // }); - // const allorgs = page.waitForResponse("**/api/default/organizations**"); - // const functions = page.waitForResponse("**/api/default/functions**"); - await page.goto( - `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` - ); - const allsearch = page.waitForResponse("**/api/default/_search**"); - await selectStreamAndStreamTypeForLogs(page,logData.Stream); - await applyQueryButton(page); - // const streams = page.waitForResponse("**/api/default/streams**"); - }); - - test.skip('display error if mandatory fields not added on pipeline creation UI ', async ({ page }) => { - await page.locator('[data-test="menu-link-\\/pipeline-item"]').click(); - await page.getByRole('main').locator('div').filter({ hasText: 'Enrichment TablesFunctionsStream AssociationStream' }).first().click(); - await page.locator('[data-test="stream-pipelines-tab"]').click(); - await page.locator('[data-test="pipeline-list-add-pipeline-btn"]').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').fill('e2epipeline'); - await page.locator('[data-test="add-pipeline-submit-btn"]').click(); - await page.getByText('Field is required!').click(); - }); - - test.skip('should close Add pipeline UI on clicking close icon', async ({ page }) => { - await page.locator('[data-test="menu-link-\\/pipeline-item"]').click(); - await page.getByRole('main').locator('div').filter({ hasText: 'Enrichment TablesFunctionsStream AssociationStream' }).first().click(); - await page.locator('[data-test="stream-pipelines-tab"]').click(); - await page.locator('[data-test="pipeline-list-add-pipeline-btn"]').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').fill('e2epipeline'); - await page.locator('[data-test="add-pipeline-submit-btn"]').click(); - await page.getByText('Field is required!').click(); - await page.locator('[data-test="add-pipeline-close-dialog-btn"]').click(); - // await page.waitForTimeout(2000); - await page.locator('[data-test="pipeline-list-add-pipeline-btn"]') - - }); - - test.skip('should add and delete pipeline', async ({ page }) => { - await page.locator('[data-test="menu-link-\\/pipeline-item"]').click(); - await page.getByRole('main').locator('div').filter({ hasText: 'Enrichment TablesFunctionsStream AssociationStream' }).first().click(); - await page.locator('[data-test="stream-pipelines-tab"]').click(); - await page.locator('[data-test="pipeline-list-add-pipeline-btn"]').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').fill(randomPipelineName); - await page.waitForSelector('.alert-stream-type > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native'); - await page.locator('.alert-stream-type > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native').click(); - await page.waitForTimeout(2000); - await page.getByRole('option', { name: 'Logs' }).locator('div').nth(2).click({force:true}); - await page.waitForTimeout(2000); - // await page.waitForSelector('[data-test="Stream Name *"]') - await page.getByLabel('Stream Name *').click(); - // await page.waitForSelector(':text("e2e_automate")') - await page.getByRole('option', { name: 'e2e_automate' }).locator('div').nth(2).click(); - await page.locator('[data-test="add-pipeline-submit-btn"]').click(); - await page.waitForTimeout(2000) - await page.reload(); - await page.locator(`[data-test="pipeline-list-${randomPipelineName}-delete-pipeline"]`); - await page.locator(`[data-test="pipeline-list-${randomPipelineName}-delete-pipeline"]`).click(); - await page.locator('[data-test="confirm-button"]').click(); - }); - - test.skip('should add function to pipeline', async ({ page }) => { - await page.locator('[data-test="menu-link-\\/pipeline-item"]').click(); - await page.getByRole('main').locator('div').filter({ hasText: 'Enrichment TablesFunctionsStream AssociationStream' }).first().click(); - await page.locator('[data-test="stream-pipelines-tab"]').click(); - await page.locator('[data-test="pipeline-list-add-pipeline-btn"]').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').fill(randomPipelineName); - await page.waitForSelector('.alert-stream-type > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native'); - await page.locator('.alert-stream-type > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native').click(); - await page.waitForTimeout(2000); - await page.getByRole('option', { name: 'Logs' }).locator('div').nth(2).click({force:true}); - await page.waitForTimeout(2000); - // await page.waitForSelector('[data-test="Stream Name *"]') - await page.getByLabel('Stream Name *').click(); - // await page.waitForSelector(':text("e2e_automate")') - await page.getByRole('option', { name: 'e2e_automate' }).locator('div').nth(2).click(); - await page.locator('[data-test="add-pipeline-submit-btn"]').click(); - await page.waitForTimeout(2000) - await page.locator(`[data-test="pipeline-list-${randomPipelineName}-update-pipeline"]`).click(); - await page.waitForTimeout(2000) - - // Locate the function node and pipeline chart - const functionNode = await page.waitForSelector('[data-test="pipeline-editor-function-node"]'); - const pipelineChart = await page.waitForSelector('[data-test="pipeline-editor-pipeline-chart"]'); - - // Get the bounding boxes of both elements - await page.waitForTimeout(2000) - const functionNodeBoundingBox = await functionNode.boundingBox(); - const pipelineChartBoundingBox = await pipelineChart.boundingBox(); - - // Calculate the center coordinates of the function node - const functionNodeCenterX = functionNodeBoundingBox.x + functionNodeBoundingBox.width / 2; - const functionNodeCenterY = functionNodeBoundingBox.y + functionNodeBoundingBox.height / 2; - - // Calculate the center coordinates of the pipeline chart - const pipelineChartCenterX = pipelineChartBoundingBox.x + pipelineChartBoundingBox.width / 2; - const pipelineChartCenterY = pipelineChartBoundingBox.y + pipelineChartBoundingBox.height / 2; - - // Simulate the drag-and-drop operation - await page.mouse.move(functionNodeCenterX, functionNodeCenterY); - await page.mouse.down(); - await page.mouse.move(pipelineChartCenterX, pipelineChartCenterY); - await page.mouse.up(); - await page.waitForTimeout(2000) - await page.locator('[data-test="create-function-toggle"] div').nth(2).click(); - await page.getByLabel('Name').click(); - await page.getByLabel('Name').fill(randomFunctionName); - await page.locator('[data-test="associate-function-save-btn"]').click(); - await page.waitForTimeout(2000) - await page.getByText('Function saved successfully').click(); - await page.locator('[data-test="associate-function-save-btn"]').click(); - await page.locator('[data-test="pipeline-editor-pipeline-chart"]').getByRole('img').getByText(randomFunctionName).click(); - await page.locator('[data-test="associate-function-delete-btn"]'); - await page.locator('[data-test="associate-function-delete-btn"]').click(); - await page.locator('[data-test="confirm-button"]').click(); - await deletePipeline(page, randomPipelineName); - - }); - - - - test.skip('should display error when no name added while adding function to pipeline', async ({ page }) => { - await page.locator('[data-test="menu-link-\\/pipeline-item"]').click(); - await page.getByRole('main').locator('div').filter({ hasText: 'Enrichment TablesFunctionsStream AssociationStream' }).first().click(); - await page.locator('[data-test="stream-pipelines-tab"]').click(); - await page.locator('[data-test="pipeline-list-add-pipeline-btn"]').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').fill(randomPipelineName); - await page.waitForSelector('.alert-stream-type > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native'); - await page.locator('.alert-stream-type > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native').click(); - await page.waitForTimeout(2000); - await page.getByRole('option', { name: 'Logs' }).locator('div').nth(2).click({force:true}); - await page.waitForTimeout(2000); - // await page.waitForSelector('[data-test="Stream Name *"]') - await page.getByLabel('Stream Name *').click(); - // await page.waitForSelector(':text("e2e_automate")') - await page.getByRole('option', { name: 'e2e_automate' }).locator('div').nth(2).click(); - await page.locator('[data-test="add-pipeline-submit-btn"]').click(); - await page.waitForTimeout(2000) - await page.locator(`[data-test="pipeline-list-${randomPipelineName}-update-pipeline"]`).click(); - await page.waitForTimeout(2000) - - // Locate the function node and pipeline chart - const functionNode = await page.waitForSelector('[data-test="pipeline-editor-function-node"]'); - const pipelineChart = await page.waitForSelector('[data-test="pipeline-editor-pipeline-chart"]'); - - // Get the bounding boxes of both elements - await page.waitForTimeout(2000) - const functionNodeBoundingBox = await functionNode.boundingBox(); - const pipelineChartBoundingBox = await pipelineChart.boundingBox(); - - // Calculate the center coordinates of the function node - const functionNodeCenterX = functionNodeBoundingBox.x + functionNodeBoundingBox.width / 2; - const functionNodeCenterY = functionNodeBoundingBox.y + functionNodeBoundingBox.height / 2; - - // Calculate the center coordinates of the pipeline chart - const pipelineChartCenterX = pipelineChartBoundingBox.x + pipelineChartBoundingBox.width / 2; - const pipelineChartCenterY = pipelineChartBoundingBox.y + pipelineChartBoundingBox.height / 2; - - // Simulate the drag-and-drop operation - await page.mouse.move(functionNodeCenterX, functionNodeCenterY); - await page.mouse.down(); - await page.mouse.move(pipelineChartCenterX, pipelineChartCenterY); - await page.mouse.up(); - await page.waitForTimeout(2000) - await page.locator('[data-test="associate-function-save-btn"]').click(); - // await page.getByText('Function is already associated').click(); - - }); - - test.skip('should add streamroute node', async ({ page }) => { - await page.locator('[data-test="menu-link-\\/pipeline-item"]').click(); - await page.getByRole('main').locator('div').filter({ hasText: 'Enrichment TablesFunctionsStream AssociationStream' }).first().click(); - await page.locator('[data-test="stream-pipelines-tab"]').click(); - await page.locator('[data-test="pipeline-list-add-pipeline-btn"]').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').fill(randomPipelineName); - await page.waitForSelector('.alert-stream-type > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native'); - await page.locator('.alert-stream-type > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native').click(); - await page.waitForTimeout(2000); - await page.getByRole('option', { name: 'Logs' }).locator('div').nth(2).click({force:true}); - await page.waitForTimeout(2000); - // await page.waitForSelector('[data-test="Stream Name *"]') - await page.getByLabel('Stream Name *').click(); - // await page.waitForSelector(':text("e2e_automate")') - await page.getByRole('option', { name: 'e2e_automate' }).locator('div').nth(2).click(); - await page.locator('[data-test="add-pipeline-submit-btn"]').click(); - await page.locator(`[data-test="pipeline-list-${randomPipelineName}-update-pipeline"]`) - await page.locator(`[data-test="pipeline-list-${randomPipelineName}-update-pipeline"]`).click(); - await page.waitForTimeout(2000) - - // Locate the function node and pipeline chart - const functionNode = await page.waitForSelector('[data-test="pipeline-editor-streamRoute-node"]'); - const pipelineChart = await page.waitForSelector('[data-test="pipeline-editor-pipeline-chart"]'); - - // Get the bounding boxes of both elements - await page.waitForTimeout(2000) - const functionNodeBoundingBox = await functionNode.boundingBox(); - const pipelineChartBoundingBox = await pipelineChart.boundingBox(); - - // Calculate the center coordinates of the function node - const functionNodeCenterX = functionNodeBoundingBox.x + functionNodeBoundingBox.width / 2; - const functionNodeCenterY = functionNodeBoundingBox.y + functionNodeBoundingBox.height / 2; - - // Calculate the center coordinates of the pipeline chart - const pipelineChartCenterX = pipelineChartBoundingBox.x + pipelineChartBoundingBox.width / 2; - const pipelineChartCenterY = pipelineChartBoundingBox.y + pipelineChartBoundingBox.height / 2; - - // Simulate the drag-and-drop operation - await page.mouse.move(functionNodeCenterX, functionNodeCenterY); - await page.mouse.down(); - await page.mouse.move(pipelineChartCenterX, pipelineChartCenterY); - await page.mouse.up(); - await page.waitForTimeout(2000) - await page.getByLabel('Stream Name *').click(); - await page.getByLabel('Stream Name *').fill('piplelineauto'); - await page.locator('.q-ml-none > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native').first().click(); - await page.getByRole('option', { name: '_timestamp' }).locator('div').nth(2).click(); - await page.locator('div:nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native').click(); - await page.getByRole('option', { name: '=', exact: true }).locator('div').nth(2).click(); - await page.getByPlaceholder('Value').click(); - await page.getByPlaceholder('Value').fill('1'); - await page.locator('[data-test="add-report-save-btn"]').click(); - await deletePipeline(page, randomPipelineName); - -}); - - test.skip('should display error when only blank spaces added in stream route name', async ({ page }) => { - await page.locator('[data-test="menu-link-\\/pipeline-item"]').click(); - await page.getByRole('main').locator('div').filter({ hasText: 'Enrichment TablesFunctionsStream AssociationStream' }).first().click(); - await page.locator('[data-test="stream-pipelines-tab"]').click(); - await page.locator('[data-test="pipeline-list-add-pipeline-btn"]').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').click(); - await page.locator('[data-test="add-pipeline-name-input"]').getByLabel('Name *').fill(randomPipelineName); - await page.waitForSelector('.alert-stream-type > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native'); - await page.locator('.alert-stream-type > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native').click(); - await page.waitForTimeout(2000); - await page.getByRole('option', { name: 'Logs' }).locator('div').nth(2).click({force:true}); - await page.waitForTimeout(2000); - // await page.waitForSelector('[data-test="Stream Name *"]') - await page.getByLabel('Stream Name *').click(); - // await page.waitForSelector(':text("e2e_automate")') - await page.getByRole('option', { name: 'e2e_automate' }).locator('div').nth(2).click(); - await page.locator('[data-test="add-pipeline-submit-btn"]').click(); - await page.waitForTimeout(2000) - await page.locator(`[data-test="pipeline-list-${randomPipelineName}-update-pipeline"]`).click(); - await page.waitForTimeout(2000) - - // Locate the function node and pipeline chart - const functionNode = await page.waitForSelector('[data-test="pipeline-editor-streamRoute-node"]'); - const pipelineChart = await page.waitForSelector('[data-test="pipeline-editor-pipeline-chart"]'); - - // Get the bounding boxes of both elements - await page.waitForTimeout(2000) - const functionNodeBoundingBox = await functionNode.boundingBox(); - const pipelineChartBoundingBox = await pipelineChart.boundingBox(); - - // Calculate the center coordinates of the function node - const functionNodeCenterX = functionNodeBoundingBox.x + functionNodeBoundingBox.width / 2; - const functionNodeCenterY = functionNodeBoundingBox.y + functionNodeBoundingBox.height / 2; - - // Calculate the center coordinates of the pipeline chart - const pipelineChartCenterX = pipelineChartBoundingBox.x + pipelineChartBoundingBox.width / 2; - const pipelineChartCenterY = pipelineChartBoundingBox.y + pipelineChartBoundingBox.height / 2; - - // Simulate the drag-and-drop operation - await page.mouse.move(functionNodeCenterX, functionNodeCenterY); - await page.mouse.down(); - await page.mouse.move(pipelineChartCenterX, pipelineChartCenterY); - await page.mouse.up(); - await page.waitForTimeout(2000) - await page.getByLabel('Stream Name *').fill(' '); - await page.locator('[data-test="add-report-save-btn"]').click(); - await page.getByText('Use alphanumeric and \'+=,.@-_').click(); - await page.locator('[data-test="stream-routing-cancel-btn"]').click(); - await page.locator('[data-test="confirm-button"]').click(); - await deletePipeline(page, randomPipelineName); - }); - -}) \ No newline at end of file diff --git a/tests/ui-testing/playwright-tests/pipelines.spec.js b/tests/ui-testing/playwright-tests/pipelines.spec.js new file mode 100644 index 0000000000..5146c4545f --- /dev/null +++ b/tests/ui-testing/playwright-tests/pipelines.spec.js @@ -0,0 +1,631 @@ +import { test, expect } from "./baseFixtures"; +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 { pipeline } from "stream"; + +test.describe.configure({ mode: "parallel" }); + +const randomPipelineName = `Pipeline${Math.floor(Math.random() * 1000)}`; +const randomFunctionName = `Pipeline${Math.floor(Math.random() * 1000)}`; + +async function login(page) { + await page.goto(process.env["ZO_BASE_URL"]); + // await page.getByText('Login as internal user').click(); + await page.waitForTimeout(1000); + await page + .locator('[data-cy="login-user-id"]') + .fill(process.env["ZO_ROOT_USER_EMAIL"]); + //Enter Password + 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(); + // await page.waitForTimeout(4000); + // await page.goto(process.env["ZO_BASE_URL"]); +} + +const selectStreamAndStreamTypeForLogs = 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 }); +}; +async function deletePipeline(page, randomPipelineName) { + // Click the back button + await page.locator('[data-test="add-pipeline-back-btn"]').click(); + await page.locator('[data-test="confirm-button"]').click(); + await page.waitForTimeout(2000); + + // Search for the pipeline + await page.locator('[data-test="pipeline-list-search-input"]').click(); + await page + .locator('[data-test="pipeline-list-search-input"]') + .fill("automatepi"); + + // Delete the pipeline + await page + .locator( + `[data-test="pipeline-list-${randomPipelineName}-delete-pipeline"]` + ) + .click(); + await page.locator('[data-test="confirm-button"]').click(); +} +test.describe("Pipeline testcases", () => { + // 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); + await page.waitForTimeout(5000); + + // ("ingests logs via API", () => { + 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 logsdata = {}; // Fill this with your actual data + + // Making a POST request using fetch API + 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); + await page.goto( + `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}` + ); + const allsearch = page.waitForResponse("**/api/default/_search**"); + await selectStreamAndStreamTypeForLogs(page, logData.Stream); + await applyQueryButton(page); + }); + + test("should display error when stream not selected while adding source", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectStream(); + await pipelinePage.dragStreamToTarget(pipelinePage.streamButton); + await pipelinePage.selectLogs(); + await pipelinePage.saveStream(); + await pipelinePage.confirmStreamError(); + }); + + test("should display error when user directly clicks on save without adding details", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.savePipeline(); + await pipelinePage.confirmPipelineNameRequired(); + }); + + test("should display error on entering only pipeline name and save", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + const pipelineName = `pipeline-${Math.random().toString(36).substring(7)}`; + await pipelinePage.enterPipelineName(pipelineName); + await pipelinePage.savePipeline(); + await pipelinePage.confirmSourceNodeRequired(); + }); + + test("should display error on entering only source node and save", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectStream(); + await pipelinePage.dragStreamToTarget(pipelinePage.streamButton); + await pipelinePage.selectLogs(); + + // Interact with stream name and save + await pipelinePage.enterStreamName("e2e"); + await pipelinePage.enterStreamName("e2e_automate"); + await page.waitForTimeout(1000); + await pipelinePage.selectStreamOption(); + await pipelinePage.saveInputNodeStream(); + + // Generate a random pipeline name and save + const pipelineName = `pipeline-${Math.random().toString(36).substring(7)}`; + await pipelinePage.enterPipelineName(pipelineName); + await pipelinePage.savePipeline(); + + // Confirm the destination node required error message + await pipelinePage.confirmDestinationNodeRequired(); + }); + + test("should delete the create source node on confirmation", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectStream(); + await pipelinePage.streamButton.waitFor({ state: "visible" }); + await pipelinePage.dragStreamToTarget(pipelinePage.streamButton); + await pipelinePage.selectLogs(); + + // Interact with stream name and save + await page.waitForTimeout(2000); + await pipelinePage.enterStreamName("e2e"); + await pipelinePage.enterStreamName("e2e_automate"); + await page.waitForTimeout(2000); + await pipelinePage.selectStreamOption(); + await pipelinePage.saveInputNodeStream(); + + // Delete the pipeline and confirm + await pipelinePage.deletePipeline(); + await pipelinePage.confirmDelete(); + }); + + test("should add source & destination node and then delete the pipeline", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectStream(); + await pipelinePage.dragStreamToTarget(pipelinePage.streamButton); + await pipelinePage.selectLogs(); + + // Interact with stream name and save + await pipelinePage.enterStreamName("e2e"); + await pipelinePage.enterStreamName("e2e_automate"); + await page.waitForTimeout(2000); + await pipelinePage.selectStreamOption(); + await pipelinePage.saveInputNodeStream(); + await pipelinePage.dragStreamToTarget(pipelinePage.streamButton); // First stream drag + + // Select the second stream, drag, and drop + await pipelinePage.selectAndDragSecondStream(); + await page.waitForTimeout(2000); + + // Select the previous node + await pipelinePage.selectPreviousNode(); + await pipelinePage.selectPreviousNodeDrop(); + await pipelinePage.toggleCreateStream(); + await page.getByLabel("Name *").click(); + await page.getByLabel("Name *").fill("destination-node"); + await page + .locator( + ".q-form > div:nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native" + ) + .click(); + await page + .getByRole("option", { name: "Logs" }) + .locator("div") + .nth(2) + .click(); + await pipelinePage.clickSaveStream(); + await pipelinePage.clickInputNodeStreamSave(); + const pipelineName = `pipeline-${Math.random().toString(36).substring(7)}`; + await pipelinePage.enterPipelineName(pipelineName); + await pipelinePage.savePipeline(); + await pipelinePage.searchPipeline(pipelineName); + await page.waitForTimeout(1000); + const deletePipelineButton = page.locator( + `[data-test="pipeline-list-${pipelineName}-delete-pipeline"]` + ); + await deletePipelineButton.waitFor({ state: "visible" }); + await deletePipelineButton.click(); + await pipelinePage.confirmDeletePipeline(); + await pipelinePage.verifyPipelineDeleted(); + }); + + test("should create query source and delete it", async ({ page }) => { + const pipelinePage = new PipelinePage(page); + + // Open the pipeline menu and wait for a moment + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + + // Add a new pipeline + await pipelinePage.addPipeline(); + + // Drag and drop the stream to target + await pipelinePage.dragStreamToTarget(pipelinePage.queryButton); + + // Select logs from the list + await page + .locator("div") + .filter({ hasText: /^logs$/ }) + .click(); + await page.getByRole("option", { name: "logs" }).click(); + + // Click on the editor to type the query + await page.locator(".view-lines").first().click(); + const sqlQuery = 'select * from "default"'; + + // Locate the editor and type the SQL query if it's not already typed + await page.click('[data-test="scheduled-pipeline-sql-editor"]'); + await page.keyboard.type(sqlQuery); + + // Wait for a moment to ensure the query is properly typed + await page.waitForTimeout(1000); + + // Check if the query exists in the editor (using `hasText` to ensure it's typed) + const queryTyped = await page + .locator("code") + .locator("div") + .filter({ hasText: sqlQuery }) + .count(); + + // If the query is found, click the frequency unit + if (queryTyped > 0) { + await page + .locator('[data-test="scheduled-pipeline-frequency-unit"]') + .click(); // Click frequency unit + } + await pipelinePage.saveQuery(); + await page.waitForTimeout(2000); + await pipelinePage.deletePipeline(); + await pipelinePage.confirmDelete(); + }); + + test("should add source, function,destination and then delete pipeline", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectStream(); + await pipelinePage.dragStreamToTarget(pipelinePage.streamButton); + await pipelinePage.selectLogs(); + await pipelinePage.enterStreamName("e2e"); + await pipelinePage.enterStreamName("e2e_automate"); + await page.waitForTimeout(2000); + await pipelinePage.selectStreamOption(); + await pipelinePage.saveInputNodeStream(); + await pipelinePage.selectAndDragFunction(); // Function drag + await page.waitForTimeout(2000); + await pipelinePage.selectPreviousNode(); + await page.getByText("input").click(); + await pipelinePage.toggleCreateFunction(); + await pipelinePage.enterFunctionName(randomFunctionName); + await page.locator(".view-lines").click(); + // Type the function text with a delay to ensure each character registers + await page.keyboard.type(".a=2", { delay: 100 }); + await page.keyboard.press("Enter"); + await page.keyboard.type(".", { delay: 100 }); + await page.getByText("Note: The function will be").click(); + + // Check if the required text is present in the editor + await page.getByText(".a=2 ."); + + // Optional: Add a short wait to confirm the action is processed + await page.waitForTimeout(1000); + + // Optional: Add a brief wait to allow any validation messages to process + await pipelinePage.saveFunction(); + await page.waitForTimeout(3000); + await pipelinePage.saveFunction(); + await page.waitForTimeout(3000); + await pipelinePage.dragStreamToTarget(pipelinePage.streamButton); // First stream drag + + // Select the second stream, drag, and drop + await pipelinePage.selectAndDragSecondStream(); + await page.waitForTimeout(2000); + + // // Select the previous node + await pipelinePage.selectPreviousNode(); + await pipelinePage.selectPreviousNodeDrop(); + await pipelinePage.toggleCreateStream(); + await page.getByLabel("Name *").click(); + await page.getByLabel("Name *").fill("destination-node"); + await page + .locator( + ".q-form > div:nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native" + ) + .click(); + await page + .getByRole("option", { name: "Logs" }) + .locator("div") + .nth(2) + .click(); + await pipelinePage.clickSaveStream(); + await pipelinePage.clickInputNodeStreamSave(); + const pipelineName = `pipeline-${Math.random().toString(36).substring(7)}`; + await pipelinePage.enterPipelineName(pipelineName); + await pipelinePage.savePipeline(); + await pipelinePage.searchPipeline(pipelineName); + await page.waitForTimeout(1000); + const deletePipelineButton = page.locator( + `[data-test="pipeline-list-${pipelineName}-delete-pipeline"]` + ); + await deletePipelineButton.waitFor({ state: "visible" }); + await deletePipelineButton.click(); + await pipelinePage.confirmDeletePipeline(); + await pipelinePage.verifyPipelineDeleted(); + }); + + + test("should display error when function name is not added", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectAndDragFunction(); // Function drag + await page.waitForTimeout(2000); + await pipelinePage.toggleCreateFunction(); + await page.waitForTimeout(1000); + await pipelinePage.saveFunction(); + await pipelinePage. assertFunctionNameRequiredErrorVisible() + + }); + + test("should display error when function name added but function is not added", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectAndDragFunction(); // Function drag + await page.waitForTimeout(2000); + await pipelinePage.toggleCreateFunction(); + await page.waitForTimeout(1000); + await pipelinePage.enterFunctionName(randomFunctionName); + await pipelinePage.saveFunction(); + await pipelinePage.assertFunctionRequiredErrorVisible() + }); + + + test.skip("should display error if query added without sql", async ({ page }) => { + const pipelinePage = new PipelinePage(page); + + // Open the pipeline menu and wait for a moment + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.dragStreamToTarget(pipelinePage.queryButton); + await page + .locator("div") + .filter({ hasText: /^logs$/ }) + .click(); + await page.getByRole("option", { name: "logs" }).click(); + await pipelinePage.saveQuery(); + await page.waitForTimeout(2000); + // TODO: Change the locator to the correct one, once fixed + await page.getByText('Invalid SQL Query : undefined').click() + + }); + + + + test("should display error when save clicked directly while adding destination", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectAndDragSecondStream(); + await page.waitForTimeout(2000); + await pipelinePage.saveStream(); + await pipelinePage.assertStreamSelectionErrorVisible() + }); + + test("should add source, condition & destination node and then delete the pipeline", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectStream(); + await pipelinePage.dragStreamToTarget(pipelinePage.streamButton); + await pipelinePage.selectLogs(); + + // Interact with stream name and save + await pipelinePage.enterStreamName("e2e"); + await pipelinePage.enterStreamName("e2e_automate"); + await page.waitForTimeout(2000); + await pipelinePage.selectStreamOption(); + await pipelinePage.saveInputNodeStream(); + await page.waitForTimeout(2000); + + await pipelinePage.selectAndDragCondition() // Condition drag + await pipelinePage.selectPreviousNode(); + await pipelinePage.selectPreviousNodeDrop(); + await page.getByPlaceholder('Column').click(); + await page.getByPlaceholder('Column').fill('container_name'); + await page.getByRole('option', { name: 'kubernetes_container_name' }).click(); + await page.locator('div:nth-child(2) > div:nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native').click(); + await page.getByText('Contains', { exact: true }).click(); + await page.getByPlaceholder('Value').click(); + await page.getByPlaceholder('Value').fill('prometheus'); + await pipelinePage.saveCondition() + await pipelinePage.selectAndDragSecondStream(); + await page.waitForTimeout(2000); + + await page.locator('.previous-drop-down > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native').click(); + await page.getByText('Condition 1').click(); + await pipelinePage.toggleCreateStream(); + await page.getByLabel("Name *").click(); + await page.getByLabel("Name *").fill("destination-node"); + await page + .locator( + ".q-form > div:nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native" + ) + .click(); + await page + .getByRole("option", { name: "Logs" }) + .locator("div") + .nth(2) + .click(); + await pipelinePage.clickSaveStream(); + await pipelinePage.clickInputNodeStreamSave(); + const pipelineName = `pipeline-${Math.random().toString(36).substring(7)}`; + await pipelinePage.enterPipelineName(pipelineName); + await pipelinePage.savePipeline(); + await page.waitForTimeout(1000); + await pipelinePage.searchPipeline(pipelineName); + await page.waitForTimeout(1000); + const deletePipelineButton = page.locator( + `[data-test="pipeline-list-${pipelineName}-delete-pipeline"]` + ); + await deletePipelineButton.waitFor({ state: "visible" }); + await deletePipelineButton.click(); + await pipelinePage.confirmDeletePipeline(); + await pipelinePage.verifyPipelineDeleted(); + }); + + + test("should display error when function is not selected under select function", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectAndDragFunction(); // Function drag + await page.waitForTimeout(2000); + await page.waitForTimeout(1000); + await pipelinePage.saveFunction(); + await pipelinePage.verifyFieldRequiredError(); + }); + + + test("should display error when condition is not added but user clicks save", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectAndDragCondition() // Function drag; + await page.waitForTimeout(1000); + await pipelinePage.saveCondition() + await pipelinePage.verifyFieldRequiredError(); + }); + + + test("should add source & destination node without connection and error to be displayed", async ({ + page, + }) => { + const pipelinePage = new PipelinePage(page); + + await pipelinePage.openPipelineMenu(); + await page.waitForTimeout(1000); + await pipelinePage.addPipeline(); + await pipelinePage.selectStream(); + await pipelinePage.dragStreamToTarget(pipelinePage.streamButton); + await pipelinePage.selectLogs(); + + // Interact with stream name and save + await pipelinePage.enterStreamName("e2e"); + await pipelinePage.enterStreamName("e2e_automate"); + await page.waitForTimeout(2000); + await pipelinePage.selectStreamOption(); + await pipelinePage.saveInputNodeStream(); + await pipelinePage.dragStreamToTarget(pipelinePage.streamButton); // First stream drag + + // Select the second stream, drag, and drop + await pipelinePage.selectAndDragSecondStream(); + await page.waitForTimeout(2000); + + // Select the previous node + // await pipelinePage.selectPreviousNode(); + // await pipelinePage.selectPreviousNodeDrop(); + await pipelinePage.toggleCreateStream(); + await page.getByLabel("Name *").click(); + await page.getByLabel("Name *").fill("destination-node"); + await page + .locator( + ".q-form > div:nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native" + ) + .click(); + await page + .getByRole("option", { name: "Logs" }) + .locator("div") + .nth(2) + .click(); + await pipelinePage.clickSaveStream(); + await pipelinePage.clickInputNodeStreamSave(); + const pipelineName = `pipeline-${Math.random().toString(36).substring(7)}`; + await pipelinePage.enterPipelineName(pipelineName); + await pipelinePage.savePipeline(); + await page.getByText('Please connect all nodes').click(); + + }); + +}); +