You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by "vatsrahul1001 (via GitHub)" <gi...@apache.org> on 2025/11/21 07:07:12 UTC

[PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

vatsrahul1001 opened a new pull request, #58548:
URL: https://github.com/apache/airflow/pull/58548

   Adds UI end-to-end testing framework using Playwright, integrated with Breeze.
   
   
   - New `breeze testing ui-e2e-tests` command for UI automation tests
   - Page Object Model structure for maintainable tests
   - Initial test: DAG trigger workflow with verification
   
   
   ```bash
   breeze testing ui-e2e-tests --test-pattern "dag-trigger.spec.ts" --headed
   ```
   
   
   <!-- Please keep an empty line above the dashes. -->
   ---
   **^ Add meaningful description above**
   Read the **[Pull Request Guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#pull-request-guidelines)** for more information.
   In case of fundamental code changes, an Airflow Improvement Proposal ([AIP](https://cwiki.apache.org/confluence/display/AIRFLOW/Airflow+Improvement+Proposals)) is needed.
   In case of a new dependency, check compliance with the [ASF 3rd Party License Policy](https://www.apache.org/legal/resolved.html#category-x).
   In case of backwards incompatible changes please leave a note in a newsfragment file, named `{pr_number}.significant.rst` or `{issue_number}.significant.rst`, in [airflow-core/newsfragments](https://github.com/apache/airflow/tree/main/airflow-core/newsfragments).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "vatsrahul1001 (via GitHub)" <gi...@apache.org>.
vatsrahul1001 commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2571470973


##########
dev/breeze/src/airflow_breeze/commands/common_options.py:
##########
@@ -565,3 +565,110 @@ def _normalize_platform(ctx: click.core.Context, param: click.core.Option, value
     callback=_normalize_platform,
     type=BetterChoice(SINGLE_PLATFORMS),
 )
+
+
+# UI E2E Testing Options
+
+option_airflow_ui_base_url = click.option(
+    "--airflow-ui-base-url",
+    help="Base URL for Airflow UI during e2e tests",
+    default="http://localhost:28080",
+    show_default=True,
+    envvar="AIRFLOW_UI_BASE_URL",
+)
+
+option_browser = click.option(
+    "--browser",
+    help="Browser to use for e2e tests",
+    type=BetterChoice(["chromium", "firefox", "webkit", "all"]),
+    default="chromium",
+    show_default=True,
+)

Review Comment:
   Done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "pierrejeambrun (via GitHub)" <gi...@apache.org>.
pierrejeambrun commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2571423336


##########
dev/breeze/src/airflow_breeze/commands/common_options.py:
##########
@@ -565,3 +565,110 @@ def _normalize_platform(ctx: click.core.Context, param: click.core.Option, value
     callback=_normalize_platform,
     type=BetterChoice(SINGLE_PLATFORMS),
 )
+
+
+# UI E2E Testing Options
+
+option_airflow_ui_base_url = click.option(
+    "--airflow-ui-base-url",
+    help="Base URL for Airflow UI during e2e tests",
+    default="http://localhost:28080",
+    show_default=True,
+    envvar="AIRFLOW_UI_BASE_URL",
+)
+
+option_browser = click.option(
+    "--browser",
+    help="Browser to use for e2e tests",
+    type=BetterChoice(["chromium", "firefox", "webkit", "all"]),
+    default="chromium",
+    show_default=True,
+)

Review Comment:
   By default, it should run accross all 3 browsers I think. Not just chormium.



##########
airflow-core/src/airflow/ui/tests/e2e/pages/DagsPage.ts:
##########
@@ -0,0 +1,184 @@
+/*!
+ * 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.
+ */
+import type { Locator, Page } from "@playwright/test";
+import { BasePage } from "tests/e2e/pages/BasePage";
+
+/**
+ * DAGs Page Object
+ */
+export class DagsPage extends BasePage {
+  // Page URLs
+  public static get dagsListUrl(): string {
+    return "/dags";
+  }
+
+  // Core page elements
+  public readonly confirmButton: Locator;
+  public readonly dagsTable: Locator;
+  public readonly stateElement: Locator;
+  public readonly triggerButton: Locator;
+
+  public constructor(page: Page) {
+    super(page);
+    this.dagsTable = page.locator('div:has(a[href*="/dags/"])');
+    this.triggerButton = page.locator('button[aria-label="Trigger Dag"]:has-text("Trigger")');
+    this.confirmButton = page.locator('button:has-text("Trigger")').nth(1);
+    this.stateElement = page.locator('*:has-text("State") + *').first();
+  }
+
+  // URL builders for dynamic paths
+  public static getDagDetailUrl(dagName: string): string {
+    return `/dags/${dagName}`;
+  }
+
+  public static getDagRunDetailsUrl(dagName: string, dagRunId: string): string {
+    return `/dags/${dagName}/runs/${dagRunId}/details`;
+  }
+
+  /**
+   * Navigate to DAGs list page
+   */
+  public async navigate(): Promise<void> {
+    await this.navigateTo(DagsPage.dagsListUrl);
+  }
+
+  /**
+   * Navigate to DAG detail page
+   */
+  public async navigateToDagDetail(dagName: string): Promise<void> {
+    await this.navigateTo(DagsPage.getDagDetailUrl(dagName));
+  }
+
+  /**
+   * Trigger a DAG run
+   */
+  public async triggerDag(dagName: string): Promise<string | null> {
+    await this.navigateToDagDetail(dagName);
+    await this.triggerButton.waitFor({ state: "visible", timeout: 10_000 });
+    await this.triggerButton.click();
+    const dagRunId = await this.handleTriggerDialog();
+
+    return dagRunId;
+  }
+
+  public async verifyDagRunStatus(dagName: string, dagRunId: string | null): Promise<void> {
+    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+    if (dagRunId === null || dagRunId === undefined || dagRunId === "") {
+      return;
+    }
+
+    await this.page.goto(DagsPage.getDagRunDetailsUrl(dagName, dagRunId), {
+      timeout: 15_000,
+      waitUntil: "domcontentloaded",
+    });
+
+    await this.page.waitForTimeout(2000);
+
+    const maxWaitTime = 5 * 60 * 1000;
+    const checkInterval = 10_000;
+    const startTime = Date.now();
+
+    while (Date.now() - startTime < maxWaitTime) {
+      const currentStatus = await this.getCurrentDagRunStatus();
+
+      if (currentStatus === "success") {
+        return;
+      } else if (currentStatus === "failed") {
+        throw new Error(`DAG run failed: ${dagRunId}`);
+      }
+
+      await this.page.waitForTimeout(checkInterval);
+
+      await this.page.reload({ waitUntil: "domcontentloaded" });
+
+      await this.page.waitForTimeout(2000);
+    }
+
+    throw new Error(`DAG run did not complete within 5 minutes: ${dagRunId}`);
+  }
+
+  private async getCurrentDagRunStatus(): Promise<string> {
+    try {
+      const statusText = await this.stateElement.textContent().catch(() => "");
+      const status = statusText?.trim() ?? "";
+
+      switch (status) {
+        case "Failed":
+          return "failed";
+        case "Queued":
+          return "queued";
+        case "Running":
+          return "running";
+        case "Success":
+          return "success";
+        default:
+          return "unknown";
+      }
+    } catch {
+      return "unknown";
+    }
+  }
+
+  private async handleTriggerDialog(): Promise<string | null> {
+    await this.page.waitForTimeout(1000);
+
+    const responsePromise = this.page
+
+      .waitForResponse(
+        (response) => {
+          const url = response.url();
+
+          const method = response.request().method();
+
+          return (
+            method === "POST" && Boolean(url.includes("dagRuns")) && Boolean(!url.includes("hitlDetails"))
+          );
+        },
+        { timeout: 10_000 },
+      )
+
+      .catch(() => undefined);
+
+    await this.confirmButton.waitFor({ state: "visible", timeout: 8000 });
+
+    await this.page.waitForTimeout(2000);
+    await this.confirmButton.click({ force: true });
+
+    const apiResponse = await responsePromise;
+
+    if (apiResponse) {
+      try {
+        const responseBody = await apiResponse.text();
+        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+        const responseJson = JSON.parse(responseBody);
+
+        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+        if (Boolean(responseJson.dag_run_id)) {
+          // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
+          return responseJson.dag_run_id;
+        }
+      } catch {

Review Comment:
   Here I think we can use the `DagRunResponse` object for typing. 
   
   This will help remove all those unsafe assignment.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "vatsrahul1001 (via GitHub)" <gi...@apache.org>.
vatsrahul1001 commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2570577060


##########
airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts:
##########
@@ -0,0 +1,60 @@
+/*!
+ * 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.
+ */
+import { test } from "@playwright/test";
+
+import { testConfig } from "../../../playwright.config.ts";
+import { DagsPage } from "../pages/DagsPage.ts";
+import { LoginPage } from "../pages/LoginPage.ts";
+
+/**
+ * DAG Trigger E2E Tests
+ */
+
+test.describe("DAG Trigger Workflow", () => {
+  let loginPage: LoginPage;
+  let dagsPage: DagsPage;
+
+  // Test configuration from centralized config
+
+  const testCredentials = testConfig.credentials;
+
+  const testDagId = testConfig.testDag.id;
+
+  // eslint-disable-next-line @typescript-eslint/require-await
+  test.beforeEach(async ({ page }) => {
+    loginPage = new LoginPage(page);
+
+    dagsPage = new DagsPage(page);
+  });
+
+  test("should successfully trigger a DAG run", async () => {
+    test.setTimeout(7 * 60 * 1000);
+
+    await loginPage.navigateAndLogin(testCredentials.username, testCredentials.password);
+
+    await loginPage.expectLoginSuccess();
+
+    const dagRunId = await dagsPage.triggerDag(testDagId);
+
+    // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
+    if (dagRunId) {

Review Comment:
   Correct, fixed



##########
airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts:
##########
@@ -0,0 +1,60 @@
+/*!
+ * 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.
+ */
+import { test } from "@playwright/test";
+
+import { testConfig } from "../../../playwright.config.ts";
+import { DagsPage } from "../pages/DagsPage.ts";
+import { LoginPage } from "../pages/LoginPage.ts";
+
+/**
+ * DAG Trigger E2E Tests
+ */
+
+test.describe("DAG Trigger Workflow", () => {
+  let loginPage: LoginPage;
+  let dagsPage: DagsPage;
+
+  // Test configuration from centralized config
+
+  const testCredentials = testConfig.credentials;
+
+  const testDagId = testConfig.testDag.id;
+
+  // eslint-disable-next-line @typescript-eslint/require-await

Review Comment:
   Right updated to sync function



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "potiuk (via GitHub)" <gi...@apache.org>.
potiuk commented on PR #58548:
URL: https://github.com/apache/airflow/pull/58548#issuecomment-3590659533

   This is cool. 
   
   But there are two follow up questions: 
   
   * Currently `breeze testing ui-e2e-tests` fails when there is no pnpm installed locally:
   
   ```
     File "/Users/jarekpotiuk/.local/share/uv/python/cpython-3.13.7-macos-aarch64-none/lib/python3.13/subprocess.py", line 1972, in _execute_child
       raise child_exception_type(errno_num, err_msg, err_filename)
   FileNotFoundError: [Errno 2] No such file or directory: 'pnpm'
   ```
   
   I think it should at least be explained as a prerequisite or installed automatically. Generally `breeze testing` is a command that does **everything** - lile building images when needed etc.  Might be a good idea to improve that part
   
   
   * the tests are not run in CI  (I guess?) - this means that they are prone to be broken any time. Any plans to run them on CI ? 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "pierrejeambrun (via GitHub)" <gi...@apache.org>.
pierrejeambrun commented on PR #58548:
URL: https://github.com/apache/airflow/pull/58548#issuecomment-3587004767

   We probably also should ignore reports and test results 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "vatsrahul1001 (via GitHub)" <gi...@apache.org>.
vatsrahul1001 commented on PR #58548:
URL: https://github.com/apache/airflow/pull/58548#issuecomment-3590988287

   Thanks for raising this @potiuk I will raise PR to handle this today.
   > * Currently `breeze testing ui-e2e-tests` fails when there is no pnpm installed locally:
   
   Yes, the plan is to create a CI workflow that will deploy an Airflow instance and run these tests. I will create a follow-up PR for this soon.
   `the tests are not run in CI (I guess?) - this means that they are prone to be broken any time. Any plans to run them on CI ?
   `
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "vatsrahul1001 (via GitHub)" <gi...@apache.org>.
vatsrahul1001 commented on PR #58548:
URL: https://github.com/apache/airflow/pull/58548#issuecomment-3591034854

   [PR](https://github.com/apache/airflow/pull/58845) to install pnpm if not already installed.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "pierrejeambrun (via GitHub)" <gi...@apache.org>.
pierrejeambrun commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2569645618


##########
airflow-core/src/airflow/ui/tests/e2e/pages/LoginPage.ts:
##########
@@ -0,0 +1,93 @@
+/*!
+ * 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.
+ */
+import { expect } from "@playwright/test";
+import type { Locator, Page } from "@playwright/test";
+
+import { BasePage } from "./BasePage.ts";
+
+/**
+ * Login Page Object
+ */
+export class LoginPage extends BasePage {
+  // Page URLs
+  public static get loginUrl(): string {
+    return "/auth/login";
+  }
+
+  public readonly errorMessage: Locator;
+  public readonly loginButton: Locator;
+  public readonly passwordInput: Locator;
+  public readonly usernameInput: Locator;
+
+  public constructor(page: Page) {
+    super(page);
+
+    this.usernameInput = page.locator('input[name="username"]');
+    this.passwordInput = page.locator('input[name="password"]');
+    this.loginButton = page.locator('button[type="submit"]');

Review Comment:
   Could be great to handle both `SimpleAuthManager` and `FabAuthManager`. 
   
   The button is not found with `FabAuthManager` at the moment. I think it's a small adjustment to make to the selector. (if simplemanager button is not found, try the fabauthmanger selector)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "pierrejeambrun (via GitHub)" <gi...@apache.org>.
pierrejeambrun commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2569626566


##########
airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts:
##########
@@ -0,0 +1,60 @@
+/*!
+ * 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.
+ */
+import { test } from "@playwright/test";
+
+import { testConfig } from "../../../playwright.config.ts";
+import { DagsPage } from "../pages/DagsPage.ts";
+import { LoginPage } from "../pages/LoginPage.ts";

Review Comment:
   Nit:
   
   We try to avoid relative imports like this. Can we replace this with absolute imports?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "vatsrahul1001 (via GitHub)" <gi...@apache.org>.
vatsrahul1001 merged PR #58548:
URL: https://github.com/apache/airflow/pull/58548


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "vatsrahul1001 (via GitHub)" <gi...@apache.org>.
vatsrahul1001 commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2570562725


##########
airflow-core/src/airflow/ui/playwright.config.ts:
##########
@@ -0,0 +1,104 @@
+/*!
+ * 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.
+ */
+import { defineConfig, devices } from "@playwright/test";
+
+/**
+ * Playwright configuration for Airflow UI End-to-End Tests
+ */
+export const testConfig = {
+  credentials: {
+    password: process.env.TEST_PASSWORD ?? "admin",
+    username: process.env.TEST_USERNAME ?? "admin",
+  },
+  testDag: {
+    id: process.env.TEST_DAG_ID ?? "example_bash_operator",
+  },
+};
+
+export default defineConfig({
+  expect: {
+    timeout: 5000,
+  },
+  forbidOnly: process.env.CI !== undefined && process.env.CI !== "",
+  fullyParallel: true,
+  projects: [
+    {
+      name: "chromium",
+      use: {
+        ...devices["Desktop Chrome"],
+        launchOptions: {
+          args: [
+            "--start-maximized",
+            "--disable-web-security",
+            "--disable-features=VizDisplayCompositor",
+            "--window-size=1920,1080",
+            "--window-position=0,0",
+          ],
+          channel: "chrome",
+          ignoreDefaultArgs: ["--enable-automation"],
+        },
+      },
+    },
+    {
+      name: "firefox",
+      use: {
+        ...devices["Desktop Firefox"],
+        launchOptions: {
+          args: [
+            "--width=1920",
+            "--height=1080",
+            "--no-sandbox",
+            "--disable-dev-shm-usage",
+            "--disable-web-security",
+          ],
+        },
+      },
+    },
+    {
+      name: "webkit",
+      use: {
+        ...devices["Desktop Safari"],
+        launchOptions: {
+          args: [],
+        },
+      },
+    },
+  ],
+  reporter: [
+    ["html", { outputFolder: "playwright-report" }],
+    ["json", { outputFile: "test-results/results.json" }],
+    process.env.CI !== undefined && process.env.CI !== "" ? ["github"] : ["list"],
+  ],
+
+  retries: process.env.CI !== undefined && process.env.CI !== "" ? 2 : 0,
+
+  testDir: "./tests/e2e/specs",
+
+  timeout: 30_000,

Review Comment:
   This is 30 seconds



##########
airflow-core/src/airflow/ui/playwright.config.ts:
##########
@@ -0,0 +1,104 @@
+/*!
+ * 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.
+ */
+import { defineConfig, devices } from "@playwright/test";
+
+/**
+ * Playwright configuration for Airflow UI End-to-End Tests
+ */
+export const testConfig = {
+  credentials: {
+    password: process.env.TEST_PASSWORD ?? "admin",
+    username: process.env.TEST_USERNAME ?? "admin",
+  },
+  testDag: {
+    id: process.env.TEST_DAG_ID ?? "example_bash_operator",
+  },
+};
+
+export default defineConfig({
+  expect: {
+    timeout: 5000,
+  },
+  forbidOnly: process.env.CI !== undefined && process.env.CI !== "",
+  fullyParallel: true,
+  projects: [
+    {
+      name: "chromium",
+      use: {
+        ...devices["Desktop Chrome"],
+        launchOptions: {
+          args: [
+            "--start-maximized",
+            "--disable-web-security",
+            "--disable-features=VizDisplayCompositor",
+            "--window-size=1920,1080",
+            "--window-position=0,0",
+          ],
+          channel: "chrome",
+          ignoreDefaultArgs: ["--enable-automation"],
+        },
+      },
+    },
+    {
+      name: "firefox",
+      use: {
+        ...devices["Desktop Firefox"],
+        launchOptions: {
+          args: [
+            "--width=1920",
+            "--height=1080",
+            "--no-sandbox",
+            "--disable-dev-shm-usage",
+            "--disable-web-security",
+          ],
+        },
+      },
+    },
+    {
+      name: "webkit",
+      use: {
+        ...devices["Desktop Safari"],
+        launchOptions: {
+          args: [],
+        },
+      },
+    },
+  ],
+  reporter: [
+    ["html", { outputFolder: "playwright-report" }],
+    ["json", { outputFile: "test-results/results.json" }],
+    process.env.CI !== undefined && process.env.CI !== "" ? ["github"] : ["list"],
+  ],
+
+  retries: process.env.CI !== undefined && process.env.CI !== "" ? 2 : 0,
+
+  testDir: "./tests/e2e/specs",
+
+  timeout: 30_000,
+  use: {
+    actionTimeout: 10_000,

Review Comment:
   This is 30 seconds



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "vatsrahul1001 (via GitHub)" <gi...@apache.org>.
vatsrahul1001 commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2570576598


##########
airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts:
##########


Review Comment:
   Yes, I will open a separate PR for the workflow



##########
airflow-core/src/airflow/ui/tests/e2e/pages/LoginPage.ts:
##########
@@ -0,0 +1,93 @@
+/*!
+ * 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.
+ */
+import { expect } from "@playwright/test";
+import type { Locator, Page } from "@playwright/test";
+
+import { BasePage } from "./BasePage.ts";
+
+/**
+ * Login Page Object
+ */
+export class LoginPage extends BasePage {
+  // Page URLs
+  public static get loginUrl(): string {
+    return "/auth/login";
+  }
+
+  public readonly errorMessage: Locator;
+  public readonly loginButton: Locator;
+  public readonly passwordInput: Locator;
+  public readonly usernameInput: Locator;
+
+  public constructor(page: Page) {
+    super(page);
+
+    this.usernameInput = page.locator('input[name="username"]');
+    this.passwordInput = page.locator('input[name="password"]');
+    this.loginButton = page.locator('button[type="submit"]');

Review Comment:
   Added a locator for fab as well



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "pierrejeambrun (via GitHub)" <gi...@apache.org>.
pierrejeambrun commented on PR #58548:
URL: https://github.com/apache/airflow/pull/58548#issuecomment-3847908674

   @anushkaaaaaaaa Thank you for showing interest. You can comment on an unassigned e2e issue tracker.
   
   Meta issue is here https://github.com/apache/airflow/issues/59028 and there you will find also related sub issues.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "pierrejeambrun (via GitHub)" <gi...@apache.org>.
pierrejeambrun commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2569626566


##########
airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts:
##########
@@ -0,0 +1,60 @@
+/*!
+ * 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.
+ */
+import { test } from "@playwright/test";
+
+import { testConfig } from "../../../playwright.config.ts";
+import { DagsPage } from "../pages/DagsPage.ts";
+import { LoginPage } from "../pages/LoginPage.ts";

Review Comment:
   Nit:
   
   We try to avoid relative imports like this. 



##########
airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts:
##########
@@ -0,0 +1,60 @@
+/*!
+ * 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.
+ */
+import { test } from "@playwright/test";
+
+import { testConfig } from "../../../playwright.config.ts";
+import { DagsPage } from "../pages/DagsPage.ts";
+import { LoginPage } from "../pages/LoginPage.ts";
+
+/**
+ * DAG Trigger E2E Tests
+ */
+
+test.describe("DAG Trigger Workflow", () => {
+  let loginPage: LoginPage;
+  let dagsPage: DagsPage;
+
+  // Test configuration from centralized config
+
+  const testCredentials = testConfig.credentials;
+
+  const testDagId = testConfig.testDag.id;
+
+  // eslint-disable-next-line @typescript-eslint/require-await

Review Comment:
   You can probaly convert this to a sync function, so we can get rid of the eslint disable above. @
   



##########
airflow-core/src/airflow/ui/playwright.config.ts:
##########
@@ -0,0 +1,104 @@
+/*!
+ * 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.
+ */
+import { defineConfig, devices } from "@playwright/test";
+
+/**
+ * Playwright configuration for Airflow UI End-to-End Tests
+ */
+export const testConfig = {
+  credentials: {
+    password: process.env.TEST_PASSWORD ?? "admin",
+    username: process.env.TEST_USERNAME ?? "admin",
+  },
+  testDag: {
+    id: process.env.TEST_DAG_ID ?? "example_bash_operator",
+  },
+};
+
+export default defineConfig({
+  expect: {
+    timeout: 5000,
+  },
+  forbidOnly: process.env.CI !== undefined && process.env.CI !== "",
+  fullyParallel: true,
+  projects: [
+    {
+      name: "chromium",
+      use: {
+        ...devices["Desktop Chrome"],
+        launchOptions: {
+          args: [
+            "--start-maximized",
+            "--disable-web-security",
+            "--disable-features=VizDisplayCompositor",
+            "--window-size=1920,1080",
+            "--window-position=0,0",
+          ],
+          channel: "chrome",
+          ignoreDefaultArgs: ["--enable-automation"],
+        },
+      },
+    },
+    {
+      name: "firefox",
+      use: {
+        ...devices["Desktop Firefox"],
+        launchOptions: {
+          args: [
+            "--width=1920",
+            "--height=1080",
+            "--no-sandbox",
+            "--disable-dev-shm-usage",
+            "--disable-web-security",
+          ],
+        },
+      },
+    },
+    {
+      name: "webkit",
+      use: {
+        ...devices["Desktop Safari"],
+        launchOptions: {
+          args: [],
+        },
+      },
+    },
+  ],
+  reporter: [
+    ["html", { outputFolder: "playwright-report" }],
+    ["json", { outputFile: "test-results/results.json" }],
+    process.env.CI !== undefined && process.env.CI !== "" ? ["github"] : ["list"],
+  ],
+
+  retries: process.env.CI !== undefined && process.env.CI !== "" ? 2 : 0,
+
+  testDir: "./tests/e2e/specs",
+
+  timeout: 30_000,

Review Comment:
   That timeout value might be too long no? Similarly above i've seen a 30_000 somewhere else.



##########
airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts:
##########


Review Comment:
   I would be for running this by default as a workflow to all UI PRs, so we're sure this doesn't get broken and very hard to maintain. 
   
   As long as those tests are lightweight and doesn't require too much time / resources that would be my recommendation.



##########
airflow-core/src/airflow/ui/tests/e2e/README.md:
##########
@@ -0,0 +1,91 @@
+<!--
+ 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.
+ -->
+
+# Airflow UI End-to-End Tests
+
+UI automation tests using Playwright for critical Airflow workflows.
+
+## Prerequisites
+
+**Requires running Airflow with example DAGs:**
+
+- Airflow running on `http://localhost:28080` (default)
+- Admin user: `admin/admin`
+- Example DAGs loaded (uses `example_bash_operator`)
+
+## Running Tests
+
+### Using Breeze
+
+```bash
+# Basic run
+breeze testing ui-e2e-tests
+
+# Specific test with browser visible
+breeze testing ui-e2e-tests --test-pattern "dag-trigger.spec.ts" --headed
+
+# Different browsers
+breeze testing ui-e2e-tests --browser firefox --headed
+breeze testing ui-e2e-tests --browser webkit --headed
+```
+
+### Using pnpm directly
+
+```bash
+cd airflow-core/src/airflow/ui
+
+# Install dependencies
+pnpm install
+pnpm exec playwright install
+
+# Run tests
+pnpm test:e2e:headed                    # Show browser
+pnpm test:e2e:ui                       # Interactive debugging
+```
+
+## Test Structure
+
+```
+tests/e2e/
+├── pages/           # Page Object Models
+└── specs/           # Test files
+```
+
+## Configuration
+
+Set environment variables if needed:
+
+```bash
+export AIRFLOW_UI_BASE_URL=http://localhost:28080
+export TEST_USERNAME=admin
+export TEST_PASSWORD=admin
+export TEST_DAG_ID=example_bash_operator
+```
+
+## Debugging
+
+```bash
+# Step through tests
+breeze testing ui-e2e-tests --debug-e2e
+
+# View test report
+pnpm exec playwright show-report

Review Comment:
   maybe replace by `test:e2e:report` 



##########
airflow-core/src/airflow/ui/tests/e2e/README.md:
##########
@@ -0,0 +1,91 @@
+<!--
+ 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.
+ -->
+
+# Airflow UI End-to-End Tests
+
+UI automation tests using Playwright for critical Airflow workflows.
+
+## Prerequisites
+
+**Requires running Airflow with example DAGs:**
+
+- Airflow running on `http://localhost:28080` (default)

Review Comment:
   ```suggestion
   - Airflow UI running on `http://localhost:28080` (default)
   ```



##########
airflow-core/src/airflow/ui/playwright.config.ts:
##########
@@ -0,0 +1,104 @@
+/*!
+ * 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.
+ */
+import { defineConfig, devices } from "@playwright/test";
+
+/**
+ * Playwright configuration for Airflow UI End-to-End Tests
+ */
+export const testConfig = {
+  credentials: {
+    password: process.env.TEST_PASSWORD ?? "admin",
+    username: process.env.TEST_USERNAME ?? "admin",
+  },
+  testDag: {
+    id: process.env.TEST_DAG_ID ?? "example_bash_operator",
+  },
+};
+
+export default defineConfig({
+  expect: {
+    timeout: 5000,
+  },
+  forbidOnly: process.env.CI !== undefined && process.env.CI !== "",
+  fullyParallel: true,
+  projects: [
+    {
+      name: "chromium",
+      use: {
+        ...devices["Desktop Chrome"],
+        launchOptions: {
+          args: [
+            "--start-maximized",
+            "--disable-web-security",
+            "--disable-features=VizDisplayCompositor",
+            "--window-size=1920,1080",
+            "--window-position=0,0",
+          ],
+          channel: "chrome",
+          ignoreDefaultArgs: ["--enable-automation"],
+        },
+      },
+    },
+    {
+      name: "firefox",
+      use: {
+        ...devices["Desktop Firefox"],
+        launchOptions: {
+          args: [
+            "--width=1920",
+            "--height=1080",
+            "--no-sandbox",
+            "--disable-dev-shm-usage",
+            "--disable-web-security",
+          ],
+        },
+      },
+    },
+    {
+      name: "webkit",
+      use: {
+        ...devices["Desktop Safari"],
+        launchOptions: {
+          args: [],
+        },
+      },
+    },
+  ],
+  reporter: [
+    ["html", { outputFolder: "playwright-report" }],
+    ["json", { outputFile: "test-results/results.json" }],
+    process.env.CI !== undefined && process.env.CI !== "" ? ["github"] : ["list"],
+  ],
+
+  retries: process.env.CI !== undefined && process.env.CI !== "" ? 2 : 0,
+
+  testDir: "./tests/e2e/specs",
+
+  timeout: 30_000,
+  use: {
+    actionTimeout: 10_000,

Review Comment:
   Same here, that's almost 3 hours



##########
airflow-core/src/airflow/ui/tests/e2e/pages/LoginPage.ts:
##########
@@ -0,0 +1,93 @@
+/*!
+ * 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.
+ */
+import { expect } from "@playwright/test";
+import type { Locator, Page } from "@playwright/test";
+
+import { BasePage } from "./BasePage.ts";
+
+/**
+ * Login Page Object
+ */
+export class LoginPage extends BasePage {
+  // Page URLs
+  public static get loginUrl(): string {
+    return "/auth/login";
+  }
+
+  public readonly errorMessage: Locator;
+  public readonly loginButton: Locator;
+  public readonly passwordInput: Locator;
+  public readonly usernameInput: Locator;
+
+  public constructor(page: Page) {
+    super(page);
+
+    this.usernameInput = page.locator('input[name="username"]');
+    this.passwordInput = page.locator('input[name="password"]');
+    this.loginButton = page.locator('button[type="submit"]');

Review Comment:
   Could be great to handle both `SimpleAuthManager` and `FabAuthManager`. 
   
   The button is not found with `FabAuthManager` at the moment. I think it's a small adjustment to make to the selector. (if else)



##########
airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts:
##########
@@ -0,0 +1,60 @@
+/*!
+ * 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.
+ */
+import { test } from "@playwright/test";
+
+import { testConfig } from "../../../playwright.config.ts";
+import { DagsPage } from "../pages/DagsPage.ts";
+import { LoginPage } from "../pages/LoginPage.ts";
+
+/**
+ * DAG Trigger E2E Tests
+ */
+
+test.describe("DAG Trigger Workflow", () => {
+  let loginPage: LoginPage;
+  let dagsPage: DagsPage;
+
+  // Test configuration from centralized config
+
+  const testCredentials = testConfig.credentials;
+
+  const testDagId = testConfig.testDag.id;
+
+  // eslint-disable-next-line @typescript-eslint/require-await
+  test.beforeEach(async ({ page }) => {
+    loginPage = new LoginPage(page);
+
+    dagsPage = new DagsPage(page);
+  });
+
+  test("should successfully trigger a DAG run", async () => {
+    test.setTimeout(7 * 60 * 1000);
+
+    await loginPage.navigateAndLogin(testCredentials.username, testCredentials.password);
+
+    await loginPage.expectLoginSuccess();
+
+    const dagRunId = await dagsPage.triggerDag(testDagId);
+
+    // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
+    if (dagRunId) {

Review Comment:
   Here you need an actual boolean check I believe. It will remove the eslint warning. `Boolean(...)`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "pierrejeambrun (via GitHub)" <gi...@apache.org>.
pierrejeambrun commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2569619431


##########
airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts:
##########
@@ -0,0 +1,60 @@
+/*!
+ * 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.
+ */
+import { test } from "@playwright/test";
+
+import { testConfig } from "../../../playwright.config.ts";
+import { DagsPage } from "../pages/DagsPage.ts";
+import { LoginPage } from "../pages/LoginPage.ts";
+
+/**
+ * DAG Trigger E2E Tests
+ */
+
+test.describe("DAG Trigger Workflow", () => {
+  let loginPage: LoginPage;
+  let dagsPage: DagsPage;
+
+  // Test configuration from centralized config
+
+  const testCredentials = testConfig.credentials;
+
+  const testDagId = testConfig.testDag.id;
+
+  // eslint-disable-next-line @typescript-eslint/require-await

Review Comment:
   You can probaly convert this to a sync function, so we can get rid of the eslint disable above.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "vatsrahul1001 (via GitHub)" <gi...@apache.org>.
vatsrahul1001 commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2571461387


##########
airflow-core/src/airflow/ui/tests/e2e/pages/DagsPage.ts:
##########
@@ -0,0 +1,184 @@
+/*!
+ * 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.
+ */
+import type { Locator, Page } from "@playwright/test";
+import { BasePage } from "tests/e2e/pages/BasePage";
+
+/**
+ * DAGs Page Object
+ */
+export class DagsPage extends BasePage {
+  // Page URLs
+  public static get dagsListUrl(): string {
+    return "/dags";
+  }
+
+  // Core page elements
+  public readonly confirmButton: Locator;
+  public readonly dagsTable: Locator;
+  public readonly stateElement: Locator;
+  public readonly triggerButton: Locator;
+
+  public constructor(page: Page) {
+    super(page);
+    this.dagsTable = page.locator('div:has(a[href*="/dags/"])');
+    this.triggerButton = page.locator('button[aria-label="Trigger Dag"]:has-text("Trigger")');
+    this.confirmButton = page.locator('button:has-text("Trigger")').nth(1);
+    this.stateElement = page.locator('*:has-text("State") + *').first();
+  }
+
+  // URL builders for dynamic paths
+  public static getDagDetailUrl(dagName: string): string {
+    return `/dags/${dagName}`;
+  }
+
+  public static getDagRunDetailsUrl(dagName: string, dagRunId: string): string {
+    return `/dags/${dagName}/runs/${dagRunId}/details`;
+  }
+
+  /**
+   * Navigate to DAGs list page
+   */
+  public async navigate(): Promise<void> {
+    await this.navigateTo(DagsPage.dagsListUrl);
+  }
+
+  /**
+   * Navigate to DAG detail page
+   */
+  public async navigateToDagDetail(dagName: string): Promise<void> {
+    await this.navigateTo(DagsPage.getDagDetailUrl(dagName));
+  }
+
+  /**
+   * Trigger a DAG run
+   */
+  public async triggerDag(dagName: string): Promise<string | null> {
+    await this.navigateToDagDetail(dagName);
+    await this.triggerButton.waitFor({ state: "visible", timeout: 10_000 });
+    await this.triggerButton.click();
+    const dagRunId = await this.handleTriggerDialog();
+
+    return dagRunId;
+  }
+
+  public async verifyDagRunStatus(dagName: string, dagRunId: string | null): Promise<void> {
+    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+    if (dagRunId === null || dagRunId === undefined || dagRunId === "") {
+      return;
+    }
+
+    await this.page.goto(DagsPage.getDagRunDetailsUrl(dagName, dagRunId), {
+      timeout: 15_000,
+      waitUntil: "domcontentloaded",
+    });
+
+    await this.page.waitForTimeout(2000);
+
+    const maxWaitTime = 5 * 60 * 1000;
+    const checkInterval = 10_000;
+    const startTime = Date.now();
+
+    while (Date.now() - startTime < maxWaitTime) {
+      const currentStatus = await this.getCurrentDagRunStatus();
+
+      if (currentStatus === "success") {
+        return;
+      } else if (currentStatus === "failed") {
+        throw new Error(`DAG run failed: ${dagRunId}`);
+      }
+
+      await this.page.waitForTimeout(checkInterval);
+
+      await this.page.reload({ waitUntil: "domcontentloaded" });
+
+      await this.page.waitForTimeout(2000);
+    }
+
+    throw new Error(`DAG run did not complete within 5 minutes: ${dagRunId}`);
+  }
+
+  private async getCurrentDagRunStatus(): Promise<string> {
+    try {
+      const statusText = await this.stateElement.textContent().catch(() => "");
+      const status = statusText?.trim() ?? "";
+
+      switch (status) {
+        case "Failed":
+          return "failed";
+        case "Queued":
+          return "queued";
+        case "Running":
+          return "running";
+        case "Success":
+          return "success";
+        default:
+          return "unknown";
+      }
+    } catch {
+      return "unknown";
+    }
+  }
+
+  private async handleTriggerDialog(): Promise<string | null> {
+    await this.page.waitForTimeout(1000);
+
+    const responsePromise = this.page
+
+      .waitForResponse(
+        (response) => {
+          const url = response.url();
+
+          const method = response.request().method();
+
+          return (
+            method === "POST" && Boolean(url.includes("dagRuns")) && Boolean(!url.includes("hitlDetails"))
+          );
+        },
+        { timeout: 10_000 },
+      )
+
+      .catch(() => undefined);
+
+    await this.confirmButton.waitFor({ state: "visible", timeout: 8000 });
+
+    await this.page.waitForTimeout(2000);
+    await this.confirmButton.click({ force: true });
+
+    const apiResponse = await responsePromise;
+
+    if (apiResponse) {
+      try {
+        const responseBody = await apiResponse.text();
+        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+        const responseJson = JSON.parse(responseBody);
+
+        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+        if (Boolean(responseJson.dag_run_id)) {
+          // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
+          return responseJson.dag_run_id;
+        }
+      } catch {

Review Comment:
   Done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "vatsrahul1001 (via GitHub)" <gi...@apache.org>.
vatsrahul1001 commented on code in PR #58548:
URL: https://github.com/apache/airflow/pull/58548#discussion_r2570576841


##########
airflow-core/src/airflow/ui/tests/e2e/README.md:
##########
@@ -0,0 +1,91 @@
+<!--
+ 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.
+ -->
+
+# Airflow UI End-to-End Tests
+
+UI automation tests using Playwright for critical Airflow workflows.
+
+## Prerequisites
+
+**Requires running Airflow with example DAGs:**
+
+- Airflow running on `http://localhost:28080` (default)

Review Comment:
   done



##########
airflow-core/src/airflow/ui/tests/e2e/README.md:
##########
@@ -0,0 +1,91 @@
+<!--
+ 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.
+ -->
+
+# Airflow UI End-to-End Tests
+
+UI automation tests using Playwright for critical Airflow workflows.
+
+## Prerequisites
+
+**Requires running Airflow with example DAGs:**
+
+- Airflow running on `http://localhost:28080` (default)
+- Admin user: `admin/admin`
+- Example DAGs loaded (uses `example_bash_operator`)
+
+## Running Tests
+
+### Using Breeze
+
+```bash
+# Basic run
+breeze testing ui-e2e-tests
+
+# Specific test with browser visible
+breeze testing ui-e2e-tests --test-pattern "dag-trigger.spec.ts" --headed
+
+# Different browsers
+breeze testing ui-e2e-tests --browser firefox --headed
+breeze testing ui-e2e-tests --browser webkit --headed
+```
+
+### Using pnpm directly
+
+```bash
+cd airflow-core/src/airflow/ui
+
+# Install dependencies
+pnpm install
+pnpm exec playwright install
+
+# Run tests
+pnpm test:e2e:headed                    # Show browser
+pnpm test:e2e:ui                       # Interactive debugging
+```
+
+## Test Structure
+
+```
+tests/e2e/
+├── pages/           # Page Object Models
+└── specs/           # Test files
+```
+
+## Configuration
+
+Set environment variables if needed:
+
+```bash
+export AIRFLOW_UI_BASE_URL=http://localhost:28080
+export TEST_USERNAME=admin
+export TEST_PASSWORD=admin
+export TEST_DAG_ID=example_bash_operator
+```
+
+## Debugging
+
+```bash
+# Step through tests
+breeze testing ui-e2e-tests --debug-e2e
+
+# View test report
+pnpm exec playwright show-report

Review Comment:
   done



##########
airflow-core/src/airflow/ui/tests/e2e/specs/dag-trigger.spec.ts:
##########
@@ -0,0 +1,60 @@
+/*!
+ * 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.
+ */
+import { test } from "@playwright/test";
+
+import { testConfig } from "../../../playwright.config.ts";
+import { DagsPage } from "../pages/DagsPage.ts";
+import { LoginPage } from "../pages/LoginPage.ts";

Review Comment:
   Yes, replaced with absolute imports



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add UI E2E testing framework with Playwright and Breeze integration [airflow]

Posted by "anushkaaaaaaaa (via GitHub)" <gi...@apache.org>.
anushkaaaaaaaa commented on PR #58548:
URL: https://github.com/apache/airflow/pull/58548#issuecomment-3846086213

   Hey I've experience in E2E testing, I'd like to work on this, can you please assign this issue to me, thankyou!


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@airflow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org