You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by ke...@apache.org on 2022/01/27 08:18:13 UTC

[dolphinscheduler] branch dev updated: [E2E] add udf manage test (#8203)

This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new d6690fa  [E2E] add udf manage test (#8203)
d6690fa is described below

commit d6690fa89c6433e88c3d7f6d99ff31fd7abdd7f6
Author: xiangzihao <46...@qq.com>
AuthorDate: Thu Jan 27 16:17:32 2022 +0800

    [E2E] add udf manage test (#8203)
---
 .github/workflows/e2e.yml                          |   2 +
 .../e2e/cases/FileManageE2ETest.java               |  18 +-
 .../e2e/cases/UdfManageE2ETest.java                | 225 +++++++++++++++++++++
 .../e2e/pages/resource/FunctionManagePage.java     |  34 ++++
 .../e2e/pages/resource/ResourcePage.java           |  25 ++-
 .../e2e/pages/resource/UdfManagePage.java          | 194 ++++++++++++++++++
 .../pages/udf/pages/createUdfFolder/index.vue      |   6 +-
 .../pages/udf/pages/function/_source/createUdf.vue |   7 +-
 .../pages/udf/pages/resource/_source/list.vue      |   8 +-
 .../pages/udf/pages/resource/_source/rename.vue    |   2 +
 .../resource/pages/udf/pages/resource/index.vue    |   4 +-
 .../js/module/components/fileUpdate/udfUpdate.vue  |   2 +-
 12 files changed, 504 insertions(+), 23 deletions(-)

diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index e7255ac..f7579ef 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -85,6 +85,8 @@ jobs:
             class: org.apache.dolphinscheduler.e2e.cases.WorkflowE2ETest
           - name: FileManage
             class: org.apache.dolphinscheduler.e2e.cases.FileManageE2ETest
+          - name: UdfManage
+            class: org.apache.dolphinscheduler.e2e.cases.UdfManageE2ETest
           - name: MysqlDataSource
             class: org.apache.dolphinscheduler.e2e.cases.MysqlDataSourceE2ETest
           - name: ClickhouseDataSource
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java
index e9e708c..5815d8c 100644
--- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/FileManageE2ETest.java
@@ -66,7 +66,7 @@ public class FileManageE2ETest {
 
     private static final String phone = "15800000000";
 
-    private static final String testDiretoryName = "test_directory";
+    private static final String testDirectoryName = "test_directory";
 
     private static final String testSubDirectoryName = "test_sub_directory";
 
@@ -116,12 +116,12 @@ public class FileManageE2ETest {
     void testCreateDirectory() {
         final FileManagePage page = new FileManagePage(browser);
 
-        page.createDirectory(testDiretoryName, "test_desc");
+        page.createDirectory(testDirectoryName, "test_desc");
 
         await().untilAsserted(() -> assertThat(page.fileList())
                 .as("File list should contain newly-created file")
                 .extracting(WebElement::getText)
-                .anyMatch(it -> it.contains(testDiretoryName)));
+                .anyMatch(it -> it.contains(testDirectoryName)));
     }
 
     @Test
@@ -129,12 +129,12 @@ public class FileManageE2ETest {
     void testCancelCreateDirectory() {
         final FileManagePage page = new FileManagePage(browser);
 
-        page.cancelCreateDirectory(testDiretoryName, "test_desc");
+        page.cancelCreateDirectory(testDirectoryName, "test_desc");
 
         await().untilAsserted(() -> assertThat(page.fileList())
             .as("File list should contain newly-created file")
             .extracting(WebElement::getText)
-            .anyMatch(it -> it.contains(testDiretoryName)));
+            .anyMatch(it -> it.contains(testDirectoryName)));
     }
 
     @Test
@@ -142,7 +142,7 @@ public class FileManageE2ETest {
     void testCreateDuplicateDirectory() {
         final FileManagePage page = new FileManagePage(browser);
 
-        page.createDirectory(testDiretoryName, "test_desc");
+        page.createDirectory(testDirectoryName, "test_desc");
 
         await().untilAsserted(() -> assertThat(browser.findElement(By.tagName("body")).getText())
                 .contains("resource already exists")
@@ -156,7 +156,7 @@ public class FileManageE2ETest {
     void testCreateSubDirectory() {
         final FileManagePage page = new FileManagePage(browser);
 
-        page.createSubDirectory(testDiretoryName, testSubDirectoryName, "test_desc");
+        page.createSubDirectory(testDirectoryName, testSubDirectoryName, "test_desc");
 
         await().untilAsserted(() -> assertThat(page.fileList())
             .as("File list should contain newly-created file")
@@ -188,7 +188,7 @@ public class FileManageE2ETest {
 
         page.goToNav(ResourcePage.class)
             .goToTab(FileManagePage.class)
-            .delete(testDiretoryName);
+            .delete(testDirectoryName);
 
         await().untilAsserted(() -> {
             browser.navigate().refresh();
@@ -196,7 +196,7 @@ public class FileManageE2ETest {
             assertThat(
                     page.fileList()
             ).noneMatch(
-                    it -> it.getText().contains(testDiretoryName)
+                    it -> it.getText().contains(testDirectoryName)
             );
         });
     }
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UdfManageE2ETest.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UdfManageE2ETest.java
new file mode 100644
index 0000000..1c9a878
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/UdfManageE2ETest.java
@@ -0,0 +1,225 @@
+/*
+ * 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.cases;
+
+import lombok.SneakyThrows;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+
+import org.apache.dolphinscheduler.e2e.core.Constants;
+import org.apache.dolphinscheduler.e2e.core.DolphinScheduler;
+import org.apache.dolphinscheduler.e2e.pages.LoginPage;
+import org.apache.dolphinscheduler.e2e.pages.resource.ResourcePage;
+import org.apache.dolphinscheduler.e2e.pages.resource.UdfManagePage;
+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.WebElement;
+import org.openqa.selenium.remote.RemoteWebDriver;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Comparator;
+import java.util.Objects;
+
+@DolphinScheduler(composeFiles = "docker/file-manage/docker-compose.yaml")
+public class UdfManageE2ETest {
+    private static RemoteWebDriver browser;
+
+    private static final String tenant = System.getProperty("user.name");
+
+    private static final String user = "admin";
+
+    private static final String password = "dolphinscheduler123";
+
+    private static final String email = "admin@gmail.com";
+
+    private static final String phone = "15800000000";
+
+    private static final String testDirectoryName = "test_directory";
+
+    private static final String testRenameDirectoryName = "test_rename_directory";
+
+    private static final String testUploadUdfFileName = "hive-jdbc-3.1.2.jar";
+
+    private static final Path testUploadUdfFilePath = Constants.HOST_TMP_PATH.resolve(testUploadUdfFileName);
+
+    private static final String testUploadUdfRenameFileName = "hive-jdbc.jar";
+
+    @BeforeAll
+    public static void setup() {
+        TenantPage tenantPage = new LoginPage(browser)
+            .login(user, password)
+            .create(tenant);
+
+        await().untilAsserted(() -> assertThat(tenantPage.tenantList())
+            .as("Tenant list should contain newly-created tenant")
+            .extracting(WebElement::getText)
+            .anyMatch(it -> it.contains(tenant)));
+
+        tenantPage.goToNav(SecurityPage.class)
+            .goToTab(UserPage.class)
+            .update(user, user, password, email, phone)
+            .goToNav(ResourcePage.class)
+            .goToTab(UdfManagePage.class);
+    }
+
+    @AfterAll
+    @SneakyThrows
+    public static void cleanup() {
+        Files.walk(Constants.HOST_CHROME_DOWNLOAD_PATH)
+            .sorted(Comparator.reverseOrder())
+            .map(Path::toFile)
+            .forEach(File::delete);
+
+        Files.deleteIfExists(testUploadUdfFilePath);
+    }
+
+    @Test
+    @Order(10)
+    void testCreateDirectory() {
+        final UdfManagePage page = new UdfManagePage(browser);
+
+        browser.navigate().refresh();
+
+        page.createDirectory(testDirectoryName, "test_desc");
+
+        await().untilAsserted(() -> assertThat(page.udfList())
+            .as("File list should contain newly-created file")
+            .extracting(WebElement::getText)
+            .anyMatch(it -> it.contains(testDirectoryName)));
+    }
+
+    @Test
+    @Order(20)
+    void testRenameDirectory() {
+        final UdfManagePage page = new UdfManagePage(browser);
+
+        page.rename(testDirectoryName, testRenameDirectoryName);
+
+        await().untilAsserted(() -> {
+            browser.navigate().refresh();
+
+            assertThat(page.udfList())
+                .as("File list should contain newly-created file")
+                .extracting(WebElement::getText)
+                .anyMatch(it -> it.contains(testRenameDirectoryName));
+        });
+    }
+
+    @Test
+    @Order(30)
+    void testDeleteDirectory() {
+        final UdfManagePage page = new UdfManagePage(browser);
+
+        page.delete(testRenameDirectoryName);
+
+        await().untilAsserted(() -> {
+            browser.navigate().refresh();
+
+            assertThat(
+                page.udfList()
+            ).noneMatch(
+                it -> it.getText().contains(testRenameDirectoryName)
+            );
+        });
+    }
+
+    @Test
+    @Order(40)
+    @SneakyThrows
+    void testUploadUdf() {
+        final UdfManagePage page = new UdfManagePage(browser);
+
+        downloadFile("https://repo1.maven.org/maven2/org/apache/hive/hive-jdbc/3.1.2/hive-jdbc-3.1.2.jar", testUploadUdfFilePath.toFile().getAbsolutePath());
+
+        page.uploadFile(testUploadUdfFilePath.toFile().getAbsolutePath());
+
+        await().untilAsserted(() -> {
+            assertThat(page.udfList())
+                .as("File list should contain newly-created file")
+                .extracting(WebElement::getText)
+                .anyMatch(it -> it.contains(testUploadUdfFileName));
+        });
+    }
+
+    void downloadFile(String downloadUrl, String filePath) throws Exception {
+        int byteRead;
+
+        URL url = new URL(downloadUrl);
+
+        URLConnection conn = url.openConnection();
+        InputStream inStream = conn.getInputStream();
+        FileOutputStream fs = new FileOutputStream(filePath);
+
+        byte[] buffer = new byte[1024];
+        while ((byteRead = inStream.read(buffer)) != -1) {
+            fs.write(buffer, 0, byteRead);
+        }
+
+        inStream.close();
+        fs.close();
+    }
+
+    @Test
+    @Order(60)
+    void testRenameUdf() {
+        final UdfManagePage page = new UdfManagePage(browser);
+
+        page.rename(testUploadUdfFileName, testUploadUdfRenameFileName);
+
+        await().untilAsserted(() -> {
+            assertThat(page.udfList())
+                .as("File list should contain newly-created file")
+                .extracting(WebElement::getText)
+                .anyMatch(it -> it.contains(testUploadUdfRenameFileName));
+        });
+    }
+
+    @Test
+    @Order(70)
+    void testDeleteUdf() {
+        final UdfManagePage page = new UdfManagePage(browser);
+
+        page.delete(testUploadUdfRenameFileName);
+
+        await().untilAsserted(() -> {
+            browser.navigate().refresh();
+
+            assertThat(
+                page.udfList()
+            ).noneMatch(
+                it -> it.getText().contains(testUploadUdfRenameFileName)
+            );
+        });
+    }
+}
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java
new file mode 100644
index 0000000..6934e9e
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java
@@ -0,0 +1,34 @@
+/*
+ * 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.resource;
+
+import lombok.Getter;
+
+import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
+
+import org.openqa.selenium.remote.RemoteWebDriver;
+
+@Getter
+public class FunctionManagePage extends NavBarPage implements ResourcePage.Tab {
+    public FunctionManagePage(RemoteWebDriver driver) {
+        super(driver);
+    }
+}
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java
index 0e9ee74..7fc207b 100644
--- a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/ResourcePage.java
@@ -33,7 +33,13 @@ import org.openqa.selenium.support.ui.WebDriverWait;
 @Getter
 public class ResourcePage extends NavBarPage implements NavBarPage.NavBarItem {
     @FindBy(className = "tab-file-manage")
-    private WebElement fileMagageManage;
+    private WebElement fileManageTab;
+
+    @FindBy(className = "tab-udf-resource-manage")
+    private WebElement udfManageTab;
+
+    @FindBy(className = "tab-function-resource-manage")
+    private WebElement functionManageTab;
 
     public ResourcePage(RemoteWebDriver driver) {
         super(driver);
@@ -41,10 +47,23 @@ public class ResourcePage extends NavBarPage implements NavBarPage.NavBarItem {
 
     public <T extends ResourcePage.Tab> T goToTab(Class<T> tab) {
         if (tab == FileManagePage.class) {
-            WebElement fileMagageManageElement = new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(fileMagageManage));
-            fileMagageManageElement.click();
+            WebElement fileManageTabElement = new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(fileManageTab));
+            fileManageTabElement.click();
             return tab.cast(new FileManagePage(driver));
         }
+
+        if (tab == UdfManagePage.class) {
+            WebElement udfManageTabElement = new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(udfManageTab));
+            udfManageTabElement.click();
+            return tab.cast(new UdfManagePage(driver));
+        }
+
+        if (tab == FunctionManagePage.class) {
+            WebElement functionManageTabElement = new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(functionManageTab));
+            functionManageTabElement.click();
+            return tab.cast(new FunctionManagePage(driver));
+        }
+
         throw new UnsupportedOperationException("Unknown tab: " + tab.getName());
     }
 
diff --git a/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/UdfManagePage.java b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/UdfManagePage.java
new file mode 100644
index 0000000..ae867e1
--- /dev/null
+++ b/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/UdfManagePage.java
@@ -0,0 +1,194 @@
+/*
+ * 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.resource;
+
+import lombok.Getter;
+
+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.LocalFileDetector;
+import org.openqa.selenium.remote.RemoteWebDriver;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.FindBys;
+import org.openqa.selenium.support.PageFactory;
+
+@Getter
+public class UdfManagePage extends NavBarPage implements ResourcePage.Tab {
+    @FindBy(id = "btnCreateDirectory")
+    private WebElement buttonCreateDirectory;
+
+    @FindBy(id = "btnUploadUdf")
+    private WebElement buttonUploadUdf;
+
+    @FindBy(className = "udf-items")
+    private List<WebElement> udfList;
+
+    @FindBys({
+        @FindBy(className = "el-popconfirm"),
+        @FindBy(className = "el-button--primary"),
+    })
+    private List<WebElement> buttonConfirm;
+
+    private final UploadFileBox uploadFileBox;
+
+    private final RenameDirectoryBox renameDirectoryBox;
+
+    private final CreateDirectoryBox createDirectoryBox;
+
+    public UdfManagePage(RemoteWebDriver driver) {
+        super(driver);
+
+        uploadFileBox = new UploadFileBox();
+
+        renameDirectoryBox = new RenameDirectoryBox();
+
+        createDirectoryBox = new CreateDirectoryBox();
+    }
+
+    public UdfManagePage createDirectory(String name, String description) {
+        buttonCreateDirectory().click();
+
+        createDirectoryBox().inputDirectoryName().sendKeys(name);
+        createDirectoryBox().inputDescription().sendKeys(description);
+        createDirectoryBox().buttonSubmit().click();
+
+        return this;
+    }
+
+    public UdfManagePage uploadFile(String filePath) {
+        buttonUploadUdf().click();
+
+        driver.setFileDetector(new LocalFileDetector());
+
+        uploadFileBox().buttonUpload().sendKeys(filePath);
+        uploadFileBox().buttonSubmit().click();
+
+        return this;
+    }
+
+    public UdfManagePage downloadFile(String fileName) {
+        udfList()
+            .stream()
+            .filter(it -> it.getText().contains(fileName))
+            .flatMap(it -> it.findElements(By.id("btnDownload")).stream())
+            .filter(WebElement::isDisplayed)
+            .findFirst()
+            .orElseThrow(() -> new RuntimeException("No download button in udf manage list"))
+            .click();
+
+        return this;
+    }
+
+    public UdfManagePage rename(String currentName, String AfterName) {
+        udfList()
+            .stream()
+            .filter(it -> it.getText().contains(currentName))
+            .flatMap(it -> it.findElements(By.id("btnRename")).stream())
+            .filter(WebElement::isDisplayed)
+            .findFirst()
+            .orElseThrow(() -> new RuntimeException("No rename button in udf manage list"))
+            .click();
+
+        renameDirectoryBox().inputName().clear();
+        renameDirectoryBox().inputName().sendKeys(AfterName);
+        renameDirectoryBox().buttonSubmit().click();
+
+        return this;
+    }
+
+    public UdfManagePage delete(String name) {
+        udfList()
+            .stream()
+            .filter(it -> it.getText().contains(name))
+            .flatMap(it -> it.findElements(By.id("btnDelete")).stream())
+            .filter(WebElement::isDisplayed)
+            .findFirst()
+            .orElseThrow(() -> new RuntimeException("No delete button in udf manage list"))
+            .click();
+
+        buttonConfirm()
+            .stream()
+            .filter(WebElement::isDisplayed)
+            .findFirst()
+            .orElseThrow(() -> new RuntimeException("No confirm button when deleting"))
+            .click();
+
+        return this;
+    }
+
+    @Getter
+    public class RenameDirectoryBox {
+        RenameDirectoryBox() {
+            PageFactory.initElements(driver, this);
+        }
+
+        @FindBy(id = "inputName")
+        private WebElement inputName;
+
+        @FindBy(id = "inputDescription")
+        private WebElement inputDescription;
+
+        @FindBy(id = "btnSubmit")
+        private WebElement buttonSubmit;
+
+        @FindBy(id = "btnCancel")
+        private WebElement buttonCancel;
+    }
+
+    @Getter
+    public class UploadFileBox {
+        UploadFileBox() {
+            PageFactory.initElements(driver, this);
+        }
+
+        @FindBy(id = "btnUpload")
+        private WebElement buttonUpload;
+
+        @FindBy(id = "btnSubmit")
+        private WebElement buttonSubmit;
+
+        @FindBy(id = "btnCancel")
+        private WebElement buttonCancel;
+    }
+
+    @Getter
+    public class CreateDirectoryBox {
+        CreateDirectoryBox() {
+            PageFactory.initElements(driver, this);
+        }
+
+        @FindBy(id = "inputDirectoryName")
+        private WebElement inputDirectoryName;
+
+        @FindBy(id = "inputDescription")
+        private WebElement inputDescription;
+
+        @FindBy(id = "btnSubmit")
+        private WebElement buttonSubmit;
+
+        @FindBy(id = "btnCancel")
+        private WebElement buttonCancel;
+    }
+}
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/createUdfFolder/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/createUdfFolder/index.vue
index c864d65..a6ed93f 100755
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/createUdfFolder/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/createUdfFolder/index.vue
@@ -22,6 +22,7 @@
           <template slot="name"><strong>*</strong>{{$t('Folder Name')}}</template>
           <template slot="content">
             <el-input
+                    id="inputDirectoryName"
                     type="input"
                     v-model="name"
                     maxlength="60"
@@ -35,6 +36,7 @@
           <template slot="name">{{$t('Description')}}</template>
           <template slot="content">
             <el-input
+                    id="inputDescription"
                     type="textarea"
                     v-model="description"
                     style="width: 430px;"
@@ -47,8 +49,8 @@
           <template slot="name">&nbsp;</template>
           <template slot="content">
             <div class="submit">
-              <el-button type="primary" size="mini" round :loading="spinnerLoading" @click="ok()">{{spinnerLoading ? $t('Loading...') : $t('Create')}} </el-button>
-              <el-button type="text" size="mini" @click="() => $router.push({name: 'resource-udf'})"> {{$t('Cancel')}} </el-button>
+              <el-button id="btnSubmit" type="primary" size="mini" round :loading="spinnerLoading" @click="ok()">{{spinnerLoading ? $t('Loading...') : $t('Create')}} </el-button>
+              <el-button id="btnCancel" type="text" size="mini" @click="() => $router.push({name: 'resource-udf'})"> {{$t('Cancel')}} </el-button>
             </div>
           </template>
         </m-list-box-f>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue
index e1d9946..ed4632e 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue
@@ -31,6 +31,7 @@
           <template slot="name"><strong>*</strong>{{$t('UDF Function Name')}}</template>
           <template slot="content">
             <el-input
+                    id="inputFunctionName"
                     type="input"
                     maxlength="40"
                     v-model="funcName"
@@ -43,6 +44,7 @@
           <template slot="name"><strong>*</strong>{{$t('Package Name')}}</template>
           <template slot="content">
             <el-input
+                    id="inputClassName"
                     type="input"
                     maxlength="100"
                     v-model="className"
@@ -54,8 +56,8 @@
         <m-list-box-f>
           <template slot="name"><strong>*</strong>{{$t('UDF Resources')}}</template>
           <template slot="content">
-            <treeselect style="width:535px;float:left;" v-model="resourceId" maxHeight="200" :disable-branch-nodes="true" :options="udfResourceList" :disabled="isUpdate" :normalizer="normalizer" :placeholder="$t('Please select UDF resources directory')">
-              <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+            <treeselect id="btnUdfResourceDropDown" style="width:535px;float:left;" v-model="resourceId" maxHeight="200" :disable-branch-nodes="true" :options="udfResourceList" :disabled="isUpdate" :normalizer="normalizer" :placeholder="$t('Please select UDF resources directory')">
+              <div class="options-udf-resource" slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
             </treeselect>
             <el-button type="primary" size="small" @click="_toggleUpdate" :disabled="upDisabled">{{$t('Upload Resources')}}</el-button>
           </template>
@@ -82,6 +84,7 @@
           <template slot="name">{{$t('Instructions')}}</template>
           <template slot="content">
             <el-input
+                    id="inputDescription"
                     type="textarea"
                     v-model="description"
                     size="small"
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue
index 1d35343..7459e75 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue
@@ -17,7 +17,7 @@
 <template>
   <div class="list-model">
     <div class="table-box">
-      <el-table :data="list" size="mini" style="width: 100%">
+      <el-table :data="list" size="mini" style="width: 100%" row-class-name="udf-items">
         <el-table-column type="index" :label="$t('#')" width="50"></el-table-column>
         <el-table-column :label="$t('UDF Resource Name')" min-width="100">
           <template slot-scope="scope">
@@ -58,10 +58,10 @@
         <el-table-column :label="$t('Operation')" min-width="120">
           <template slot-scope="scope">
             <el-tooltip :content="$t('Rename')" placement="top" :enterable="false">
-              <span><el-button type="primary" size="mini" icon="el-icon-edit" @click="_rename(scope.row,scope.$index)" circle></el-button></span>
+              <span><el-button id="btnRename" type="primary" size="mini" icon="el-icon-edit" @click="_rename(scope.row,scope.$index)" circle></el-button></span>
             </el-tooltip>
             <el-tooltip :content="$t('Download')" placement="top" :enterable="false">
-              <span><el-button type="primary" size="mini" icon="el-icon-download" @click="_downloadFile(scope.row)" :disabled="scope.row.directory? true: false" circle></el-button></span>
+              <span><el-button id="btnDownload" type="primary" size="mini" icon="el-icon-download" @click="_downloadFile(scope.row)" :disabled="scope.row.directory? true: false" circle></el-button></span>
             </el-tooltip>
             <el-tooltip :content="$t('Delete')" placement="top" :enterable="false">
               <el-popconfirm
@@ -72,7 +72,7 @@
                 :title="$t('Delete?')"
                 @onConfirm="_delete(scope.row,scope.row.id)"
               >
-                <el-button type="danger" size="mini" icon="el-icon-delete" circle slot="reference"></el-button>
+                <el-button id="btnDelete" type="danger" size="mini" icon="el-icon-delete" circle slot="reference"></el-button>
               </el-popconfirm>
             </el-tooltip>
           </template>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/rename.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/rename.vue
index f64fc46..5b7fbd1 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/rename.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/rename.vue
@@ -22,6 +22,7 @@
           <template slot="name"><strong>*</strong>{{$t('Name')}}</template>
           <template slot="content">
             <el-input
+                    id="inputName"
                     type="input"
                     v-model="name"
                     maxlength="60"
@@ -34,6 +35,7 @@
           <template slot="name">{{$t('Description')}}</template>
           <template slot="content">
             <el-input
+                    id="inputDescription"
                     type="textarea"
                     v-model="description"
                     size="small"
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue
index 2fa8439..de02c75 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue
@@ -20,8 +20,8 @@
       <m-conditions @on-conditions="_onConditions">
         <template slot="button-group">
           <el-button-group>
-            <el-button size="mini"  @click="() => this.$router.push({name: 'resource-udf-createUdfFolder'})">{{$t('Create folder')}}</el-button>
-            <el-button size="mini"  @click="_uploading">{{$t('Upload UDF Resources')}}</el-button>
+            <el-button id="btnCreateDirectory" size="mini" @click="() => this.$router.push({name: 'resource-udf-createUdfFolder'})">{{$t('Create folder')}}</el-button>
+            <el-button id="btnUploadUdf" size="mini"  @click="_uploading">{{$t('Upload UDF Resources')}}</el-button>
           </el-button-group>
         </template>
       </m-conditions>
diff --git a/dolphinscheduler-ui/src/js/module/components/fileUpdate/udfUpdate.vue b/dolphinscheduler-ui/src/js/module/components/fileUpdate/udfUpdate.vue
index 35d9726..d1761f0 100644
--- a/dolphinscheduler-ui/src/js/module/components/fileUpdate/udfUpdate.vue
+++ b/dolphinscheduler-ui/src/js/module/components/fileUpdate/udfUpdate.vue
@@ -29,7 +29,7 @@
                     :placeholder="$t('Please enter name')">
             </el-input>
             <div class="p1" style="position: absolute;">
-              <input ref="file" name="file" type="file" class="file-update" @change="_onChange" v-if="!progress">
+              <input id="btnUpload" ref="file" name="file" type="file" class="file-update" @change="_onChange" v-if="!progress">
               <el-button type="dashed" size="small" :disabled="progress !== 0">{{$t('Upload')}}<em class="el-icon-upload"></em></el-button>
             </div>
           </div>