Browse Source

[Feature-8850][E2E] Restore project center e2e test cases in ui-next (#8909)

3.0.0/version-upgrade
xiangzihao 3 years ago committed by GitHub
parent
commit
eefe7896c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      .github/workflows/e2e.yml
  2. 129
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java
  3. 2
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java
  4. 5
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java
  5. 8
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java
  6. 30
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java
  7. 40
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowDefinitionTab.java
  8. 5
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java
  9. 29
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java
  10. 2
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java
  11. 68
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowSaveDialog.java
  12. 10
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/ShellTaskForm.java
  13. 39
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java
  14. 48
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java
  15. 6
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java
  16. 6
      dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/basic/docker-compose.yaml
  17. 2
      dolphinscheduler-ui-next/src/components/form/fields/custom-parameters.ts
  18. 4
      dolphinscheduler-ui-next/src/components/modal/index.tsx
  19. 3
      dolphinscheduler-ui-next/src/views/projects/list/components/project-modal.tsx
  20. 2
      dolphinscheduler-ui-next/src/views/projects/list/index.tsx
  21. 1
      dolphinscheduler-ui-next/src/views/projects/list/use-table.ts
  22. 3
      dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-child-node.ts
  23. 3
      dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-custom-params.ts
  24. 1
      dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-name.ts
  25. 1
      dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-pre-tasks.ts
  26. 2
      dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-canvas.tsx
  27. 5
      dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-save-modal.tsx
  28. 2
      dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-sidebar.tsx
  29. 4
      dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-toolbar.tsx
  30. 3
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/start-modal.tsx
  31. 4
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/table-action.tsx
  32. 3
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.tsx
  33. 1
      dolphinscheduler-ui-next/src/views/projects/workflow/definition/use-table.ts
  34. 2
      dolphinscheduler-ui-next/src/views/projects/workflow/instance/components/table-action.tsx
  35. 2
      dolphinscheduler-ui-next/src/views/projects/workflow/instance/index.tsx
  36. 12
      dolphinscheduler-ui-next/src/views/projects/workflow/instance/use-table.ts

8
.github/workflows/e2e.yml

@ -77,16 +77,16 @@ jobs:
class: org.apache.dolphinscheduler.e2e.cases.UserE2ETest
- name: WorkerGroup
class: org.apache.dolphinscheduler.e2e.cases.WorkerGroupE2ETest
# - name: Project
# class: org.apache.dolphinscheduler.e2e.cases.ProjectE2ETest
- name: Project
class: org.apache.dolphinscheduler.e2e.cases.ProjectE2ETest
- name: Queue
class: org.apache.dolphinscheduler.e2e.cases.QueueE2ETest
- name: Environment
class: org.apache.dolphinscheduler.e2e.cases.EnvironmentE2ETest
- name: Token
class: org.apache.dolphinscheduler.e2e.cases.TokenE2ETest
# - name: Workflow
# class: org.apache.dolphinscheduler.e2e.cases.WorkflowE2ETest
- name: Workflow
class: org.apache.dolphinscheduler.e2e.cases.WorkflowE2ETest
# - name: WorkflowForSwitch
# class: org.apache.dolphinscheduler.e2e.cases.WorkflowSwitchE2ETest
- name: FileManage

129
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases/WorkflowE2ETest.java

@ -32,11 +32,15 @@ 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.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.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
@ -44,46 +48,63 @@ import static org.awaitility.Awaitility.await;
@DolphinScheduler(composeFiles = "docker/basic/docker-compose.yaml")
class WorkflowE2ETest {
private static final String project = "test-workflow-1";
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 tenant = System.getProperty("user.name");
private static RemoteWebDriver browser;
@BeforeAll
public static void setup() {
new LoginPage(browser)
UserPage userPage = new LoginPage(browser)
.login("admin", "dolphinscheduler123")
.goToNav(SecurityPage.class)
.goToTab(TenantPage.class)
.create(tenant)
.goToNav(SecurityPage.class)
.goToTab(UserPage.class);
new WebDriverWait(userPage.driver(), 20).until(ExpectedConditions.visibilityOfElementLocated(
new By.ByClassName("name")));
userPage.update(user, user, password, email, phone, 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)
;
}
// @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 String workflow = "test-workflow-1";
final WorkflowDefinitionTab workflowDefinitionPage =
WorkflowDefinitionTab workflowDefinitionPage =
new ProjectPage(browser)
.goTo(project)
.goToTab(WorkflowDefinitionTab.class);
@ -104,43 +125,47 @@ class WorkflowE2ETest {
.submit()
;
await().untilAsserted(() -> assertThat(
workflowDefinitionPage.workflowList()
).anyMatch(it -> it.getText().contains(workflow)));
await().untilAsserted(() -> assertThat(workflowDefinitionPage.workflowList())
.as("Workflow list should contain newly-created workflow")
.anyMatch(
it -> it.getText().contains(workflow)
));
workflowDefinitionPage.publish(workflow);
}
@Test
@Order(10)
void testCreateSubWorkflow() {
final String workflow = "test-sub-workflow-1";
final WorkflowDefinitionTab workflowDefinitionPage =
new ProjectPage(browser)
.goToNav(ProjectPage.class)
.goTo(project)
.goToTab(WorkflowDefinitionTab.class);
workflowDefinitionPage
.createWorkflow()
.<SubWorkflowTaskForm> 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(10)
// void testCreateSubWorkflow() {
// final String workflow = "test-sub-workflow-1";
//
// WorkflowDefinitionTab workflowDefinitionPage =
// new ProjectPage(browser)
// .goToNav(ProjectPage.class)
// .goTo(project)
// .goToTab(WorkflowDefinitionTab.class);
//
// workflowDefinitionPage
// .createWorkflow()
//
// .<SubWorkflowTaskForm> addTask(TaskType.SUB_PROCESS)
// .childNode("test-workflow-1")
// .name("test-sub-1")
// .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)

2
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java

@ -58,6 +58,8 @@ public final class LoginPage extends NavBarPage {
@SneakyThrows
public NavBarPage login(String username, String password) {
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(buttonSwitchLanguage));
buttonSwitchLanguage().click();
inputUsername().sendKeys(username);

5
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/common/CodeEditor.java

@ -19,6 +19,7 @@
*/
package org.apache.dolphinscheduler.e2e.pages.common;
import org.junit.rules.ExpectedException;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
@ -29,6 +30,8 @@ import org.openqa.selenium.support.FindBys;
import org.openqa.selenium.support.PageFactory;
import lombok.Getter;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
@Getter
public final class CodeEditor {
@ -46,6 +49,8 @@ public final class CodeEditor {
}
public CodeEditor content(String content) {
new WebDriverWait(this.driver, 10).until(ExpectedConditions.elementToBeClickable(editor));
editor.click();
Actions actions = new Actions(this.driver);

8
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectDetailPage.java

@ -32,11 +32,13 @@ import lombok.Getter;
@Getter
public final class ProjectDetailPage extends NavBarPage {
@FindBy(className = "tab-process-definition")
@FindBy(css = ".tab-vertical .n-submenu:nth-of-type(2) .n-menu-item:nth-of-type(2) > .n-menu-item-content")
private WebElement menuProcessDefinition;
@FindBy(className = "tab-process-instance")
@FindBy(css = ".tab-vertical .n-submenu:nth-of-type(2) .n-menu-item:nth-of-type(3) > .n-menu-item-content")
private WebElement menuProcessInstances;
@FindBy(className = "tab-task-instance")
@FindBy(css = ".tab-vertical .n-submenu:nth-of-type(3) .n-menu-item:nth-of-type(2) > .n-menu-item-content")
private WebElement menuTaskInstances;
public ProjectDetailPage(RemoteWebDriver driver) {

30
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/ProjectPage.java

@ -25,6 +25,7 @@ import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage.NavBarItem;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.FindBy;
@ -37,17 +38,17 @@ import lombok.Getter;
@Getter
public final class ProjectPage extends NavBarPage implements NavBarItem {
@FindBy(id = "btnCreateProject")
@FindBy(className = "btn-create-project")
private WebElement buttonCreateProject;
@FindBy(className = "items-project")
@FindBy(className = "items")
private List<WebElement> projectList;
@FindBys({
@FindBy(className = "el-popconfirm"),
@FindBy(className = "el-button--primary"),
@FindBy(className = "n-popconfirm__action"),
@FindBy(className = "n-button--primary-type"),
})
private List<WebElement> buttonConfirm;
private WebElement buttonConfirm;
private final CreateProjectForm createProjectForm;
@ -64,9 +65,6 @@ public final class ProjectPage extends NavBarPage implements NavBarItem {
createProjectForm().inputProjectName().sendKeys(project);
createProjectForm().buttonSubmit().click();
new WebDriverWait(driver(), 10)
.until(ExpectedConditions.textToBePresentInElementLocated(By.className("project-name"), project));
return this;
}
@ -78,12 +76,7 @@ public final class ProjectPage extends NavBarPage implements NavBarItem {
.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();
((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm());
return this;
}
@ -91,7 +84,7 @@ public final class ProjectPage extends NavBarPage implements NavBarItem {
public ProjectDetailPage goTo(String project) {
projectList().stream()
.filter(it -> it.getText().contains(project))
.map(it -> it.findElement(By.className("project-name")))
.map(it -> it.findElement(By.className("project-name")).findElement(new By.ByTagName("button")))
.findFirst()
.orElseThrow(() -> new RuntimeException("Cannot click the project item"))
.click();
@ -105,10 +98,13 @@ public final class ProjectPage extends NavBarPage implements NavBarItem {
PageFactory.initElements(driver, this);
}
@FindBy(id = "inputProjectName")
@FindBys({
@FindBy(className = "input-project-name"),
@FindBy(tagName = "input"),
})
private WebElement inputProjectName;
@FindBy(id = "btnSubmit")
@FindBy(className = "btn-submit")
private WebElement buttonSubmit;
}
}

40
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowDefinitionTab.java

@ -23,6 +23,7 @@ import lombok.Getter;
import org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
import org.apache.dolphinscheduler.e2e.pages.project.ProjectDetailPage;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.FindBy;
@ -34,17 +35,21 @@ import java.util.stream.Collectors;
@Getter
public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDetailPage.Tab {
@FindBy(id = "btnCreateProcess")
@FindBy(className = "btn-create-process")
private WebElement buttonCreateProcess;
@FindBy(className = "select-all")
private WebElement checkBoxSelectAll;
@FindBy(className = "btn-delete-all")
private WebElement buttonDeleteAll;
@FindBys({
@FindBy(className = "el-popconfirm"),
@FindBy(className = "el-button--primary"),
@FindBy(className = "n-popconfirm__action"),
@FindBy(className = "n-button--primary-type"),
})
private List<WebElement> buttonConfirm;
private WebElement buttonConfirm;
@FindBy(className = "items")
private List<WebElement> workflowList;
@ -61,8 +66,8 @@ public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDe
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(it -> it.findElement(By.className("workflow-name")).getAttribute("innerText").equals(workflow))
.flatMap(it -> it.findElements(By.className("btn-publish")).stream())
.filter(WebElement::isDisplayed)
.findFirst()
.orElseThrow(() -> new RuntimeException("Can not find publish button in workflow definition"))
@ -74,8 +79,8 @@ public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDe
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(it -> it.findElement(By.className("workflow-name")).getAttribute("innerText").equals(workflow))
.flatMap(it -> it.findElements(By.className("btn-run")).stream())
.filter(WebElement::isDisplayed)
.findFirst()
.orElseThrow(() -> new RuntimeException("Can not find run button in workflow definition"))
@ -85,17 +90,14 @@ public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDe
}
public WorkflowDefinitionTab cancelPublishAll() {
final Supplier<List<WebElement>> cancelButtons = () ->
workflowList()
List<WebElement> cancelButtons = workflowList()
.stream()
.flatMap(it -> it.findElements(By.className("btn-cancel-publish")).stream())
.flatMap(it -> it.findElements(By.className("btn-publish")).stream())
.filter(WebElement::isDisplayed)
.collect(Collectors.toList());
for (List<WebElement> buttons = cancelButtons.get();
!buttons.isEmpty();
buttons = cancelButtons.get()) {
buttons.forEach(WebElement::click);
for (WebElement cancelButton : cancelButtons) {
cancelButton.click();
driver().navigate().refresh();
}
@ -109,12 +111,8 @@ public final class WorkflowDefinitionTab extends NavBarPage implements ProjectDe
checkBoxSelectAll().click();
buttonDeleteAll().click();
buttonConfirm()
.stream()
.filter(WebElement::isDisplayed)
.findFirst()
.orElseThrow(() -> new RuntimeException("No confirm button is displayed"))
.click();
((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm());
return this;
}

5
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowForm.java

@ -24,6 +24,7 @@ import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.SubWorkflowTa
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.dolphinscheduler.e2e.pages.project.workflow.task.SwitchTaskForm;
import org.openqa.selenium.By;
@ -44,14 +45,14 @@ import org.openqa.selenium.support.ui.WebDriverWait;
@SuppressWarnings("UnstableApiUsage")
@Getter
public final class WorkflowForm {
private final WebDriver driver;
private WebDriver driver;
private final WorkflowSaveDialog saveForm;
private final WorkflowFormatDialog formatDialog;
@FindBy(className = "graph-format")
private WebElement formatBtn;
@FindBy(id = "btnSave")
@FindBy(className = "btn-save")
private WebElement buttonSave;
public WorkflowForm(WebDriver driver) {

29
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowInstanceTab.java

@ -26,6 +26,7 @@ import java.util.List;
import java.util.stream.Collectors;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.FindBy;
@ -33,20 +34,27 @@ import org.openqa.selenium.support.FindBys;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.openqa.selenium.support.pagefactory.ByChained;
@Getter
public final class WorkflowInstanceTab extends NavBarPage implements ProjectDetailPage.Tab {
@FindBy(className = "items-workflow-instances")
private List<WebElement> instanceList;
@FindBy(className = "select-all")
@FindBys({
@FindBy(className = "btn-selected"),
@FindBy(className = "n-checkbox-box"),
})
private WebElement checkBoxSelectAll;
@FindBy(className = "btn-delete-all")
private WebElement buttonDeleteAll;
@FindBys({
@FindBy(className = "el-popconfirm"),
@FindBy(className = "el-button--primary"),
@FindBy(className = "n-popconfirm__action"),
@FindBy(className = "n-button--primary-type"),
})
private List<WebElement> buttonConfirm;
private WebElement buttonConfirm;
public WorkflowInstanceTab(RemoteWebDriver driver) {
super(driver);
@ -66,13 +74,10 @@ public final class WorkflowInstanceTab extends NavBarPage implements ProjectDeta
}
checkBoxSelectAll().click();
buttonDeleteAll().click();
buttonConfirm()
.stream()
.filter(WebElement::isDisplayed)
.findFirst()
.orElseThrow(() -> new RuntimeException("No confirm button is displayed"))
.click();
((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonConfirm());
return this;
}
@ -90,11 +95,11 @@ public final class WorkflowInstanceTab extends NavBarPage implements ProjectDeta
}
public int executionTime() {
return Integer.parseInt(row.findElement(By.className("execution-time")).getText());
return Integer.parseInt(row.findElement(By.className("workflow-run-times")).getText());
}
public Row rerun() {
row.findElements(By.className("btn-rerun"))
row.findElements(new ByChained(By.className("btn-rerun"), By.className("n-button__content")))
.stream()
.filter(WebElement::isDisplayed)
.findFirst()

2
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowRunDialog.java

@ -29,7 +29,7 @@ import lombok.Getter;
public final class WorkflowRunDialog {
private final WorkflowDefinitionTab parent;
@FindBy(id = "btnSubmit")
@FindBy(className = "btn-submit")
private WebElement buttonSubmit;
public WorkflowRunDialog(WorkflowDefinitionTab parent) {

68
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/WorkflowSaveDialog.java

@ -38,23 +38,33 @@ public final class WorkflowSaveDialog {
private final WebDriver driver;
private final WorkflowForm parent;
@FindBy(id = "inputName")
@FindBys({
@FindBy(className = "input-name"),
@FindBy(tagName = "input")
})
private WebElement inputName;
@FindBy(id = "btnSubmit")
@FindBy(className = "btn-submit")
private WebElement buttonSubmit;
@FindBys({
@FindBy(className = "input-param-key"),
@FindBy(tagName = "input"),
@FindBy(className = "input-global-params"),
@FindBy(tagName = "button"),
})
private List<WebElement> inputParamKey;
private WebElement buttonGlobalCustomParameters;
@FindBys({
@FindBy(className = "input-param-val"),
@FindBy(tagName = "input"),
@FindBy(className = "btn-select-tenant-code"),
@FindBy(className = "n-base-selection"),
})
private List<WebElement> inputParamVal;
@FindBy(id = "selectTenant")
private WebElement selectTenant;
@FindBy(className = "n-base-select-option__content")
private List<WebElement> selectTenantOption;
@FindBy(className = "input-global-params")
private WebElement globalParamsItems;
public WorkflowSaveDialog(WorkflowForm parent) {
this.parent = parent;
this.driver = parent.driver();
@ -71,37 +81,33 @@ public final class WorkflowSaveDialog {
public WorkflowSaveDialog tenant(String tenant) {
selectTenant().click();
final By optionsLocator = By.className("option-tenants");
new WebDriverWait(driver, 10)
.until(ExpectedConditions.visibilityOfElementLocated(optionsLocator));
driver().findElements(optionsLocator)
selectTenantOption()
.stream()
.filter(it -> it.getText().contains(tenant))
.filter(it -> it.getAttribute("innerText").contains(tenant))
.findFirst()
.orElseThrow(() -> new RuntimeException("No such tenant: " + tenant))
.click()
;
.orElseThrow(() -> new RuntimeException(String.format("No %s in workflow save dialog tenant dropdown " +
"list", tenant)))
.click();
return this;
}
public WorkflowSaveDialog addGlobalParam(String key, String val) {
assert inputParamKey().size() == inputParamVal().size();
final int len = inputParamKey().size();
public WorkflowSaveDialog addGlobalParam(String key, String value) {
final int len = globalParamsItems().findElements(By.tagName("input")).size();
final WebDriver 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);
if (len == 0) {
buttonGlobalCustomParameters().click();
globalParamsItems().findElements(By.tagName("input")).get(0).sendKeys(key);
globalParamsItems().findElements(By.tagName("input")).get(1).sendKeys(value);
} else {
globalParamsItems().findElements(By.tagName("button")).get(len-1).click();
globalParamsItems().findElements(By.tagName("input")).get(len).sendKeys(key);
globalParamsItems().findElements(By.tagName("input")).get(len+1).sendKeys(value);
}
return this;
}

10
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/ShellTaskForm.java

@ -23,19 +23,25 @@ import org.apache.dolphinscheduler.e2e.pages.common.CodeEditor;
import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm;
import lombok.Getter;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
@Getter
public final class ShellTaskForm extends TaskNodeForm {
private final CodeEditor codeEditor;
private CodeEditor codeEditor;
private WebDriver driver;
public ShellTaskForm(WorkflowForm parent) {
super(parent);
this.codeEditor = new CodeEditor(parent.driver());
this.driver = parent.driver();
}
public ShellTaskForm script(String script) {
codeEditor().content(script);
codeEditor.content(script);
return this;
}

39
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/SubWorkflowTaskForm.java

@ -22,10 +22,49 @@ package org.apache.dolphinscheduler.e2e.pages.project.workflow.task;
import org.apache.dolphinscheduler.e2e.pages.project.workflow.WorkflowForm;
import lombok.Getter;
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.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.util.List;
@Getter
public final class SubWorkflowTaskForm extends TaskNodeForm {
@FindBys({
@FindBy(className = "select-child-node"),
@FindBy(className = "n-base-selection"),
})
private WebElement btnSelectChildNodeDropdown;
@FindBy(className = "n-base-select-option__content")
private List<WebElement> selectChildNode;
private WebDriver driver;
public SubWorkflowTaskForm(WorkflowForm parent) {
super(parent);
this.driver = parent.driver();
}
public SubWorkflowTaskForm childNode(String node) {
btnSelectChildNodeDropdown().click();
new WebDriverWait(driver, 5).until(ExpectedConditions.visibilityOfElementLocated(new By.ByClassName(
"n-base-select-option__content")));
selectChildNode()
.stream()
.filter(it -> it.getText().contains(node))
.findFirst()
.orElseThrow(() -> new RuntimeException(String.format("No %s in child node dropdown list", node)))
.click();
return this;
}
}

48
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/project/workflow/task/TaskNodeForm.java

@ -37,27 +37,42 @@ import java.util.stream.Stream;
@Getter
public abstract class TaskNodeForm {
@FindBy(id = "inputNodeName")
@FindBys({
@FindBy(className = "input-node-name"),
@FindBy(tagName = "input")
})
private WebElement inputNodeName;
@FindBy(id = "btnSubmit")
@FindBy(className = "btn-submit")
private WebElement buttonSubmit;
@FindBys({
@FindBy(className = "input-param-key"),
@FindBy(tagName = "input"),
})
private List<WebElement> inputParamKey;
@FindBys({
@FindBy(className = "input-param-val"),
@FindBy(className = "input-param-value"),
@FindBy(tagName = "input"),
})
private List<WebElement> inputParamVal;
private List<WebElement> inputParamValue;
@FindBys({
@FindBy(className = "pre_tasks-model"),
@FindBy(tagName = "input"),
@FindBy(className = "pre-tasks-model"),
@FindBy(className = "n-base-selection"),
})
private WebElement selectPreTasks;
@FindBys({
@FindBy(className = "btn-custom-parameters"),
@FindBy(tagName = "button"),
})
private WebElement buttonCustomParameters;
@FindBy(className = "btn-create-custom-parameter")
private WebElement buttonCreateCustomParameters;
private final WorkflowForm parent;
TaskNodeForm(WorkflowForm parent) {
@ -74,21 +89,24 @@ public abstract class TaskNodeForm {
return this;
}
public TaskNodeForm addParam(String key, String val) {
assert inputParamKey().size() == inputParamVal().size();
public TaskNodeForm addParam(String key, String value) {
assert inputParamKey().size() == inputParamValue().size();
final int len = inputParamKey().size();
final WebDriver 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();
if (len == 0) {
buttonCustomParameters().click();
inputParamKey().get(0).sendKeys(key);
inputParamValue().get(0).sendKeys(value);
} else {
buttonCreateCustomParameters().click();
inputParamKey().get(len).sendKeys(key);
inputParamVal().get(len).sendKeys(val);
inputParamValue().get(len).sendKeys(value);
}
return this;
}

6
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/resource/FunctionManagePage.java

@ -51,9 +51,9 @@ public class FunctionManagePage extends NavBarPage implements ResourcePage.Tab {
})
private WebElement buttonConfirm;
private final CreateUdfFunctionBox createUdfFunctionBox;
private CreateUdfFunctionBox createUdfFunctionBox;
private final RenameUdfFunctionBox renameUdfFunctionBox;
private RenameUdfFunctionBox renameUdfFunctionBox;
public FunctionManagePage(RemoteWebDriver driver) {
super(driver);
@ -66,7 +66,7 @@ public class FunctionManagePage extends NavBarPage implements ResourcePage.Tab {
public FunctionManagePage createUdfFunction(String udfFunctionName, String className, String udfResourceName, String description) {
buttonCreateUdfFunction().click();
createUdfFunctionBox().radioFunctionType().click();
((JavascriptExecutor) driver).executeScript("arguments[0].click();", createUdfFunctionBox().radioFunctionType());
createUdfFunctionBox().inputFunctionName().sendKeys(udfFunctionName);

6
dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/resources/docker/basic/docker-compose.yaml

@ -23,10 +23,8 @@ services:
environment:
MASTER_MAX_CPU_LOAD_AVG: 100
WORKER_TENANT_AUTO_CREATE: 'true'
# expose:
# - 12345
ports:
- 12345:12345
expose:
- 12345
networks:
- e2e
healthcheck:

2
dolphinscheduler-ui-next/src/components/form/fields/custom-parameters.ts

@ -46,6 +46,7 @@ const CustomParameters = defineComponent({
circle: true,
size: 'small',
type: 'info',
class: 'btn-create-custom-parameter',
disabled,
onClick: onAdd
},
@ -134,6 +135,7 @@ export function renderCustomParameters(
type: 'error',
size: 'small',
disabled,
class: 'btn-delete-custom-parameter',
onClick: () => {
fields[field].splice(i, 1)
rules.splice(i, 1)

4
dolphinscheduler-ui-next/src/components/modal/index.tsx

@ -123,7 +123,7 @@ const Modal = defineComponent({
<NSpace justify='end'>
{this.cancelShow && (
<NButton
class={this.cancelClassName}
class={[this.cancelClassName, 'btn-cancel']}
quaternary
size='small'
onClick={onCancel}
@ -134,7 +134,7 @@ const Modal = defineComponent({
{/* TODO: Add left and right slots later */}
{renderSlot($slots, 'btn-middle')}
<NButton
class={this.confirmClassName}
class={[this.confirmClassName, 'btn-submit']}
type='info'
size='small'
onClick={onConfirm}

3
dolphinscheduler-ui-next/src/views/projects/list/components/project-modal.tsx

@ -101,6 +101,8 @@ const ProjectModal = defineComponent({
onConfirm={this.confirmModal}
onCancel={this.cancelModal}
confirmDisabled={!this.model.projectName || !this.model.userName}
confirmClassName='btn-submit'
cancelClassName='btn-cancel'
confirmLoading={this.saving}
>
<NForm rules={this.rules} ref='projectFormRef'>
@ -108,6 +110,7 @@ const ProjectModal = defineComponent({
<NInput
v-model={[this.model.projectName, 'value']}
placeholder={t('project.list.project_tips')}
class='input-project-name'
/>
</NFormItem>
<NFormItem label={t('project.list.owned_users')} path='userName'>

2
dolphinscheduler-ui-next/src/views/projects/list/index.tsx

@ -100,7 +100,7 @@ const list = defineComponent({
size='small'
onClick={this.handleModalChange}
type='primary'
class='btn-create-tenant'
class='btn-create-project'
>
{t('project.list.create_project')}
</NButton>

1
dolphinscheduler-ui-next/src/views/projects/list/use-table.ts

@ -71,6 +71,7 @@ export function useTable() {
{
title: t('project.list.project_name'),
key: 'name',
className: 'project-name',
render: (row: { code: string; name: any }) =>
h(
NEllipsis,

3
dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-child-node.ts

@ -82,6 +82,7 @@ export function useChildNode({
loading: loading,
'on-update:value': onChange
},
options: options
options: options,
class: 'select-child-node'
}
}

3
dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-custom-params.ts

@ -39,12 +39,14 @@ export function useCustomParams({
type: 'custom-parameters',
field: field,
name: t(`project.node.${name}`),
class: 'btn-custom-parameters',
span,
children: [
{
type: 'input',
field: 'prop',
span: 10,
class: 'input-param-key',
props: {
placeholder: t('project.node.prop_tips'),
maxLength: 256
@ -71,6 +73,7 @@ export function useCustomParams({
type: 'input',
field: 'value',
span: 10,
class: 'input-param-value',
props: {
placeholder: t('project.node.value_tips'),
maxLength: 256

1
dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-name.ts

@ -23,6 +23,7 @@ export function useName(): IJsonItem {
return {
type: 'input',
field: 'name',
class: 'input-node-name',
name: t('project.node.name'),
props: {
placeholder: t('project.node.name_tips'),

1
dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-pre-tasks.ts

@ -57,6 +57,7 @@ export function usePreTasks(
type: 'select',
field: 'preTasks',
span: 24,
class: 'pre-tasks-model',
name: t('project.node.pre_tasks'),
props: {
multiple: true,

2
dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-canvas.tsx

@ -37,7 +37,7 @@ export default defineComponent({
return () => (
<div
ref={container}
class={Styles.canvas}
class={[Styles.canvas, 'dag-container']}
onDrop={(e) => {
context.emit('drop', e)
}}

5
dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-save-modal.tsx

@ -178,18 +178,20 @@ export default defineComponent({
>
<NForm model={formValue.value} rules={rule} ref={formRef}>
<NFormItem label={t('project.dag.workflow_name')} path='name'>
<NInput v-model:value={formValue.value.name} />
<NInput v-model:value={formValue.value.name} class='input-name'/>
</NFormItem>
<NFormItem label={t('project.dag.description')} path='description'>
<NInput
type='textarea'
v-model:value={formValue.value.description}
class='input-description'
/>
</NFormItem>
<NFormItem label={t('project.dag.tenant')} path='tenantCode'>
<NSelect
options={tenantsDropdown.value}
v-model:value={formValue.value.tenantCode}
class='btn-select-tenant-code'
/>
</NFormItem>
<NFormItem label={t('project.dag.timeout_alert')} path='timeoutFlag'>
@ -216,6 +218,7 @@ export default defineComponent({
preset='pair'
key-placeholder={t('project.dag.key')}
value-placeholder={t('project.dag.value')}
class='input-global-params'
/>
</NFormItem>
{props.definition && (

2
dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-sidebar.tsx

@ -35,7 +35,7 @@ export default defineComponent({
<div class={styles.sidebar}>
{allTaskTypes.map((task) => (
<div
class={styles.draggable}
class={[styles.draggable, `task-item-${task.type}`]}
draggable='true'
onDragstart={(e) => {
context.emit('dragStart', e, task.type as TaskType)

4
dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-toolbar.tsx

@ -462,7 +462,7 @@ export default defineComponent({
)}
{/* Save workflow */}
<NButton
class={Styles['toolbar-right-item']}
class={[Styles['toolbar-right-item'], 'btn-save']}
type='info'
secondary
round
@ -473,7 +473,7 @@ export default defineComponent({
{t('project.dag.save')}
</NButton>
{/* Return to previous page */}
<NButton secondary round onClick={onClose}>
<NButton secondary round onClick={onClose} class='btn-close'>
{t('project.dag.close')}
</NButton>
</div>

3
dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/start-modal.tsx

@ -392,12 +392,13 @@ export default defineComponent({
text
type='error'
onClick={() => this.removeStartParams(index)}
class='btn-delete-custom-parameter'
>
<NIcon>
<DeleteOutlined />
</NIcon>
</NButton>
<NButton text type='primary' onClick={this.addStartParams}>
<NButton text type='primary' onClick={this.addStartParams} class='btn-create-custom-parameter'>
<NIcon>
<PlusCircleOutlined />
</NIcon>

4
dolphinscheduler-ui-next/src/views/projects/workflow/definition/components/table-action.tsx

@ -128,6 +128,7 @@ export default defineComponent({
circle
onClick={this.handleEditWorkflow}
disabled={releaseState === 'ONLINE'}
class='btn-edit'
/* TODO: Edit workflow */
>
<NIcon>
@ -148,6 +149,7 @@ export default defineComponent({
circle
onClick={this.handleStartWorkflow}
disabled={releaseState === 'OFFLINE'}
class='btn-run'
>
<NIcon>
<PlayCircleOutlined />
@ -188,6 +190,7 @@ export default defineComponent({
tag='div'
circle
onClick={this.handleReleaseWorkflow}
class='btn-publish'
>
<NIcon>
{releaseState === 'ONLINE' ? (
@ -248,6 +251,7 @@ export default defineComponent({
tag='div'
circle
disabled={releaseState === 'ONLINE'}
class='btn-delete'
>
<NPopconfirm onPositiveClick={this.handleDeleteWorkflow}>
{{

3
dolphinscheduler-ui-next/src/views/projects/workflow/definition/index.tsx

@ -99,7 +99,7 @@ export default defineComponent({
<Card class={styles.card}>
<div class={styles.header}>
<NSpace>
<NButton type='primary' onClick={this.createDefinition}>
<NButton type='primary' onClick={this.createDefinition} class='btn-create-process'>
{t('project.workflow.create_workflow')}
</NButton>
<NButton strong secondary onClick={() => (this.showRef = true)}>
@ -132,6 +132,7 @@ export default defineComponent({
striped
size={'small'}
class={styles.table}
row-class-name='items'
/>
<div class={styles.pagination}>
<NPagination

1
dolphinscheduler-ui-next/src/views/projects/workflow/definition/use-table.ts

@ -65,6 +65,7 @@ export function useTable() {
title: t('project.workflow.workflow_name'),
key: 'name',
width: 200,
className: 'workflow-name',
render: (row) =>
h(
NEllipsis,

2
dolphinscheduler-ui-next/src/views/projects/workflow/instance/components/table-action.tsx

@ -116,6 +116,7 @@ export default defineComponent({
size='small'
type='info'
circle
class='btn-edit'
disabled={
(state !== 'SUCCESS' &&
state !== 'PAUSE' &&
@ -143,6 +144,7 @@ export default defineComponent({
type='info'
circle
onClick={this.handleReRun}
class='btn-rerun'
disabled={
(state !== 'SUCCESS' &&
state !== 'PAUSE' &&

2
dolphinscheduler-ui-next/src/views/projects/workflow/instance/index.tsx

@ -107,6 +107,7 @@ export default defineComponent({
class={styles.table}
scrollX={1800}
v-model:checked-row-keys={this.checkedRowKeys}
row-class-name='items-workflow-instances'
/>
<div class={styles.pagination}>
<NPagination
@ -129,6 +130,7 @@ export default defineComponent({
type='primary'
disabled={this.checkedRowKeys.length <= 0}
style='position: absolute; bottom: 10px; left: 10px;'
class='btn-delete-all'
>
<NPopconfirm onPositiveClick={this.handleBatchDelete}>
{{

12
dolphinscheduler-ui-next/src/views/projects/workflow/instance/use-table.ts

@ -63,7 +63,8 @@ export function useTable() {
const createColumns = (variables: any) => {
variables.columns = [
{
type: 'selection'
type: 'selection',
className: 'btn-selected'
},
{
title: '#',
@ -75,6 +76,7 @@ export function useTable() {
title: t('project.workflow.workflow_name'),
key: 'name',
width: 200,
className: 'workflow-name',
render: (row: IWorkflowInstance) =>
h(
ButtonLink,
@ -92,13 +94,15 @@ export function useTable() {
{
title: t('project.workflow.status'),
key: 'state',
className: 'workflow-status',
render: (_row: IWorkflowInstance) => {
const stateIcon = taskStateIcon[_row.state]
const iconElement = h(
NIcon,
{
size: '18px',
style: 'position: relative; top: 7.5px; left: 7.5px'
style: 'position: relative; top: 7.5px; left: 7.5px',
class: stateIcon.classNames
},
{
default: () =>
@ -134,6 +138,7 @@ export function useTable() {
{
title: t('project.workflow.run_type'),
key: 'commandType',
className: 'workflow-run-type',
render: (_row: IWorkflowInstance) =>
(
_.filter(runningType(t), (v) => v.code === _row.commandType)[0] ||
@ -171,7 +176,8 @@ export function useTable() {
},
{
title: t('project.workflow.run_times'),
key: 'runTimes'
key: 'runTimes',
className: 'workflow-run-times'
},
{
title: t('project.workflow.fault_tolerant_sign'),

Loading…
Cancel
Save