From 37ba1eb5adb962f6f13825ee0375e82b4823f254 Mon Sep 17 00:00:00 2001 From: kezhenxu94 Date: Tue, 30 Nov 2021 13:07:55 +0800 Subject: [PATCH] Add E2E tests for some core features (#7025) --- .github/workflows/e2e.yml | 16 +- .../e2e/cases/ProjectE2ETest.java | 68 ++ .../e2e/cases/TenantE2ETest.java | 88 +++ .../e2e/cases/WorkflowE2ETest.java | 200 ++++++ .../e2e/cases/security/TenantE2ETest.java | 98 --- .../dolphinscheduler/e2e/pages/LoginPage.java | 25 +- .../e2e/pages/common/CodeEditor.java | 45 ++ .../e2e/pages/common/NavBarPage.java | 62 ++ .../e2e/pages/project/ProjectDetailPage.java | 58 ++ .../e2e/pages/project/ProjectPage.java | 114 ++++ .../workflow/WorkflowDefinitionTab.java | 123 ++++ .../pages/project/workflow/WorkflowForm.java | 85 +++ .../project/workflow/WorkflowInstanceTab.java | 107 +++ .../project/workflow/WorkflowRunDialog.java | 46 ++ .../project/workflow/WorkflowSaveDialog.java | 115 ++++ .../project/workflow/task/ShellTaskForm.java | 42 ++ .../workflow/task/SubWorkflowTaskForm.java | 31 + .../project/workflow/task/TaskNodeForm.java | 93 +++ .../e2e/pages/security/SecurityPage.java | 51 ++ .../e2e/pages/{ => security}/TenantPage.java | 55 +- .../{tenant => basic}/docker-compose.yaml | 1 + .../src/test/resources/dragAndDrop.js | 55 ++ .../e2e/core/DolphinSchedulerExtension.java | 45 +- dolphinscheduler-e2e/pom.xml | 18 +- dolphinscheduler-ui/pom.xml | 2 +- .../home/pages/dag/_source/canvas/taskbar.vue | 3 +- .../home/pages/dag/_source/canvas/toolbar.vue | 1 + .../js/conf/home/pages/dag/_source/config.js | 18 +- .../js/conf/home/pages/dag/_source/dag.vue | 1 + .../pages/dag/_source/formModel/formModel.vue | 2 + .../formModel/tasks/_source/localParams.vue | 2 + .../dag/_source/udp/_source/selectTenant.vue | 2 + .../conf/home/pages/dag/_source/udp/udp.vue | 3 +- .../definition/pages/list/_source/list.vue | 14 +- .../definition/pages/list/_source/start.vue | 2 +- .../pages/definition/pages/list/index.vue | 2 +- .../instance/pages/list/_source/list.vue | 12 +- .../pages/list/_source/createProject.vue | 3 +- .../projects/pages/list/_source/list.vue | 6 +- .../home/pages/projects/pages/list/index.vue | 2 +- .../projects/pages/taskDefinition/index.vue | 614 +++++++++--------- .../src/js/module/components/nav/nav.vue | 4 +- .../components/secondaryMenu/_source/menu.js | 9 +- .../secondaryMenu/secondaryMenu.vue | 4 +- 44 files changed, 1861 insertions(+), 486 deletions(-) create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/ProjectE2ETest.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/TenantE2ETest.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java delete mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/security/TenantE2ETest.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowDefinitionTab.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowSaveDialog.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/ShellTaskForm.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java rename dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/{ => security}/TenantPage.java (55%) rename dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/{tenant => basic}/docker-compose.yaml (96%) create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/dragAndDrop.js diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 244b0e5fb3..5ccf937dda 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -27,10 +27,6 @@ on: branches: - dev -env: - TAG: ci - RECORDING_PATH: /tmp/recording - name: E2E concurrency: @@ -45,7 +41,13 @@ jobs: matrix: case: - name: Tenant - class: org.apache.dolphinscheduler.e2e.cases.security.TenantE2ETest + class: org.apache.dolphinscheduler.e2e.cases.TenantE2ETest + - name: Project + class: org.apache.dolphinscheduler.e2e.cases.ProjectE2ETest + - name: Workflow + class: org.apache.dolphinscheduler.e2e.cases.WorkflowE2ETest + env: + RECORDING_PATH: /tmp/recording-${{ matrix.case.name }} steps: - uses: actions/checkout@v2 with: @@ -62,13 +64,13 @@ jobs: run: TAG=ci sh ./docker/build/hooks/build - name: Run Test run: | - ./mvnw -f dolphinscheduler-e2e/pom.xml -am \ + ./mvnw -B -f dolphinscheduler-e2e/pom.xml -am \ -DfailIfNoTests=false \ -Dtest=${{ matrix.case.class }} test - uses: actions/upload-artifact@v2 if: always() name: Upload Recording with: - name: recording + name: recording-${{ matrix.case.name }} path: ${{ env.RECORDING_PATH }} retention-days: 1 diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/ProjectE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/ProjectE2ETest.java new file mode 100644 index 0000000000..9615075616 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/ProjectE2ETest.java @@ -0,0 +1,68 @@ +/* + * Licensed to Apache Software Foundation (ASF) under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Apache Software Foundation (ASF) licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.dolphinscheduler.e2e.cases; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.pages.LoginPage; +import org.apache.dolphinscheduler.e2e.pages.project.ProjectPage; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.remote.RemoteWebDriver; + +@DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml") +class ProjectE2ETest { + private static final String project = "test-project-1"; + + private static RemoteWebDriver browser; + + @BeforeAll + public static void setup() { + new LoginPage(browser) + .login("admin", "dolphinscheduler123") + .goToNav(ProjectPage.class); + } + + @Test + @Order(1) + void testCreateProject() { + new ProjectPage(browser).create(project); + } + + @Test + @Order(30) + void testDeleteProject() { + final var page = new ProjectPage(browser); + page.delete(project); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + assertThat( + page.projectList() + ).noneMatch( + it -> it.getText().contains(project) + ); + }); + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/TenantE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/TenantE2ETest.java new file mode 100644 index 0000000000..9de3edbca3 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/TenantE2ETest.java @@ -0,0 +1,88 @@ +/* + * Licensed to Apache Software Foundation (ASF) under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Apache Software Foundation (ASF) licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.dolphinscheduler.e2e.cases; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.pages.LoginPage; +import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage; +import org.apache.dolphinscheduler.e2e.pages.security.TenantPage; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.remote.RemoteWebDriver; + +@DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml") +class TenantE2ETest { + private static final String tenant = System.getProperty("user.name"); + + private static RemoteWebDriver browser; + + @BeforeAll + public static void setup() { + new LoginPage(browser) + .login("admin", "dolphinscheduler123") + .goToNav(SecurityPage.class) + .goToTab(TenantPage.class) + ; + } + + @Test + @Order(10) + void testCreateTenant() { + new TenantPage(browser).create(tenant); + } + + @Test + @Order(20) + void testCreateDuplicateTenant() { + final var page = new TenantPage(browser); + + page.create(tenant); + + await().untilAsserted(() -> + assertThat(browser.findElement(By.tagName("body")).getText()) + .contains("already exists") + ); + + page.createTenantForm().buttonCancel().click(); + } + + @Test + @Order(30) + void testDeleteTenant() { + final var page = new TenantPage(browser); + page.delete(tenant); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + assertThat( + page.tenantList() + ).noneMatch( + it -> it.getText().contains(tenant) + ); + }); + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java new file mode 100644 index 0000000000..cc51932114 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java @@ -0,0 +1,200 @@ +/* + * Licensed to Apache Software Foundation (ASF) under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Apache Software Foundation (ASF) licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.dolphinscheduler.e2e.cases; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; +import org.apache.dolphinscheduler.e2e.pages.LoginPage; +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; +import org.apache.dolphinscheduler.e2e.pages.project.ProjectPage; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowDefinitionTab; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm.TaskType; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowInstanceTab; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowInstanceTab.Row; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.ShellTaskForm; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.SubWorkflowTaskForm; +import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage; +import org.apache.dolphinscheduler.e2e.pages.security.TenantPage; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.remote.RemoteWebDriver; + +@DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml") +class WorkflowE2ETest { + private static final String project = "test-workflow-1"; + private static final String tenant = System.getProperty("user.name"); + + private static RemoteWebDriver browser; + + @BeforeAll + public static void setup() { + new LoginPage(browser) + .login("admin", "dolphinscheduler123") + .goToNav(SecurityPage.class) + .goToTab(TenantPage.class) + .create(tenant) + .goToNav(ProjectPage.class) + .create(project) + ; + } + + @AfterAll + public static void cleanup() { + new NavBarPage(browser) + .goToNav(ProjectPage.class) + .goTo(project) + .goToTab(WorkflowDefinitionTab.class) + .cancelPublishAll() + .deleteAll() + ; + new NavBarPage(browser) + .goToNav(ProjectPage.class) + .delete(project) + .goToNav(SecurityPage.class) + .goToTab(TenantPage.class) + .delete(tenant) + ; + } + + @Test + @Order(1) + void testCreateWorkflow() { + final var workflow = "test-workflow-1"; + + final var workflowDefinitionPage = + new ProjectPage(browser) + .goTo(project) + .goToTab(WorkflowDefinitionTab.class); + + workflowDefinitionPage + .createWorkflow() + + . addTask(TaskType.SHELL) + .script("echo ${today}\necho ${global_param}\n") + .name("test-1") + .addParam("today", "${system.datetime}") + .submit() + + .submit() + .name(workflow) + .tenant(tenant) + .addGlobalParam("global_param", "hello world") + .submit() + ; + + await().untilAsserted(() -> assertThat( + workflowDefinitionPage.workflowList() + ).anyMatch(it -> it.getText().contains(workflow))); + + workflowDefinitionPage.publish(workflow); + } + + @Test + @Order(10) + void testCreateSubWorkflow() { + final var workflow = "test-sub-workflow-1"; + + final var workflowDefinitionPage = + new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(project) + .goToTab(WorkflowDefinitionTab.class); + + workflowDefinitionPage + .createWorkflow() + + . addTask(TaskType.SUB_PROCESS) + .submit() + + .submit() + .name(workflow) + .tenant(tenant) + .addGlobalParam("global_param", "hello world") + .submit() + ; + + await().untilAsserted(() -> assertThat( + workflowDefinitionPage.workflowList() + ).anyMatch(it -> it.getText().contains(workflow))); + + workflowDefinitionPage.publish(workflow); + } + + @Test + @Order(30) + void testRunWorkflow() { + final var workflow = "test-workflow-1"; + + final var projectPage = + new ProjectPage(browser) + .goToNav(ProjectPage.class) + .goTo(project); + + projectPage + .goToTab(WorkflowInstanceTab.class) + .deleteAll(); + + projectPage + .goToTab(WorkflowDefinitionTab.class) + .run(workflow) + .submit(); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + + final Row row = projectPage + .goToTab(WorkflowInstanceTab.class) + .instances() + .iterator() + .next(); + + assertThat(row.isSuccess()).isTrue(); + assertThat(row.executionTime()).isEqualTo(1); + }); + + // Test rerun + projectPage + .goToTab(WorkflowInstanceTab.class) + .instances() + .stream() + .filter(it -> it.rerunButton().isDisplayed()) + .iterator() + .next() + .rerun(); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + + final Row row = projectPage + .goToTab(WorkflowInstanceTab.class) + .instances() + .iterator() + .next(); + + assertThat(row.isSuccess()).isTrue(); + assertThat(row.executionTime()).isEqualTo(2); + }); + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/security/TenantE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/security/TenantE2ETest.java deleted file mode 100644 index ab3159a275..0000000000 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/security/TenantE2ETest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to Apache Software Foundation (ASF) under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Apache Software Foundation (ASF) licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.dolphinscheduler.e2e.cases.security; - - -import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; - -import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; -import org.apache.dolphinscheduler.e2e.pages.LoginPage; -import org.apache.dolphinscheduler.e2e.pages.TenantPage; - -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.openqa.selenium.By; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.remote.RemoteWebDriver; - -@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml") -class TenantE2ETest { - private RemoteWebDriver browser; - - @Test - @Order(1) - void testLogin() { - final LoginPage page = new LoginPage(browser); - page.inputUsername().sendKeys("admin"); - page.inputPassword().sendKeys("dolphinscheduler123"); - page.buttonLogin().click(); - } - - @Test - @Order(10) - void testCreateTenant() { - final TenantPage page = new TenantPage(browser); - final String tenant = System.getProperty("user.name"); - - page.buttonCreateTenant().click(); - page.createTenantForm().inputTenantCode().sendKeys(tenant); - page.createTenantForm().inputDescription().sendKeys("Test"); - page.createTenantForm().buttonSubmit().click(); - - await().untilAsserted(() -> assertThat(page.tenantList()) - .as("Tenant list should contain newly-created tenant") - .extracting(WebElement::getText) - .anyMatch(it -> it.contains(tenant))); - } - - @Test - @Order(20) - void testCreateDuplicateTenant() { - final String tenant = System.getProperty("user.name"); - final TenantPage page = new TenantPage(browser); - page.buttonCreateTenant().click(); - page.createTenantForm().inputTenantCode().sendKeys(tenant); - page.createTenantForm().inputDescription().sendKeys("Test"); - page.createTenantForm().buttonSubmit().click(); - - await().untilAsserted(() -> assertThat(browser.findElementByTagName("body") - .getText().contains("already exists")) - .as("Should fail when creating a duplicate tenant") - .isTrue()); - - page.createTenantForm().buttonCancel().click(); - } - - @Test - @Order(30) - void testDeleteTenant() { - final String tenant = System.getProperty("user.name"); - final TenantPage page = new TenantPage(browser); - - page.tenantList() - .stream() - .filter(it -> it.getText().contains(tenant)) - .findFirst() - .ifPresent(it -> it.findElement(By.className("delete")).click()); - - page.buttonConfirm().click(); - } -} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java index a772517204..f2431d6311 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java @@ -19,17 +19,20 @@ package org.apache.dolphinscheduler.e2e.pages; +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; +import org.apache.dolphinscheduler.e2e.pages.security.TenantPage; + import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; import lombok.Getter; +import lombok.SneakyThrows; @Getter -public final class LoginPage { - private final RemoteWebDriver driver; - +public final class LoginPage extends NavBarPage { @FindBy(id = "input-username") private WebElement inputUsername; @@ -40,8 +43,18 @@ public final class LoginPage { private WebElement buttonLogin; public LoginPage(RemoteWebDriver driver) { - this.driver = driver; + super(driver); + } + + @SneakyThrows + public TenantPage login(String username, String password) { + inputUsername().sendKeys(username); + inputPassword().sendKeys(password); + buttonLogin().click(); + + new WebDriverWait(driver(), 10) + .until(ExpectedConditions.urlContains("/#/security")); - PageFactory.initElements(driver, this); + return new TenantPage(driver); } } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java new file mode 100644 index 0000000000..5a8645d496 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.common; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.PageFactory; + +import lombok.Getter; + +@Getter +public final class CodeEditor { + @FindBy(className = "CodeMirror") + private WebElement editor; + + public CodeEditor(WebDriver driver) { + PageFactory.initElements(driver, this); + } + + public CodeEditor content(String content) { + editor.findElement(By.className("CodeMirror-line")).click(); + editor.findElement(By.tagName("textarea")).sendKeys(content); + + return this; + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java new file mode 100644 index 0000000000..546a714236 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.common; + +import org.apache.dolphinscheduler.e2e.pages.project.ProjectPage; +import org.apache.dolphinscheduler.e2e.pages.security.SecurityPage; + +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.PageFactory; + +import lombok.Getter; + +@Getter +public class NavBarPage { + protected final RemoteWebDriver driver; + + @FindBy(id = "project-tab") + private WebElement projectTab; + @FindBy(id = "security-tab") + private WebElement securityTab; + + public NavBarPage(RemoteWebDriver driver) { + this.driver = driver; + + PageFactory.initElements(driver, this); + } + + public T goToNav(Class nav) { + if (nav == ProjectPage.class) { + projectTab().click(); + return nav.cast(new ProjectPage(driver)); + } + if (nav == SecurityPage.class) { + securityTab().click(); + return nav.cast(new SecurityPage(driver)); + } + + throw new UnsupportedOperationException("Unknown nav bar"); + } + + public interface NavBarItem { + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java new file mode 100644 index 0000000000..5dd7051524 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.project; + +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowDefinitionTab; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowInstanceTab; + +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.FindBy; + +import lombok.Getter; + +@Getter +public final class ProjectDetailPage extends NavBarPage { + @FindBy(className = "process-definition") + private WebElement menuProcessDefinition; + @FindBy(className = "process-instance") + private WebElement menuProcessInstances; + + public ProjectDetailPage(RemoteWebDriver driver) { + super(driver); + } + + public T goToTab(Class tab) { + if (tab == WorkflowDefinitionTab.class) { + menuProcessDefinition().click(); + return tab.cast(new WorkflowDefinitionTab(driver)); + } + if (tab == WorkflowInstanceTab.class) { + menuProcessInstances().click(); + return tab.cast(new WorkflowInstanceTab(driver)); + } + + throw new UnsupportedOperationException("Unknown tab: " + tab.getName()); + } + + public interface Tab { + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java new file mode 100644 index 0000000000..86cdb931bd --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.project; + +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage.NavBarItem; + +import java.util.List; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.FindBys; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +import lombok.Getter; + +@Getter +public final class ProjectPage extends NavBarPage implements NavBarItem { + @FindBy(id = "button-create-project") + private WebElement buttonCreateProject; + + @FindBy(className = "rows-project") + private List projectList; + + @FindBys({ + @FindBy(className = "el-popconfirm"), + @FindBy(className = "el-button--primary"), + }) + private List buttonConfirm; + + private final CreateProjectForm createProjectForm; + + public ProjectPage(RemoteWebDriver driver) { + super(driver); + + this.createProjectForm = new CreateProjectForm(); + + PageFactory.initElements(driver, this); + } + + public ProjectPage create(String project) { + buttonCreateProject().click(); + createProjectForm().inputProjectName().sendKeys(project); + createProjectForm().buttonSubmit().click(); + + new WebDriverWait(driver(), 10) + .until(ExpectedConditions.textToBePresentInElementLocated(By.className("project-name"), project)); + + return this; + } + + public ProjectPage delete(String project) { + projectList() + .stream() + .filter(it -> it.getText().contains(project)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Cannot find project: " + project)) + .findElement(By.className("delete")).click(); + + buttonConfirm() + .stream() + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No confirm button is displayed")) + .click(); + + return this; + } + + public ProjectDetailPage goTo(String project) { + projectList().stream() + .filter(it -> it.getText().contains(project)) + .map(it -> it.findElement(By.className("project-name"))) + .findFirst() + .orElseThrow(() -> new RuntimeException("Cannot click the project item")) + .click(); + + return new ProjectDetailPage(driver); + } + + @Getter + public class CreateProjectForm { + CreateProjectForm() { + PageFactory.initElements(driver, this); + } + + @FindBy(id = "input-project-name") + private WebElement inputProjectName; + + @FindBy(id = "button-submit") + private WebElement buttonSubmit; + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowDefinitionTab.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowDefinitionTab.java new file mode 100644 index 0000000000..56f0eb3d04 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowDefinitionTab.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.project.workflow; + +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; +import org.apache.dolphinscheduler.e2e.pages.project.ProjectDetailPage; + +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.FindBys; + +import lombok.Getter; + +@Getter +public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDetailPage.Tab { + @FindBy(id = "button-create-process") + private WebElement buttonCreateProcess; + @FindBy(className = "select-all") + private WebElement checkBoxSelectAll; + @FindBy(className = "button-delete-all") + private WebElement buttonDeleteAll; + @FindBys({ + @FindBy(className = "el-popconfirm"), + @FindBy(className = "el-button--primary"), + }) + private List buttonConfirm; + @FindBy(className = "rows-workflow-definitions") + private List workflowList; + + public WorkflowDefinitionTab(RemoteWebDriver driver) { + super(driver); + } + + public WorkflowForm createWorkflow() { + buttonCreateProcess().click(); + + return new WorkflowForm(driver); + } + + public WorkflowDefinitionTab publish(String workflow) { + workflowList() + .stream() + .filter(it -> it.findElement(By.className("name")).getAttribute("innerHTML").equals(workflow)) + .flatMap(it -> it.findElements(By.className("button-publish")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("Cannot find publish button in workflow definition")) + .click(); + + return this; + } + + public WorkflowRunDialog run(String workflow) { + workflowList() + .stream() + .filter(it -> it.findElement(By.className("name")).getAttribute("innerHTML").equals(workflow)) + .flatMap(it -> it.findElements(By.className("button-run")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("Cannot find run button in workflow definition")) + .click(); + + return new WorkflowRunDialog(this); + } + + public WorkflowDefinitionTab cancelPublishAll() { + final Supplier> cancelButtons = () -> + workflowList() + .stream() + .flatMap(it -> it.findElements(By.className("button-cancel-publish")).stream()) + .filter(WebElement::isDisplayed) + .collect(Collectors.toList()); + + for (var buttons = cancelButtons.get(); + !buttons.isEmpty(); + buttons = cancelButtons.get()) { + buttons.forEach(WebElement::click); + driver().navigate().refresh(); + } + + return this; + } + + public WorkflowDefinitionTab deleteAll() { + if (workflowList().isEmpty()) { + return this; + } + + checkBoxSelectAll().click(); + buttonDeleteAll().click(); + buttonConfirm() + .stream() + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No confirm button is displayed")) + .click(); + + return this; + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java new file mode 100644 index 0000000000..95c21b1ba2 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.project.workflow; + +import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.ShellTaskForm; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.SubWorkflowTaskForm; + +import java.nio.charset.StandardCharsets; + +import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.PageFactory; + +import com.google.common.io.Resources; + +import lombok.Getter; +import lombok.SneakyThrows; + +@SuppressWarnings("UnstableApiUsage") +@Getter +public final class WorkflowForm { + private final WebDriver driver; + private final WorkflowSaveDialog saveForm; + + @FindBy(id = "button-save") + private WebElement buttonSave; + + public WorkflowForm(WebDriver driver) { + this.driver = driver; + this.saveForm = new WorkflowSaveDialog(this); + + PageFactory.initElements(driver, this); + } + + @SneakyThrows + @SuppressWarnings("unchecked") + public T addTask(TaskType type) { + final var task = driver.findElement(By.className("task-item-" + type.name())); + final var canvas = driver.findElement(By.className("dag-container")); + + final var js = (JavascriptExecutor) driver; + final var dragAndDrop = String.join("\n", + Resources.readLines(Resources.getResource("dragAndDrop.js"), StandardCharsets.UTF_8)); + js.executeScript(dragAndDrop, task, canvas); + + switch (type) { + case SHELL: + return (T) new ShellTaskForm(this); + case SUB_PROCESS: + return (T) new SubWorkflowTaskForm(this); + } + throw new UnsupportedOperationException("Unknown task type"); + } + + public WorkflowSaveDialog submit() { + buttonSave().click(); + + return new WorkflowSaveDialog(this); + } + + public enum TaskType { + SHELL, + SUB_PROCESS, + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java new file mode 100644 index 0000000000..97f29b40a9 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.project.workflow; + +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; +import org.apache.dolphinscheduler.e2e.pages.project.ProjectDetailPage; + +import java.util.List; +import java.util.stream.Collectors; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.FindBys; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +public final class WorkflowInstanceTab extends NavBarPage implements ProjectDetailPage.Tab { + @FindBy(className = "rows-workflow-instances") + private List instanceList; + @FindBy(className = "select-all") + private WebElement checkBoxSelectAll; + @FindBy(className = "button-delete-all") + private WebElement buttonDeleteAll; + @FindBys({ + @FindBy(className = "el-popconfirm"), + @FindBy(className = "el-button--primary"), + }) + private List buttonConfirm; + + public WorkflowInstanceTab(RemoteWebDriver driver) { + super(driver); + } + + public List instances() { + return instanceList() + .stream() + .filter(WebElement::isDisplayed) + .map(Row::new) + .collect(Collectors.toList()); + } + + public WorkflowInstanceTab deleteAll() { + if (instanceList().isEmpty()) { + return this; + } + + checkBoxSelectAll().click(); + buttonDeleteAll().click(); + buttonConfirm() + .stream() + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No confirm button is displayed")) + .click(); + + return this; + } + + @RequiredArgsConstructor + public static class Row { + private final WebElement row; + + public WebElement rerunButton() { + return row.findElement(By.className("button-rerun")); + } + + public boolean isSuccess() { + return !row.findElements(By.className("success")).isEmpty(); + } + + public int executionTime() { + return Integer.parseInt(row.findElement(By.className("execution-time")).getText()); + } + + public Row rerun() { + row.findElements(By.className("button-rerun")) + .stream() + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("Cannot find rerun button")) + .click(); + + return this; + } + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java new file mode 100644 index 0000000000..9801378454 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.project.workflow; + +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.PageFactory; + +import lombok.Getter; + +@Getter +public final class WorkflowRunDialog { + private final WorkflowDefinitionTab parent; + + @FindBy(id = "button-submit") + private WebElement buttonSubmit; + + public WorkflowRunDialog(WorkflowDefinitionTab parent) { + this.parent = parent; + + PageFactory.initElements(parent().driver(), this); + } + + public WorkflowDefinitionTab submit() { + buttonSubmit().click(); + + return parent(); + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowSaveDialog.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowSaveDialog.java new file mode 100644 index 0000000000..ce08926f90 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowSaveDialog.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.project.workflow; + +import java.util.List; +import java.util.stream.Stream; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.FindBys; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.pagefactory.ByChained; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +import lombok.Getter; + +@Getter +public final class WorkflowSaveDialog { + private final WebDriver driver; + private final WorkflowForm parent; + + @FindBy(id = "input-name") + private WebElement inputName; + @FindBy(id = "button-submit") + private WebElement buttonSubmit; + @FindBys({ + @FindBy(className = "input-param-key"), + @FindBy(tagName = "input"), + }) + private List inputParamKey; + @FindBys({ + @FindBy(className = "input-param-val"), + @FindBy(tagName = "input"), + }) + private List inputParamVal; + @FindBy(id = "select-tenant") + private WebElement selectTenant; + + public WorkflowSaveDialog(WorkflowForm parent) { + this.parent = parent; + this.driver = parent.driver(); + + PageFactory.initElements(driver, this); + } + + public WorkflowSaveDialog name(String name) { + inputName().sendKeys(name); + + return this; + } + + public WorkflowSaveDialog tenant(String tenant) { + selectTenant().click(); + + final var optionsLocator = By.className("option-tenants"); + + new WebDriverWait(driver, 10) + .until(ExpectedConditions.visibilityOfElementLocated(optionsLocator)); + + driver().findElements(optionsLocator) + .stream() + .filter(it -> it.getText().contains(tenant)) + .findFirst() + .orElseThrow(() -> new RuntimeException("No such tenant: " + tenant)) + .click() + ; + + return this; + } + + public WorkflowSaveDialog addGlobalParam(String key, String val) { + assert inputParamKey().size() == inputParamVal().size(); + + final var len = inputParamKey().size(); + + final var driver = parent().driver(); + Stream.concat( + driver.findElements(new ByChained(By.className("user-def-params-model"), By.className("add"))).stream(), + driver.findElements(new ByChained(By.className("user-def-params-model"), By.className("add-dp"))).stream()) + .findFirst() + .orElseThrow(() -> new RuntimeException("Cannot find button to add param")) + .click(); + + inputParamKey().get(len).sendKeys(key); + inputParamVal().get(len).sendKeys(val); + + return this; + } + + public WorkflowForm submit() { + buttonSubmit().click(); + + return parent; + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/ShellTaskForm.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/ShellTaskForm.java new file mode 100644 index 0000000000..70b5f5dfa2 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/ShellTaskForm.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.project.workflow.task; + +import org.apache.dolphinscheduler.e2e.pages.common.CodeEditor; +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm; + +import lombok.Getter; + +@Getter +public final class ShellTaskForm extends TaskNodeForm { + private final CodeEditor codeEditor; + + public ShellTaskForm(WorkflowForm parent) { + super(parent); + + this.codeEditor = new CodeEditor(parent.driver()); + } + + public ShellTaskForm script(String script) { + codeEditor().content(script); + + return this; + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java new file mode 100644 index 0000000000..a94102f769 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.project.workflow.task; + +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm; + +import lombok.Getter; + +@Getter +public final class SubWorkflowTaskForm extends TaskNodeForm { + public SubWorkflowTaskForm(WorkflowForm parent) { + super(parent); + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java new file mode 100644 index 0000000000..8689a21569 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.project.workflow.task; + +import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm; + +import java.util.List; +import java.util.stream.Stream; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.FindBys; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.pagefactory.ByChained; + +import lombok.Getter; + +@Getter +public abstract class TaskNodeForm { + @FindBy(id = "input-node-name") + private WebElement inputNodeName; + @FindBy(id = "button-submit") + private WebElement buttonSubmit; + @FindBys({ + @FindBy(className = "input-param-key"), + @FindBy(tagName = "input"), + }) + private List inputParamKey; + @FindBys({ + @FindBy(className = "input-param-val"), + @FindBy(tagName = "input"), + }) + private List inputParamVal; + + private final WorkflowForm parent; + + TaskNodeForm(WorkflowForm parent) { + this.parent = parent; + + final var driver = parent.driver(); + + PageFactory.initElements(driver, this); + } + + public TaskNodeForm name(String name) { + inputNodeName().sendKeys(name); + + return this; + } + + public TaskNodeForm addParam(String key, String val) { + assert inputParamKey().size() == inputParamVal().size(); + + final var len = inputParamKey().size(); + + final var driver = parent().driver(); + Stream.concat( + driver.findElements(new ByChained(By.className("user-def-params-model"), By.className("add"))).stream(), + driver.findElements(new ByChained(By.className("user-def-params-model"), By.className("add-dp"))).stream()) + .findFirst() + .orElseThrow(() -> new RuntimeException("Cannot find button to add param")) + .click(); + + inputParamKey().get(len).sendKeys(key); + inputParamVal().get(len).sendKeys(val); + + return this; + } + + public WorkflowForm submit() { + buttonSubmit.click(); + + return parent(); + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java new file mode 100644 index 0000000000..8e4c7b9848 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/SecurityPage.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.dolphinscheduler.e2e.pages.security; + +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage.NavBarItem; + +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.FindBy; + +import lombok.Getter; + +@Getter +public class SecurityPage extends NavBarPage implements NavBarItem { + @FindBy(className = "tenant-manage") + private WebElement menuTenantManage; + + public SecurityPage(RemoteWebDriver driver) { + super(driver); + } + + public T goToTab(Class tab) { + if (tab == TenantPage.class) { + menuTenantManage().click(); + return tab.cast(new TenantPage(driver)); + } + + throw new UnsupportedOperationException("Unknown tab: " + tab.getName()); + } + + public interface Tab { + } +} diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/TenantPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java similarity index 55% rename from dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/TenantPage.java rename to dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java index da973490d3..6e9c548189 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/TenantPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java @@ -17,12 +17,18 @@ * under the License. */ -package org.apache.dolphinscheduler.e2e.pages; +package org.apache.dolphinscheduler.e2e.pages.security; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; import java.util.List; -import org.openqa.selenium.WebDriver; +import org.openqa.selenium.By; import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.FindBys; import org.openqa.selenium.support.PageFactory; @@ -30,9 +36,7 @@ import org.openqa.selenium.support.PageFactory; import lombok.Getter; @Getter -public final class TenantPage { - private final WebDriver driver; - +public final class TenantPage extends NavBarPage implements SecurityPage.Tab { @FindBy(id = "button-create-tenant") private WebElement buttonCreateTenant; @@ -40,18 +44,47 @@ public final class TenantPage { private List tenantList; @FindBys({ - @FindBy(className = "el-popconfirm"), - @FindBy(className = "el-button--primary"), + @FindBy(className = "el-popconfirm"), + @FindBy(className = "el-button--primary"), }) private WebElement buttonConfirm; private final CreateTenantForm createTenantForm; - public TenantPage(WebDriver driver) { - this.driver = driver; - this.createTenantForm = new CreateTenantForm(); + public TenantPage(RemoteWebDriver driver) { + super(driver); + + createTenantForm = new CreateTenantForm(); + } + + public TenantPage create(String tenant) { + return create(tenant, ""); + } + + public TenantPage create(String tenant, String description) { + buttonCreateTenant().click(); + createTenantForm().inputTenantCode().sendKeys(tenant); + createTenantForm().inputDescription().sendKeys(description); + createTenantForm().buttonSubmit().click(); + + await().untilAsserted(() -> assertThat(tenantList()) + .as("Tenant list should contain newly-created tenant") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(tenant))); + + return this; + } + + public TenantPage delete(String tenant) { + tenantList() + .stream() + .filter(it -> it.getText().contains(tenant)) + .findFirst() + .ifPresent(it -> it.findElement(By.className("delete")).click()); + + buttonConfirm().click(); - PageFactory.initElements(driver, this); + return this; } @Getter diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/tenant/docker-compose.yaml b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/basic/docker-compose.yaml similarity index 96% rename from dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/tenant/docker-compose.yaml rename to dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/basic/docker-compose.yaml index ec761b291a..22bd9ecf2b 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/tenant/docker-compose.yaml +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/basic/docker-compose.yaml @@ -23,6 +23,7 @@ services: command: [ standalone-server ] environment: DATABASE_TYPE: h2 + WORKER_TENANT_AUTO_CREATE: 'true' expose: - 12345 networks: diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/dragAndDrop.js b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/dragAndDrop.js new file mode 100644 index 0000000000..96011d9c32 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/dragAndDrop.js @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function createEvent(typeOfEvent) { + const event = document.createEvent("CustomEvent"); + event.initCustomEvent(typeOfEvent, true, true, null); + event.dataTransfer = { + data: {}, + setData: function (key, value) { + this.data[key] = value; + }, + getData: function (key) { + return this.data[key]; + } + }; + return event; +} + +function dispatchEvent(element, event, transferData) { + if (transferData !== undefined) { + event.dataTransfer = transferData; + } + if (element.dispatchEvent) { + element.dispatchEvent(event); + } else if (element.fireEvent) { + element.fireEvent("on" + event.type, event); + } +} + +function simulateHTML5DragAndDrop(element, destination) { + const dragStartEvent = createEvent('dragstart'); + dispatchEvent(element, dragStartEvent); + const dropEvent = createEvent('drop'); + dispatchEvent(destination, dropEvent, dragStartEvent.dataTransfer); + const dragEndEvent = createEvent('dragend'); + dispatchEvent(element, dragEndEvent, dropEvent.dataTransfer); +} + +const source = arguments[0]; +const destination = arguments[1]; +simulateHTML5DragAndDrop(source, destination); diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java index d7f3232675..d6b18861c5 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-core/src/main/java/org/apache/dolphinscheduler/e2e/core/DolphinSchedulerExtension.java @@ -24,6 +24,8 @@ import static org.testcontainers.containers.VncRecordingContainer.VncRecordingFo import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -60,8 +62,8 @@ import lombok.extern.slf4j.Slf4j; @Slf4j final class DolphinSchedulerExtension - implements BeforeAllCallback, AfterAllCallback, - BeforeEachCallback { + implements BeforeAllCallback, AfterAllCallback, + BeforeEachCallback { private final boolean LOCAL_MODE = Objects.equals(System.getProperty("local"), "true"); private RemoteWebDriver driver; @@ -71,7 +73,7 @@ final class DolphinSchedulerExtension @Override @SuppressWarnings("UnstableApiUsage") public void beforeAll(ExtensionContext context) throws IOException { - Awaitility.setDefaultTimeout(Duration.ofSeconds(5)); + Awaitility.setDefaultTimeout(Duration.ofSeconds(10)); Awaitility.setDefaultPollInterval(Duration.ofSeconds(1)); Network network = null; @@ -115,8 +117,8 @@ final class DolphinSchedulerExtension record = Files.createTempDirectory("record-"); } browser = new BrowserWebDriverContainer<>() - .withCapabilities(new ChromeOptions()) - .withRecordingMode(RECORD_ALL, record.toFile(), MP4); + .withCapabilities(new ChromeOptions()) + .withRecordingMode(RECORD_ALL, record.toFile(), MP4); if (network != null) { browser.withNetwork(network); } @@ -127,6 +129,8 @@ final class DolphinSchedulerExtension driver.manage().timeouts() .implicitlyWait(5, TimeUnit.SECONDS) .pageLoadTimeout(5, TimeUnit.SECONDS); + driver.manage().window() + .maximize(); if (address == null) { try { address = HostAndPort.fromParts(browser.getTestHostIpAddress(), 8888); @@ -142,6 +146,12 @@ final class DolphinSchedulerExtension driver.get(new URL("http", address.getHost(), address.getPort(), rootPath).toString()); browser.beforeTest(new TestDescription(context)); + + final Class clazz = context.getRequiredTestClass(); + Stream.of(clazz.getDeclaredFields()) + .filter(it -> Modifier.isStatic(it.getModifiers())) + .filter(f -> WebDriver.class.isAssignableFrom(f.getType())) + .forEach(it -> setDriver(clazz, it)); } @Override @@ -158,14 +168,16 @@ final class DolphinSchedulerExtension final Object instance = context.getRequiredTestInstance(); Stream.of(instance.getClass().getDeclaredFields()) .filter(f -> WebDriver.class.isAssignableFrom(f.getType())) - .forEach(it -> { - try { - it.setAccessible(true); - it.set(instance, driver); - } catch (IllegalAccessException e) { - LOGGER.error("Failed to inject web driver to field: {}", it.getName(), e); - } - }); + .forEach(it -> setDriver(instance, it)); + } + + private void setDriver(Object object, Field field) { + try { + field.setAccessible(true); + field.set(object, driver); + } catch (IllegalAccessException e) { + LOGGER.error("Failed to inject web driver to field: {}", field.getName(), e); + } } private DockerComposeContainer createDockerCompose(ExtensionContext context) { @@ -178,9 +190,10 @@ final class DolphinSchedulerExtension .map(File::new) .collect(Collectors.toList()); compose = new DockerComposeContainer<>(files) - .withPull(true) - .withTailChildContainers(true) - .waitingFor("dolphinscheduler_1", Wait.forHealthcheck()); + .withPull(true) + .withTailChildContainers(true) + .withLogConsumer("dolphinscheduler_1", outputFrame -> LOGGER.info(outputFrame.getUtf8String())) + .waitingFor("dolphinscheduler_1", Wait.forHealthcheck()); return compose; } diff --git a/dolphinscheduler-e2e/pom.xml b/dolphinscheduler-e2e/pom.xml index 1c7ce2ecfa..22f913df95 100644 --- a/dolphinscheduler-e2e/pom.xml +++ b/dolphinscheduler-e2e/pom.xml @@ -31,8 +31,8 @@ - 8 - 8 + 11 + 11 UTF-8 5.7.2 @@ -41,18 +41,21 @@ 3.20.2 4.1.0 1.5.30 + 1.7.32 + 2.14.1 + 31.0.1-jre org.slf4j slf4j-api - 1.7.32 + ${slf4j-api.version} org.apache.logging.log4j log4j-slf4j-impl - 2.14.1 + ${log4j-slf4j-impl.version} @@ -109,6 +112,11 @@ + + com.google.guava + guava + ${guava.version} + org.junit junit-bom @@ -119,7 +127,7 @@ org.testcontainers testcontainers-bom - 1.16.0 + 1.16.1 import pom diff --git a/dolphinscheduler-ui/pom.xml b/dolphinscheduler-ui/pom.xml index a50b82e674..8ffb2d4c68 100644 --- a/dolphinscheduler-ui/pom.xml +++ b/dolphinscheduler-ui/pom.xml @@ -29,7 +29,7 @@ ${project.artifactId} - v12.20.2 + v14.15.1 6.14.11 src diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/canvas/taskbar.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/canvas/taskbar.vue index 7c5b66544d..5a46aca5a2 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/canvas/taskbar.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/canvas/taskbar.vue @@ -25,7 +25,8 @@ :key="taskType.name" @onDragstart="(e) => $emit('on-drag-start', e, taskType)" :class="{ - disabled: isDetails + disabled: isDetails, + [`task-item-${taskType.name}`]: true }" >
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/canvas/toolbar.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/canvas/toolbar.vue index d8f57ad959..3b8f4157bf 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/canvas/toolbar.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/canvas/toolbar.vue @@ -143,6 +143,7 @@ type="primary" size="mini" @click="saveProcess" + id="button-save" >{{ $t("Save") }}
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue index ac21d6a6f3..e80f03f500 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue @@ -60,6 +60,7 @@ :disabled="isDetails" :placeholder="$t('Please enter name (required)')" maxlength="100" + id="input-node-name" >
@@ -437,6 +438,7 @@ :loading="spinnerLoading" @click="ok()" :disabled="isDetails" + id="button-submit" >{{ spinnerLoading ? $t("Loading...") : $t("Confirm") }}
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/localParams.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/localParams.vue index ae9be4c040..b468cf9d56 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/localParams.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/localParams.vue @@ -26,6 +26,7 @@ size="small" v-model="localParamsList[$index].prop" :placeholder="$t('prop(required)')" + class="input-param-key" maxlength="256" @blur="_verifProp()" :style="inputStyle"> @@ -64,6 +65,7 @@ size="small" v-model="localParamsList[$index].value" :placeholder="$t('value(optional)')" + class="input-param-val" maxlength="256" @blur="_handleValue()" :style="inputStyle"> diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/udp/_source/selectTenant.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/udp/_source/selectTenant.vue index 0a491f9aa5..50a789f43c 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/udp/_source/selectTenant.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/udp/_source/selectTenant.vue @@ -20,9 +20,11 @@ @change="_onChange" v-model="selectedValue" size="small" + id="select-tenant" style="width: 180px"> diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/udp/udp.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/udp/udp.vue index 100f47f78b..d39ac79c3b 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/udp/udp.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/udp/udp.vue @@ -22,6 +22,7 @@ type="text" size="small" v-model="name" + id="input-name" :disabled="router.history.current.name === 'projects-instance-details'" :placeholder="$t('Please enter name (required)')"> @@ -101,7 +102,7 @@ {{$t('Cancel')}} - {{$t('Add')}} + {{$t('Add')}} diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/list.vue index 0af0b5a836..b7d99bfe20 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/list.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/list.vue @@ -17,8 +17,8 @@