From 269a62418f9b4374d036249f0a133dd377425f2e Mon Sep 17 00:00:00 2001 From: kezhenxu94 Date: Tue, 28 Dec 2021 14:02:06 +0800 Subject: [PATCH] Add E2E case for user manage (#7652) --- .github/workflows/e2e.yml | 2 + .../e2e/cases/TenantE2ETest.java | 10 +- .../e2e/cases/UserE2ETest.java | 139 ++++++++++++++++ .../e2e/pages/security/SecurityPage.java | 8 + .../e2e/pages/security/TenantPage.java | 8 - .../e2e/pages/security/UserPage.java | 148 ++++++++++++++++++ .../e2e/core/DolphinSchedulerExtension.java | 4 +- .../pages/users/_source/createUser.vue | 6 + .../security/pages/users/_source/list.vue | 8 +- .../home/pages/security/pages/users/index.vue | 2 +- .../components/secondaryMenu/_source/menu.js | 3 +- 11 files changed, 321 insertions(+), 17 deletions(-) create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UserE2ETest.java create mode 100644 dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/UserPage.java diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 87828b790f..63df024e94 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -42,6 +42,8 @@ jobs: case: - name: Tenant class: org.apache.dolphinscheduler.e2e.cases.TenantE2ETest + - name: User + class: org.apache.dolphinscheduler.e2e.cases.UserE2ETest - name: Project class: org.apache.dolphinscheduler.e2e.cases.ProjectE2ETest - name: Workflow 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 index 4938a8b514..254a2af719 100644 --- 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 @@ -32,6 +32,7 @@ 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.WebElement; import org.openqa.selenium.remote.RemoteWebDriver; @DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml") @@ -52,7 +53,13 @@ class TenantE2ETest { @Test @Order(10) void testCreateTenant() { - new TenantPage(browser).create(tenant); + final TenantPage page = new TenantPage(browser); + page.create(tenant); + + await().untilAsserted(() -> assertThat(page.tenantList()) + .as("Tenant list should contain newly-created tenant") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(tenant))); } @Test @@ -78,6 +85,7 @@ class TenantE2ETest { await().untilAsserted(() -> { browser.navigate().refresh(); + assertThat( page.tenantList() ).noneMatch( diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UserE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UserE2ETest.java new file mode 100644 index 0000000000..8b43e1bcb7 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UserE2ETest.java @@ -0,0 +1,139 @@ +/* + * 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.apache.dolphinscheduler.e2e.pages.security.UserPage; + +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.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.RemoteWebDriver; + +@DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml") +class UserE2ETest { + private static final String tenant = System.getProperty("user.name"); + private static final String user = "test_user"; + private static final String password = "test_user123"; + private static final String email = "test_user@gmail.com"; + private static final String phone = "15800000000"; + + private static final String editUser = "edit_test_user"; + private static final String editPassword = "edit_test_user123"; + private static final String editEmail = "edit_test_user@gmail.com"; + private static final String editPhone = "15800000001"; + + private static RemoteWebDriver browser; + + @BeforeAll + public static void setup() { + new LoginPage(browser) + .login("admin", "dolphinscheduler123") + .goToNav(SecurityPage.class) + .goToTab(TenantPage.class) + .create(tenant) + .goToNav(SecurityPage.class) + .goToTab(UserPage.class); + } + + @AfterAll + public static void cleanup() { + new SecurityPage(browser) + .goToTab(TenantPage.class) + .delete(tenant) + ; + } + + @Test + @Order(1) + void testCreateUser() { + final UserPage page = new UserPage(browser); + + page.create(user, password, email, phone); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + + assertThat(page.userList()) + .as("User list should contain newly-created user") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(user)); + }); + } + + @Test + @Order(20) + void testCreateDuplicateUser() { + final UserPage page = new UserPage(browser); + + page.create(user, password, email, phone); + + await().untilAsserted(() -> + assertThat(browser.findElement(By.tagName("body")).getText()) + .contains("already exists") + ); + + page.createUserForm().buttonCancel().click(); + } + + @Test + @Order(30) + void testEditUser() { + final UserPage page = new UserPage(browser); + page.update(user, editUser, editPassword, editEmail, editPhone); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + assertThat(page.userList()) + .as("User list should contain newly-modified User") + .extracting(WebElement::getText) + .anyMatch(it -> it.contains(editUser)); + }); + } + + + @Test + @Order(40) + void testDeleteUser() { + final UserPage page = new UserPage(browser); + + page.delete(editUser); + + await().untilAsserted(() -> { + browser.navigate().refresh(); + + assertThat( + page.userList() + ).noneMatch( + it -> it.getText().contains(user) || it.getText().contains(editUser) + ); + }); + } +} 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 index 36f960c41e..920d171b0d 100644 --- 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 @@ -33,6 +33,10 @@ public class SecurityPage extends NavBarPage implements NavBarItem { @FindBy(className = "tab-tenant-manage") private WebElement menuTenantManage; + @FindBy(className = "tab-user-manage") + private WebElement menUserManage; + + public SecurityPage(RemoteWebDriver driver) { super(driver); } @@ -42,6 +46,10 @@ public class SecurityPage extends NavBarPage implements NavBarItem { menuTenantManage().click(); return tab.cast(new TenantPage(driver)); } + if (tab == UserPage.class) { + menUserManage().click(); + return tab.cast(new UserPage(driver)); + } throw new UnsupportedOperationException("Unknown tab: " + tab.getName()); } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java index 6fc70c6b54..eba9cce566 100644 --- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/TenantPage.java @@ -19,9 +19,6 @@ 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; @@ -67,11 +64,6 @@ public final class TenantPage extends NavBarPage implements SecurityPage.Tab { 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; } diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/UserPage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/UserPage.java new file mode 100644 index 0000000000..b602404b80 --- /dev/null +++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/security/UserPage.java @@ -0,0 +1,148 @@ +/* + * 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.pages.security; + +import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage; + +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 lombok.Getter; + +@Getter +public final class UserPage extends NavBarPage implements SecurityPage.Tab { + @FindBy(id = "btnCreateUser") + private WebElement buttonCreateUser; + + @FindBy(className = "items") + private List userList; + + @FindBys({ + @FindBy(className = "el-popconfirm"), + @FindBy(className = "el-button--primary"), + }) + private List buttonConfirm; + + private final UserForm createUserForm = new UserForm(); + private final UserForm editUserForm = new UserForm(); + + + public UserPage(RemoteWebDriver driver) { + super(driver); + } + + public UserPage create(String user, String password, String email, String phone) { + buttonCreateUser().click(); + + createUserForm().inputUserName().sendKeys(user); + createUserForm().inputUserPassword().sendKeys(password); + createUserForm().inputEmail().sendKeys(email); + createUserForm().inputPhone().sendKeys(phone); + createUserForm().buttonSubmit().click(); + + return this; + } + + public UserPage update(String user, String editUser, String editPassword, String editEmail, String editPhone) { + userList() + .stream() + .filter(it -> it.findElement(By.className("name")).getAttribute("innerHTML").contains(user)) + .flatMap(it -> it.findElements(By.className("edit")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No edit button in user list")) + .click(); + + editUserForm().inputUserName().clear(); + editUserForm().inputUserName().sendKeys(editUser); + editUserForm().inputUserPassword().clear(); + editUserForm().inputUserPassword().sendKeys(editPassword); + editUserForm().inputEmail().clear(); + editUserForm().inputEmail().sendKeys(editEmail); + editUserForm().inputPhone().clear(); + editUserForm().inputPhone().sendKeys(editPhone); + editUserForm().buttonSubmit().click(); + + return this; + } + + public UserPage delete(String user) { + userList() + .stream() + .filter(it -> it.findElement(By.className("name")).getAttribute("innerHTML").contains(user)) + .flatMap(it -> it.findElements(By.className("delete")).stream()) + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No delete button in user list")) + .click(); + + buttonConfirm() + .stream() + .filter(WebElement::isDisplayed) + .findFirst() + .orElseThrow(() -> new RuntimeException("No confirm button when deleting")) + .click(); + + return this; + } + + @Getter + public class UserForm { + UserForm() { + PageFactory.initElements(driver, this); + } + + @FindBy(id = "inputUserName") + private WebElement inputUserName; + + @FindBy(id = "inputUserPassword") + private WebElement inputUserPassword; + + @FindBy(id = "selectTenant") + private WebElement selectTenant; + + @FindBy(id = "selectQueue") + private WebElement selectQueue; + + @FindBy(id = "inputEmail") + private WebElement inputEmail; + + @FindBy(id = "inputPhone") + private WebElement inputPhone; + + @FindBy(id = "radioStateEnable") + private WebElement radioStateEnable; + + @FindBy(id = "radioStateDisable") + private WebElement radioStateDisable; + + @FindBy(id = "btnSubmit") + private WebElement buttonSubmit; + + @FindBy(id = "btnCancel") + private WebElement buttonCancel; + } +} 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 d6b18861c5..d43386f3a4 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 @@ -73,8 +73,8 @@ final class DolphinSchedulerExtension @Override @SuppressWarnings("UnstableApiUsage") public void beforeAll(ExtensionContext context) throws IOException { - Awaitility.setDefaultTimeout(Duration.ofSeconds(10)); - Awaitility.setDefaultPollInterval(Duration.ofSeconds(1)); + Awaitility.setDefaultTimeout(Duration.ofSeconds(60)); + Awaitility.setDefaultPollInterval(Duration.ofSeconds(10)); Network network = null; HostAndPort address = null; diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/createUser.vue b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/createUser.vue index 88f69fe97a..8f3adc0a6a 100644 --- a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/createUser.vue +++ b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/createUser.vue @@ -16,6 +16,8 @@ */