diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 244b0e5fb37ae854f6f88c7f91beb61f9810f32c..5ccf937ddafadef01e2893c775d78841ff3ac642 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 0000000000000000000000000000000000000000..961507561691fb7d26b3c0a9e2efb7de33557f92 --- /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 0000000000000000000000000000000000000000..9de3edbca3d2ad8b25f077df68a5ec1253909d05 --- /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 0000000000000000000000000000000000000000..cc519321143fe2c647375c7b5e5cd17c7166976f --- /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 ab3159a27579ff01005a639d8a21fb574b2b06bb..0000000000000000000000000000000000000000 --- 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 a772517204594c6d32edd79c62e3429404b141c5..f2431d6311e253977c421f69172c165f5c2603c1 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 0000000000000000000000000000000000000000..5a8645d49604bf1691773212d28cc5cab9204b7b --- /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 0000000000000000000000000000000000000000..546a7142360c90a90277aa928e3fc1036e62d8d3 --- /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 0000000000000000000000000000000000000000..5dd7051524cb296b4e1f39adbb6bcbb22bc3fd6f --- /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 0000000000000000000000000000000000000000..86cdb931bd651f414ae4180533b98257e2254272 --- /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 0000000000000000000000000000000000000000..56f0eb3d04de5793594cf25b2cf244d36c40f43c --- /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 0000000000000000000000000000000000000000..95c21b1ba2667b1f801a292c8f0cab55f8d7c5bd --- /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 0000000000000000000000000000000000000000..97f29b40a99b6537b0d0b3cf9b9eab4d6c05798a --- /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 0000000000000000000000000000000000000000..98013784547b5bb52f25f016c8be5a3ee6bbda1f --- /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 0000000000000000000000000000000000000000..ce08926f909204f9410358b527947fc85d02cf0d --- /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 0000000000000000000000000000000000000000..70b5f5dfa2bb3d8bec24225585e795014cea7044 --- /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 0000000000000000000000000000000000000000..a94102f7690ba81ba801db45bcd88a168e533ed9 --- /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 0000000000000000000000000000000000000000..8689a21569fb134300168b8399a1fb6dc5098c1a --- /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 0000000000000000000000000000000000000000..8e4c7b98488f234dabd99277d1519b6afd1d3616 --- /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 da973490d38b1588317784b226b66da85c791a4a..6e9c5481897e094c405a8d6e4dd7de9d863efb51 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 ec761b291a9a620b92e9fa098f78140e14bd2fad..22bd9ecf2b53160dc3a75763b14fdd64fd6f9678 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 0000000000000000000000000000000000000000..96011d9c327bf9e45a25e9f6c3e36249af362280 --- /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 d7f32326751db77a74bc06bc0fdb72040172cff1..d6b18861c5ea6b2e1cbe424fac36e4e8aead62cd 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 1c7ce2ecfa9269bc4232a3e2d6896ffc0b4880a7..22f913df958e7ed482b4647b9ae729ccc613d751 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 a50b82e674021c3c99f77c2d704585226f426fe4..8ffb2d4c685cf345bc9eb4e5ec3a16e21e96b068 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 7c5b66544d832cd530072d686505be1a292c04c8..5a46aca5a28b4e34f639bc82b2576555131dc3b7 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 d8f57ad9598209fe92d7ee224edfef18d8e3374d..3b8f4157bf647ee9721016d93913c7478f4f01c6 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 ac21d6a6f3cb28d423f48cd52a19ffee4c8a070f..e80f03f500c2ec4fcc47c94bdc5ba6dcd211023d 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 ae9be4c04048cf883db0acc0a328bfba4c89c204..b468cf9d563d378d7483f8a5b0aa60adba6dde2e 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 0a491f9aa50d294b9fbc033b1873a5ea18836e6a..50a789f43c755fedd18176c73e8ace5310cba1ec 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 100f47f78b3c633440fae9845ac6146cc9d77326..d39ac79c3b44a7478c7519b35beb1c1c214fa58b 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 0af0b5a8360b3c797114ae550dc8fae128048ae4..b7d99bfe203ceb73c55627dba51e487378b030fa 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 @@