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

benjobs pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampark.git


The following commit(s) were added to refs/heads/dev by this push:
     new 8d9d41e38 [Feature] Introduce alarm e2e test (#3899)
8d9d41e38 is described below

commit 8d9d41e381830016d859edcb51972d42ed7d18f2
Author: Zhengke Zhou <[email protected]>
AuthorDate: Tue Jul 23 23:02:28 2024 +0800

    [Feature] Introduce alarm e2e test (#3899)
    
    * [Future] Introduce alarm e2e test
    
    * [Feature] implement alarm#edit and improve code style
    
    * [Feature] improve by dynamic form
    
    * [Feature] Multi alert type test
    
    * Improve AlarmTest#create
    
    ---------
    
    Co-authored-by: benjobs <[email protected]>
---
 .github/workflows/e2e.yml                          |   6 +-
 .../org/apache/streampark/e2e/cases/AlarmTest.java | 155 +++++++++++++++++++++
 ...rnalLinkPageTest.java => ExternalLinkTest.java} |   2 +-
 .../streampark/e2e/pages/setting/SettingPage.java  |  11 ++
 .../e2e/pages/setting/alarm/AlarmPage.java         | 135 ++++++++++++++++++
 .../pages/setting/alarm/AlertTypeDetailForm.java   | 102 ++++++++++++++
 .../e2e/pages/setting/alarm/CommonForm.java        |  64 +++++++++
 .../e2e/pages/setting/alarm/DingTalkAlertForm.java |  85 +++++++++++
 .../e2e/pages/setting/alarm/EmailAlertForm.java    |  45 ++++++
 .../e2e/pages/setting/alarm/LarkAlertForm.java     |  69 +++++++++
 .../e2e/pages/setting/alarm/SMSAlertForm.java      |  33 +++++
 .../e2e/pages/setting/alarm/WeChatAlertForm.java   |  45 ++++++
 12 files changed, 749 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index de945a34c..78991717c 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -110,8 +110,10 @@ jobs:
     strategy:
       matrix:
         case:
-          - name: ExternalLinkPageTest
-            class: org.apache.streampark.e2e.cases.ExternalLinkPageTest
+          - name: AlarmTest
+            class: org.apache.streampark.e2e.cases.AlarmTest
+          - name: ExternalLinkTest
+            class: org.apache.streampark.e2e.cases.ExternalLinkTest
           - name: YarnQueueTest
             class: org.apache.streampark.e2e.cases.YarnQueueTest
           - name: TokenManagementTest
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/AlarmTest.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/AlarmTest.java
new file mode 100644
index 000000000..0eeb06b8e
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/AlarmTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.streampark.e2e.cases;
+
+import org.apache.streampark.e2e.core.StreamPark;
+import org.apache.streampark.e2e.pages.LoginPage;
+import org.apache.streampark.e2e.pages.setting.SettingPage;
+import org.apache.streampark.e2e.pages.setting.alarm.AlarmPage;
+import org.apache.streampark.e2e.pages.setting.alarm.AlertTypeDetailForm;
+import org.apache.streampark.e2e.pages.setting.alarm.DingTalkAlertForm;
+import org.apache.streampark.e2e.pages.setting.alarm.EmailAlertForm;
+import org.apache.streampark.e2e.pages.setting.alarm.LarkAlertForm;
+import org.apache.streampark.e2e.pages.setting.alarm.WeChatAlertForm;
+
+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 org.testcontainers.shaded.org.awaitility.Awaitility;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@StreamPark(composeFiles = "docker/basic/docker-compose.yaml")
+public class AlarmTest {
+
+    private static RemoteWebDriver browser;
+
+    private static final String userName = "admin";
+
+    private static final String password = "streampark";
+
+    private static final String teamName = "default";
+
+    private static final String newEmail = "[email protected]";
+
+    private static final String newAlarmName = "new_alarm";
+
+    private static final String editAlarmName = "edit_alarm";
+
+    @BeforeAll
+    public static void setup() {
+        new LoginPage(browser)
+            .login(userName, password, teamName)
+            .goToNav(SettingPage.class)
+            .goToTab(AlarmPage.class);
+    }
+
+    @Test
+    @Order(10)
+    public void testCreateAlarm() {
+        final AlarmPage alarmPage = new AlarmPage(browser);
+
+        final String dingTalkURL = "";
+        final String dingTalkToken = "dingTalkToken";
+        final String dingTalkSecretToken = "dingTalkSecretToken";
+        final String dingTalkReceiveUser = "dingTalkUser";
+
+        final String wechatToken = "wechatToken";
+
+        final String larkToken = "larkToken";
+        final String larkSecretToken = "larkSecretToken";
+
+        AlertTypeDetailForm alertTypeDetailForm = alarmPage.createAlarm();
+        alertTypeDetailForm
+            
.<EmailAlertForm>addAlertType(AlertTypeDetailForm.AlertTypeEnum.EMAIL)
+            .email(newEmail)
+            .alertName(newAlarmName);
+        alertTypeDetailForm
+            
.<DingTalkAlertForm>addAlertType(AlertTypeDetailForm.AlertTypeEnum.DINGTALK)
+            .url(dingTalkURL)
+            .token(dingTalkToken)
+            .secretEnable()
+            .secretToken(dingTalkSecretToken)
+            .effectToAllUsers()
+            .receiveUser(dingTalkReceiveUser);
+        alertTypeDetailForm
+            
.<WeChatAlertForm>addAlertType(AlertTypeDetailForm.AlertTypeEnum.WECHAT)
+            .token(wechatToken);
+        alertTypeDetailForm
+            
.<LarkAlertForm>addAlertType(AlertTypeDetailForm.AlertTypeEnum.LARK)
+            .token(larkToken)
+            .secretEnable()
+            .secretToken(larkSecretToken)
+            .effectToAllUsers()
+            .submit();
+
+        Awaitility.await()
+            .untilAsserted(
+                () -> assertThat(alarmPage.alarmList())
+                    .as("Alarm list should contain newly-created alarm")
+                    .extracting(WebElement::getText)
+                    .anyMatch(it -> it.contains(newAlarmName))
+                    .anyMatch(it -> 
it.contains(AlertTypeDetailForm.AlertTypeEnum.EMAIL.desc()))
+                    .anyMatch(it -> it.contains(newEmail))
+                    .anyMatch(it -> 
it.contains(AlertTypeDetailForm.AlertTypeEnum.DINGTALK.desc()))
+                    .anyMatch(it -> 
it.contains(AlertTypeDetailForm.AlertTypeEnum.WECHAT.desc()))
+                    .anyMatch(it -> 
it.contains(AlertTypeDetailForm.AlertTypeEnum.LARK.desc()))
+                    .anyMatch(it -> it.contains(dingTalkReceiveUser)));
+    }
+
+    @Test
+    @Order(20)
+    public void testEditAlarm() {
+        final AlarmPage alarmPage = new AlarmPage(browser);
+
+        alarmPage.editAlarm(newAlarmName)
+            // this step will cancel E-mail type click status.
+            
.<EmailAlertForm>addAlertType(AlertTypeDetailForm.AlertTypeEnum.EMAIL)
+            .alertName(editAlarmName)
+            .submit();
+
+        Awaitility.await()
+            .untilAsserted(
+                () -> assertThat(alarmPage.alarmList())
+                    .as("Alarm list should contain edited alarm")
+                    .extracting(WebElement::getText)
+                    .anyMatch(it -> it.contains(editAlarmName))
+                    .noneMatch(it -> 
it.contains(AlertTypeDetailForm.AlertTypeEnum.EMAIL.desc()))
+                    .anyMatch(it -> 
it.contains(AlertTypeDetailForm.AlertTypeEnum.DINGTALK.desc()))
+                    .anyMatch(it -> 
it.contains(AlertTypeDetailForm.AlertTypeEnum.WECHAT.desc()))
+                    .anyMatch(it -> 
it.contains(AlertTypeDetailForm.AlertTypeEnum.LARK.desc()))
+                    .noneMatch(it -> it.contains(newEmail)));
+    }
+
+    @Test
+    @Order(30)
+    public void testDeleteAlarm() {
+        final AlarmPage alarmPage = new AlarmPage(browser);
+
+        alarmPage.deleteAlarm(editAlarmName);
+
+        Awaitility.await()
+            .untilAsserted(
+                () -> assertThat(alarmPage.alarmList())
+                    .as(String.format("Alarm list shouldn't contain alarm 
witch named %s", editAlarmName))
+                    .extracting(WebElement::getText)
+                    .noneMatch(it -> it.contains(editAlarmName)));
+    }
+}
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/ExternalLinkPageTest.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/ExternalLinkTest.java
similarity index 99%
rename from 
streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/ExternalLinkPageTest.java
rename to 
streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/ExternalLinkTest.java
index ef28a0683..34a09fd21 100644
--- 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/ExternalLinkPageTest.java
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/cases/ExternalLinkTest.java
@@ -32,7 +32,7 @@ import org.testcontainers.shaded.org.awaitility.Awaitility;
 import static org.assertj.core.api.Assertions.assertThat;
 
 @StreamPark(composeFiles = "docker/basic/docker-compose.yaml")
-public class ExternalLinkPageTest {
+public class ExternalLinkTest {
 
     private static RemoteWebDriver browser;
 
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/SettingPage.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/SettingPage.java
index c3ead14a2..36df07cb7 100644
--- 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/SettingPage.java
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/SettingPage.java
@@ -19,6 +19,7 @@ package org.apache.streampark.e2e.pages.setting;
 
 import org.apache.streampark.e2e.pages.common.Constants;
 import org.apache.streampark.e2e.pages.common.NavBarPage;
+import org.apache.streampark.e2e.pages.setting.alarm.AlarmPage;
 
 import lombok.Getter;
 import org.openqa.selenium.WebElement;
@@ -36,6 +37,9 @@ public class SettingPage extends NavBarPage implements 
NavBarPage.NavBarItem {
     @FindBy(xpath = "//span[contains(@class, 
'streampark-simple-menu-sub-title') and contains(text(), 'External Link')]//..")
     private WebElement menuExternalLinkManagement;
 
+    @FindBy(xpath = "//span[contains(@class, 
'streampark-simple-menu-sub-title') and contains(text(), 'Alarms')]//..")
+    private WebElement menuAlarmManagement;
+
     public SettingPage(RemoteWebDriver driver) {
         super(driver);
     }
@@ -55,6 +59,13 @@ public class SettingPage extends NavBarPage implements 
NavBarPage.NavBarItem {
             return tab.cast(new ExternalLinkPage(driver));
         }
 
+        if (tab == AlarmPage.class) {
+            new WebDriverWait(driver, 
Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+                
.until(ExpectedConditions.elementToBeClickable(menuAlarmManagement));
+            menuAlarmManagement.click();
+            return tab.cast(new AlarmPage(driver));
+        }
+
         throw new UnsupportedOperationException("Unknown tab: " + 
tab.getName());
     }
 
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/AlarmPage.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/AlarmPage.java
new file mode 100644
index 000000000..6d24f79c7
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/AlarmPage.java
@@ -0,0 +1,135 @@
+/*
+ * 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.streampark.e2e.pages.setting.alarm;
+
+import org.apache.streampark.e2e.pages.common.Constants;
+import org.apache.streampark.e2e.pages.common.NavBarPage;
+import org.apache.streampark.e2e.pages.setting.SettingPage;
+
+import lombok.Getter;
+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.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.util.List;
+
+@Getter
+public class AlarmPage extends NavBarPage implements SettingPage.Tab {
+
+    @FindBy(xpath = "//span[contains(., 'Alarms 
Setting')]/..//button[contains(@class, 'ant-btn-dashed')]/span[contains(text(), 
'Add New')]")
+    private WebElement buttonCreateAlarm;
+
+    @FindBy(xpath = "//div[@class='ant-row']")
+    private List<WebElement> alarmList;
+
+    @FindBy(className = "ant-form-item-explain-error")
+    private List<WebElement> errorMessageList;
+
+    @FindBy(xpath = "//button[contains(text(), 'Submit')]")
+    private WebElement errorMessageConfirmButton;
+
+    @FindBy(xpath = "//button[contains(@class, 'ant-btn')]/span[contains(., 
'Yes')]")
+    private WebElement deleteConfirmButton;
+
+    public AlarmPage(RemoteWebDriver driver) {
+        super(driver);
+    }
+
+    public AlertTypeDetailForm createAlarm() {
+        waitForPageLoading();
+
+        new WebDriverWait(driver, Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+            .until(ExpectedConditions.elementToBeClickable(buttonCreateAlarm));
+        buttonCreateAlarm.click();
+
+        return new AlertTypeDetailForm(driver);
+    }
+
+    public AlertTypeDetailForm editAlarm(String alarmName) {
+        waitForPageLoading();
+
+        alarmList().stream()
+            // Filter out cards containing a specific alertName.
+            .filter(card -> {
+                WebElement titleElement = new WebDriverWait(driver, 
Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+                    .until(ExpectedConditions.visibilityOf(card
+                        
.findElement(By.xpath(".//div[@class='ant-card-head']//div[@class='ant-card-head-title']"))));
+                return titleElement.getText().contains(alarmName);
+            })
+            // Find the eligible cards and click the edit button.
+            .flatMap(card -> {
+                List<WebElement> editButtons = card.findElements(By.xpath(
+                    ".//button[.//span[contains(@class, 'anticon') and 
contains(@class, 'anticon-edit')]]"));
+
+                // Make sure the button is loaded.
+                new WebDriverWait(driver, 
Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+                    
.until(ExpectedConditions.visibilityOfAllElements(editButtons));
+
+                return editButtons.stream();
+            })
+            .filter(WebElement::isDisplayed)
+            .findFirst()
+            .orElseThrow(() -> new RuntimeException("No edit button found for 
alarm: " + alarmName))
+            .click();
+
+        return new AlertTypeDetailForm(driver);
+    }
+
+    public AlarmPage deleteAlarm(String alarmName) {
+        waitForPageLoading();
+
+        alarmList().stream()
+            // Filter out cards containing a specific alertName.
+            .filter(card -> {
+                WebElement titleElement = new WebDriverWait(driver, 
Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+                    .until(ExpectedConditions.visibilityOf(card
+                        
.findElement(By.xpath(".//div[@class='ant-card-head']//div[@class='ant-card-head-title']"))));
+                return titleElement.getText().contains(alarmName);
+            })
+            // Find the eligible cards and click the delete button.
+            .flatMap(card -> {
+                List<WebElement> deleteButtons = card.findElements(By.xpath(
+                    ".//button[.//span[contains(@class, 'anticon') and 
contains(@class, 'anticon-delete')]]"));
+
+                // Make sure the button is loaded.
+                new WebDriverWait(driver, 
Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+                    
.until(ExpectedConditions.visibilityOfAllElements(deleteButtons));
+
+                return deleteButtons.stream();
+            })
+            .filter(WebElement::isDisplayed)
+            .findFirst()
+            .orElseThrow(() -> new RuntimeException("No delete button found 
for alarm: " + alarmName))
+            .click();
+
+        new WebDriverWait(driver, Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+            
.until(ExpectedConditions.elementToBeClickable(deleteConfirmButton));
+
+        deleteConfirmButton.click();
+
+        return this;
+    }
+    private void waitForPageLoading() {
+        new WebDriverWait(driver, Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+            .until(ExpectedConditions.urlContains("/setting/alarm"));
+    }
+
+}
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/AlertTypeDetailForm.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/AlertTypeDetailForm.java
new file mode 100644
index 000000000..c5081eaf5
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/AlertTypeDetailForm.java
@@ -0,0 +1,102 @@
+/*
+ * 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.streampark.e2e.pages.setting.alarm;
+
+import org.apache.streampark.e2e.pages.common.Constants;
+
+import lombok.Getter;
+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.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.util.List;
+
+@Getter
+public class AlertTypeDetailForm {
+
+    private WebDriver driver;
+
+    @FindBys({
+            @FindBy(xpath = "//div[contains(@class, 'ant-select-selector')]"),
+            @FindBy(xpath = ".//input[@id='form_item_alertType']")
+    })
+    private WebElement btnAlertTypeDropdown;
+
+    @FindBy(xpath = 
"//*[@id='form_item_alertType']//following::div[@class='ant-select-item-option-content']")
+    private List<WebElement> selectAlertType;
+
+    public AlertTypeDetailForm(WebDriver driver) {
+        PageFactory.initElements(driver, this);
+        this.driver = driver;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T addAlertType(AlertTypeEnum alertTypeEnum) {
+        btnAlertTypeDropdown.click();
+        switch (alertTypeEnum) {
+            case EMAIL:
+                selectByAlertType(alertTypeEnum.desc());
+                return (T) new EmailAlertForm(this);
+            case DINGTALK:
+                selectByAlertType(alertTypeEnum.desc());
+                return (T) new DingTalkAlertForm(this);
+            case WECHAT:
+                selectByAlertType(alertTypeEnum.desc());
+                return (T) new WeChatAlertForm(this);
+            case SMS:
+                // ignore.
+            case LARK:
+                selectByAlertType(alertTypeEnum.desc());
+                return (T) new LarkAlertForm(this);
+            default:
+                throw new UnsupportedOperationException(
+                    String.format("Unsupported alert type %s", 
alertTypeEnum.desc()));
+        }
+    }
+
+    private void selectByAlertType(String alertType) {
+        new WebDriverWait(driver, Constants.DEFAULT_WEBDRIVER_WAIT_DURATION)
+            
.until(ExpectedConditions.visibilityOfAllElements(selectAlertType()));
+        selectAlertType.stream()
+            .filter(e -> e.getText().equals(alertType))
+            .findFirst()
+            .orElseThrow(
+                () -> new RuntimeException(
+                    String.format("No %s in alertType dropdown list", 
alertType)))
+            .click();
+    }
+
+    @Getter
+    public enum AlertTypeEnum {
+
+        EMAIL("E-mail"),
+        DINGTALK("Ding Talk"),
+        WECHAT("WeChat"),
+        LARK("Lark"),
+        SMS("SMS");
+        private final String desc;
+
+        AlertTypeEnum(String desc) {
+            this.desc = desc;
+        }
+    }
+}
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/CommonForm.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/CommonForm.java
new file mode 100644
index 000000000..5ca605f12
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/CommonForm.java
@@ -0,0 +1,64 @@
+/*
+ * 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.streampark.e2e.pages.setting.alarm;
+
+import lombok.Getter;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+import org.openqa.selenium.support.PageFactory;
+
+import static 
org.apache.streampark.e2e.pages.common.CommonFactory.WebElementDeleteAndInput;
+
+@Getter
+public abstract class CommonForm {
+
+    private WebDriver driver;
+
+    @FindBy(id = "form_item_alertName")
+    private WebElement inputAlertName;
+
+    @FindBy(xpath = "//button[contains(@class, 
'ant-btn')]//span[contains(text(), 'Submit')]")
+    private WebElement buttonSubmit;
+
+    @FindBy(xpath = "//button[contains(@class, 
'ant-btn')]//span[contains(text(), 'Cancel')]")
+    private WebElement buttonCancel;
+
+    private final AlertTypeDetailForm parent;
+
+    CommonForm(AlertTypeDetailForm alertTypeDetailForm) {
+        final WebDriver driver = alertTypeDetailForm.driver();
+        PageFactory.initElements(driver, this);
+        this.parent = alertTypeDetailForm;
+    }
+
+    public CommonForm alertName(String alertName) {
+        WebElementDeleteAndInput(inputAlertName, alertName);
+        return this;
+    }
+
+    public AlertTypeDetailForm submit() {
+        buttonSubmit.click();
+        return parent;
+    }
+
+    public AlertTypeDetailForm cancel() {
+        buttonCancel.click();
+        return parent;
+    }
+}
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/DingTalkAlertForm.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/DingTalkAlertForm.java
new file mode 100644
index 000000000..42b5e4a1f
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/DingTalkAlertForm.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.streampark.e2e.pages.setting.alarm;
+
+import lombok.Getter;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import static 
org.apache.streampark.e2e.pages.common.CommonFactory.WebElementDeleteAndInput;
+
+@Getter
+public class DingTalkAlertForm extends CommonForm {
+
+    private WebDriver driver;
+
+    @FindBy(id = "form_item_alertDingURL")
+    private WebElement inputDingTalkURL;
+
+    @FindBy(id = "form_item_dingtalkToken")
+    private WebElement inputDingTalkToken;
+
+    @FindBy(id = "form_item_dingtalkSecretEnable")
+    private WebElement btnDingTalkSecret;
+
+    @FindBy(id = "form_item_dingtalkSecretToken")
+    private WebElement inputDingTalkSecretToken;
+
+    @FindBy(id = "form_item_alertDingUser")
+    private WebElement inputDingTalkReceiveUser;
+
+    @FindBy(id = "form_item_dingtalkIsAtAll")
+    private WebElement btnDingTalkEffectToAllUsers;
+
+    public DingTalkAlertForm(AlertTypeDetailForm alertTypeDetailForm) {
+        super(alertTypeDetailForm);
+
+        this.driver = alertTypeDetailForm.driver();
+    }
+
+    public DingTalkAlertForm url(String url) {
+        WebElementDeleteAndInput(inputDingTalkURL, url);
+        return this;
+    }
+
+    public DingTalkAlertForm token(String token) {
+        WebElementDeleteAndInput(inputDingTalkToken, token);
+        return this;
+    }
+
+    public DingTalkAlertForm secretToken(String secretToken) {
+        WebElementDeleteAndInput(inputDingTalkSecretToken, secretToken);
+        return this;
+    }
+
+    public DingTalkAlertForm receiveUser(String receiveUser) {
+        WebElementDeleteAndInput(inputDingTalkReceiveUser, receiveUser);
+        return this;
+    }
+
+    public DingTalkAlertForm effectToAllUsers() {
+        btnDingTalkEffectToAllUsers.click();
+        return this;
+    }
+
+    public DingTalkAlertForm secretEnable() {
+        btnDingTalkSecret.click();
+        return this;
+    }
+}
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/EmailAlertForm.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/EmailAlertForm.java
new file mode 100644
index 000000000..3e8b5232f
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/EmailAlertForm.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.streampark.e2e.pages.setting.alarm;
+
+import lombok.Getter;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import static 
org.apache.streampark.e2e.pages.common.CommonFactory.WebElementDeleteAndInput;
+
+@Getter
+public class EmailAlertForm extends CommonForm {
+
+    private WebDriver driver;
+
+    @FindBy(id = "form_item_alertEmail")
+    private WebElement inputEmail;
+
+    public EmailAlertForm(AlertTypeDetailForm alertTypeDetailForm) {
+        super(alertTypeDetailForm);
+
+        this.driver = alertTypeDetailForm.driver();
+    }
+
+    public EmailAlertForm email(String email) {
+        WebElementDeleteAndInput(inputEmail, email);
+        return this;
+    }
+}
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/LarkAlertForm.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/LarkAlertForm.java
new file mode 100644
index 000000000..b100a5a1c
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/LarkAlertForm.java
@@ -0,0 +1,69 @@
+/*
+ * 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.streampark.e2e.pages.setting.alarm;
+
+import lombok.Getter;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import static 
org.apache.streampark.e2e.pages.common.CommonFactory.WebElementDeleteAndInput;
+
+@Getter
+public class LarkAlertForm extends CommonForm {
+
+    private WebDriver driver;
+
+    @FindBy(id = "form_item_larkToken")
+    private WebElement inputLarkToken;
+
+    @FindBy(id = "form_item_larkSecretToken")
+    private WebElement inputLarkSecretToken;
+
+    @FindBy(id = "form_item_larkSecretEnable")
+    private WebElement btnLarkSecret;
+
+    @FindBy(id = "form_item_larkIsAtAll")
+    private WebElement btnLarkEffectToAllUsers;
+
+    public LarkAlertForm(AlertTypeDetailForm alertTypeDetailForm) {
+        super(alertTypeDetailForm);
+
+        this.driver = alertTypeDetailForm.driver();
+    }
+
+    public LarkAlertForm token(String token) {
+        WebElementDeleteAndInput(inputLarkToken, token);
+        return this;
+    }
+
+    public LarkAlertForm secretToken(String secretToken) {
+        WebElementDeleteAndInput(inputLarkSecretToken, secretToken);
+        return this;
+    }
+
+    public LarkAlertForm secretEnable() {
+        btnLarkSecret.click();
+        return this;
+    }
+
+    public LarkAlertForm effectToAllUsers() {
+        btnLarkEffectToAllUsers.click();
+        return this;
+    }
+}
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/SMSAlertForm.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/SMSAlertForm.java
new file mode 100644
index 000000000..d83a34537
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/SMSAlertForm.java
@@ -0,0 +1,33 @@
+/*
+ * 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.streampark.e2e.pages.setting.alarm;
+
+import lombok.Getter;
+import org.openqa.selenium.WebDriver;
+
+@Getter
+public class SMSAlertForm extends CommonForm {
+
+    private WebDriver driver;
+
+    public SMSAlertForm(AlertTypeDetailForm alertTypeDetailForm) {
+        super(alertTypeDetailForm);
+
+        this.driver = alertTypeDetailForm.driver();
+    }
+}
diff --git 
a/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/WeChatAlertForm.java
 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/WeChatAlertForm.java
new file mode 100644
index 000000000..c93dd80eb
--- /dev/null
+++ 
b/streampark-e2e/streampark-e2e-case/src/test/java/org/apache/streampark/e2e/pages/setting/alarm/WeChatAlertForm.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.streampark.e2e.pages.setting.alarm;
+
+import lombok.Getter;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import static 
org.apache.streampark.e2e.pages.common.CommonFactory.WebElementDeleteAndInput;
+
+@Getter
+public class WeChatAlertForm extends CommonForm {
+
+    private WebDriver driver;
+
+    @FindBy(id = "form_item_weToken")
+    private WebElement inputWeChatToken;
+
+    public WeChatAlertForm(AlertTypeDetailForm alertTypeDetailForm) {
+        super(alertTypeDetailForm);
+
+        this.driver = alertTypeDetailForm.driver();
+    }
+
+    public WeChatAlertForm token(String token) {
+        WebElementDeleteAndInput(inputWeChatToken, token);
+        return this;
+    }
+}


Reply via email to