# DolphinScheduler End-to-End Test

## Page Object Model

DolphinScheduler End-to-End test respects
the [Page Object Model (POM)](https://www.selenium.dev/documentation/guidelines/page_object_models/) design pattern.
Every page of DolphinScheduler is abstracted into a class for better maintainability.

### Example

The login page is abstracted
as [`LoginPage`](dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java), with the
following fields,

```java
public final class LoginPage {
    @FindBy(id = "inputUsername")
    private WebElement inputUsername;

    @FindBy(id = "inputPassword")
    private WebElement inputPassword;

    @FindBy(id = "btnLogin")
    private WebElement buttonLogin;
}
```

where `inputUsername`, `inputPassword` and `buttonLogin` are the main elements on UI that we are interested in. They are
annotated with `FindBy` so that the test framework knows how to locate the elements on UI. You can locate the elements
by `id`, `className`, `css` selector, `tagName`, or even `xpath`, please refer
to [the JavaDoc](https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/FindBy.html).

**Note:** for better maintainability, it's essential to add some convenient `id` or `class` on UI for the wanted
elements if needed, avoid using too complex `xpath` selector or `css` selector that is not maintainable when UI have
styles changes.

With those fields declared, we should also initialize them with a web driver. Here we pass the web driver into the
constructor and invoke `PageFactory.initElements` to initialize those fields,

```java
public final class LoginPage {
    // ...
    public LoginPage(RemoteWebDriver driver) {
        this.driver = driver;

        PageFactory.initElements(driver, this);
    }
}
```

then, all those UI elements are properly filled in.

## Test Environment Setup

DolphinScheduler End-to-End test uses [testcontainers](https://www.testcontainers.org) to set up the testing
environment, with docker compose.

Typically, every test case needs one or more `docker-compose.yaml` files to set up all needed components, and expose the
DolphinScheduler UI port for testing. You can use `@DolphinScheduler(composeFiles = "")` and pass
the `docker-compose.yaml` files to automatically set up the environment in the test class.

```java

@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml")
class TenantE2ETest {
}
```

You can get the web driver that is ready for testing in the class by adding a field of type `RemoteWebDriver`, which
will be automatically injected via the testing framework.

```java

@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml")
class TenantE2ETest {
    private RemoteWebDriver browser;
}
```

Then the field `browser` can be used in the test methods.

```java

@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml")
class TenantE2ETest {
    private RemoteWebDriver browser;

    @Test
    void testLogin() {
        final LoginPage page = new LoginPage(browser); // <<-- use the browser injected
    }
}
```

## Notes

- For UI tests, it's common that the pages might need some time to load, or the operations might need some time to
  complete, we can use `await().untilAsserted(() -> {})` to wait for the assertions.

## Local development

### Mac M1
Add VM options to the test configuration in IntelliJ IDEA:
```
# In this mode you need to install docker desktop for mac and run it with locally
-Dm1_chip=true
```

### Running locally(without Docker)
```
# In this mode you need to start frontend and backend services locally
-Dlocal=true
```

### Running locally(with Docker)
```
# In this mode you only need to install docker locally
```

- To run the tests locally, you need to have the DolphinScheduler running locally. You should add `dolphinscheduler-e2e/pom.xml` to the maven project
  Since it does not participate in project compilation, it is not in the main project.
- Running run test class `org.apache.dolphinscheduler.e2e.cases.UserE2ETest` in the IDE. After execution, the test video will be saved as mp4 in a local temporary directory. Such as
  `/var/folders/hf/123/T/record-3123/PASSED-[engine:junit-jupiter]/[class:org.apache.dolphinscheduler.e2e.cases.UserE2ETest]-20240606-152333.mp4`
