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

choo121600 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 3151443a167 Improve Playwright test patterns in backfill.spec.ts and 
BackfillPage.ts (#63112)
3151443a167 is described below

commit 3151443a1672b9b2876c83647fe00cd058caee41
Author: Stats <[email protected]>
AuthorDate: Mon Mar 9 11:44:28 2026 +0900

    Improve Playwright test patterns in backfill.spec.ts and BackfillPage.ts 
(#63112)
---
 .../src/airflow/ui/tests/e2e/pages/BackfillPage.ts | 55 ++++++++++++++--------
 .../airflow/ui/tests/e2e/specs/backfill.spec.ts    | 17 +++----
 2 files changed, 42 insertions(+), 30 deletions(-)

diff --git a/airflow-core/src/airflow/ui/tests/e2e/pages/BackfillPage.ts 
b/airflow-core/src/airflow/ui/tests/e2e/pages/BackfillPage.ts
index 288c3d40b58..56fdbd9f90d 100644
--- a/airflow-core/src/airflow/ui/tests/e2e/pages/BackfillPage.ts
+++ b/airflow-core/src/airflow/ui/tests/e2e/pages/BackfillPage.ts
@@ -94,7 +94,7 @@ export class BackfillPage extends BasePage {
     super(page);
     this.triggerButton = page.getByTestId("trigger-dag-button");
     // Chakra UI radio cards: target the label directly since <input> is 
hidden.
-    this.backfillModeRadio = page.locator('label:has-text("Backfill")');
+    this.backfillModeRadio = page.locator("label").getByText("Backfill", { 
exact: true });
     this.backfillFromDateInput = page.getByTestId("datetime-input").first();
     this.backfillToDateInput = page.getByTestId("datetime-input").nth(1);
     this.backfillRunButton = page.getByRole("button", { name: "Run Backfill" 
});
@@ -374,10 +374,6 @@ export class BackfillPage extends BasePage {
     return this.page.getByRole("button", { name: /filter table columns/i });
   }
 
-  public async getTableColumnCount(): Promise<number> {
-    return this.backfillsTable.locator("thead th").count();
-  }
-
   public async navigateToBackfillsTab(dagName: string): Promise<void> {
     await this.navigateTo(BackfillPage.getBackfillsUrl(dagName));
     await expect(this.backfillsTable).toBeVisible({ timeout: 15_000 });
@@ -400,31 +396,50 @@ export class BackfillPage extends BasePage {
   }
 
   public async pauseBackfillViaApi(backfillId: number): Promise<boolean> {
-    // Retry: the server may not have fully initialized the backfill yet.
-    for (let attempt = 0; attempt < 5; attempt++) {
-      const response = await 
this.page.request.put(`${baseUrl}/api/v2/backfills/${backfillId}/pause`, {
-        timeout: 30_000,
-      });
+    let isPaused = false;
+
+    try {
+      // Retry: the server may not have fully initialized the backfill yet.
+      await expect
+        .poll(
+          async () => {
+            const response = await 
this.page.request.put(`${baseUrl}/api/v2/backfills/${backfillId}/pause`, {
+              timeout: 30_000,
+            });
 
-      if (response.ok()) {
-        return true;
-      }
+            if (response.ok()) {
+              isPaused = true;
 
-      // 409 means the backfill already completed — not retriable.
-      if (response.status() === 409) {
-        return false;
-      }
+              return true;
+            }
+
+            // 409 means the backfill already completed — not retriable.
+            if (response.status() === 409) {
+              isPaused = false;
 
-      await this.page.waitForTimeout(2000);
+              return true;
+            }
+
+            return false;
+          },
+          {
+            intervals: [2000],
+            message: `Failed to pause backfill ${backfillId}`,
+            timeout: 10_000,
+          },
+        )
+        .toBeTruthy();
+    } catch {
+      return false;
     }
 
-    return false;
+    return isPaused;
   }
 
   public async selectReprocessBehavior(behavior: ReprocessBehaviorApi): 
Promise<void> {
     const label = REPROCESS_API_TO_UI[behavior];
 
-    await this.page.locator(`label:has-text("${label}")`).first().click({ 
timeout: 5000 });
+    await this.page.locator("label").getByText(label, { exact: true }).click({ 
timeout: 5000 });
   }
 
   public async toggleColumn(columnName: string): Promise<void> {
diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/backfill.spec.ts 
b/airflow-core/src/airflow/ui/tests/e2e/specs/backfill.spec.ts
index 8babe2f9513..b97d31d8b46 100644
--- a/airflow-core/src/airflow/ui/tests/e2e/specs/backfill.spec.ts
+++ b/airflow-core/src/airflow/ui/tests/e2e/specs/backfill.spec.ts
@@ -109,17 +109,18 @@ test.describe("Backfill", () => {
 
       await backfillPage.navigateToBackfillsTab(testDagId);
 
-      const initialColumnCount = await backfillPage.getTableColumnCount();
+      const tableHeaders = backfillPage.backfillsTable.locator("thead th");
+
+      await expect(tableHeaders).toHaveCount(7); // Initial state should have 
7 columns
+      const initialColumnCount = await tableHeaders.count();
 
-      expect(initialColumnCount).toBeGreaterThan(0);
       await expect(backfillPage.getFilterButton()).toBeVisible();
 
       await backfillPage.openFilterMenu();
 
       const filterMenuItems = page.getByRole("menuitem");
-      const filterMenuCount = await filterMenuItems.count();
 
-      expect(filterMenuCount).toBeGreaterThan(0);
+      await expect(filterMenuItems).not.toHaveCount(0);
 
       const firstMenuItem = filterMenuItems.first();
       const columnToToggle = (await firstMenuItem.textContent())?.trim() ?? "";
@@ -131,9 +132,7 @@ test.describe("Backfill", () => {
 
       await 
expect(backfillPage.getColumnHeader(columnToToggle)).not.toBeVisible();
 
-      const newColumnCount = await backfillPage.getTableColumnCount();
-
-      expect(newColumnCount).toBeLessThan(initialColumnCount);
+      await expect(tableHeaders).toHaveCount(initialColumnCount - 1);
 
       await backfillPage.openFilterMenu();
       await backfillPage.toggleColumn(columnToToggle);
@@ -141,9 +140,7 @@ test.describe("Backfill", () => {
 
       await expect(backfillPage.getColumnHeader(columnToToggle)).toBeVisible();
 
-      const finalColumnCount = await backfillPage.getTableColumnCount();
-
-      expect(finalColumnCount).toBe(initialColumnCount);
+      await expect(tableHeaders).toHaveCount(initialColumnCount);
     });
   });
 

Reply via email to