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

rahulvats 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 e850b4eb362 Fix flaky backfill E2E tests with stable locators (#62913)
e850b4eb362 is described below

commit e850b4eb3626663f5cd3e53eb15285557ee84bb0
Author: Yeonguk Choo <[email protected]>
AuthorDate: Sat Mar 7 17:56:43 2026 +0900

    Fix flaky backfill E2E tests with stable locators (#62913)
    
    * Fix flaky backfill E2E tests with stable locators
    
    * fix 409 flaky
    
    * feat: add support for maxActiveRuns and createPausedBackfillViaApi for 
race with scheduler
---
 .../src/airflow/ui/tests/e2e/pages/BackfillPage.ts | 612 +++++++++++----------
 .../airflow/ui/tests/e2e/specs/backfill.spec.ts    | 349 ++++++------
 2 files changed, 480 insertions(+), 481 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 100f940f9a5..288c3d40b58 100644
--- a/airflow-core/src/airflow/ui/tests/e2e/pages/BackfillPage.ts
+++ b/airflow-core/src/airflow/ui/tests/e2e/pages/BackfillPage.ts
@@ -18,48 +18,60 @@
  */
 import { expect } from "@playwright/test";
 import type { Locator, Page } from "@playwright/test";
+import { testConfig } from "playwright.config";
 import { BasePage } from "tests/e2e/pages/BasePage";
 
-export type ReprocessBehavior = "All Runs" | "Missing and Errored Runs" | 
"Missing Runs";
+export const REPROCESS_API_TO_UI = {
+  completed: "All Runs",
+  failed: "Missing and Errored Runs",
+  none: "Missing Runs",
+} as const;
 
-export type CreateBackfillOptions = {
+export type ReprocessBehaviorApi = keyof typeof REPROCESS_API_TO_UI;
+
+type BackfillDetails = {
+  completedAt: string;
+  createdAt: string;
   fromDate: string;
-  reprocessBehavior: ReprocessBehavior;
+  reprocessBehavior: string;
   toDate: string;
 };
 
-export type BackfillDetails = {
-  createdAt: string;
+type BackfillRowIdentifier = {
   fromDate: string;
-  reprocessBehavior: string;
   toDate: string;
 };
 
-export type BackfillRowIdentifier = {
+type CreateBackfillOptions = {
   fromDate: string;
+  maxActiveRuns?: number;
+  reprocessBehavior?: ReprocessBehaviorApi;
   toDate: string;
 };
 
-function normalizeDate(dateString: string): string {
-  const trimmed = dateString.trim();
+type BackfillApiResponse = {
+  completed_at: string | null;
+  id: number;
+};
 
-  if (trimmed.includes("T")) {
-    const parts = trimmed.split("T");
+type BackfillListApiResponse = {
+  backfills: Array<BackfillApiResponse>;
+};
 
-    return parts[0] ?? trimmed;
-  }
+const {
+  connection: { baseUrl },
+} = testConfig;
 
-  if (trimmed.includes(" ")) {
-    const parts = trimmed.split(" ");
+function getColumnIndex(columnMap: Map<string, number>, name: string): number {
+  const index = columnMap.get(name);
 
-    return parts[0] ?? trimmed;
-  }
+  if (index === undefined) {
+    const available = [...columnMap.keys()].join(", ");
 
-  return trimmed;
-}
+    throw new Error(`Column "${name}" not found. Available columns: 
${available}`);
+  }
 
-function datesMatch(date1: string, date2: string): boolean {
-  return normalizeDate(date1) === normalizeDate(date2);
+  return index;
 }
 
 export class BackfillPage extends BasePage {
@@ -72,32 +84,25 @@ export class BackfillPage extends BasePage {
   public readonly cancelButton: Locator;
   public readonly pauseButton: Locator;
   public readonly triggerButton: Locator;
+  public readonly unpauseButton: Locator;
+
+  public get pauseOrUnpauseButton(): Locator {
+    return this.pauseButton.or(this.unpauseButton);
+  }
 
   public constructor(page: Page) {
     super(page);
-    this.triggerButton = page.locator('button[aria-label="Trigger 
Dag"]:has-text("Trigger")');
+    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.backfillFromDateInput = 
page.locator('input[type="datetime-local"]').first();
-    this.backfillToDateInput = 
page.locator('input[type="datetime-local"]').nth(1);
-    this.backfillRunButton = page.locator('button:has-text("Run Backfill")');
-    this.backfillsTable = page.locator("table");
-    this.backfillDateError = page.locator('text="Start Date must be before the 
End Date"');
-    this.cancelButton = page.locator('button[aria-label="Cancel backfill"]');
-    this.pauseButton = page.locator(
-      'button[aria-label="Pause backfill"], button[aria-label="Unpause 
backfill"]',
-    );
-  }
-
-  public static findColumnIndex(columnMap: Map<string, number>, possibleNames: 
Array<string>): number {
-    for (const name of possibleNames) {
-      const index = columnMap.get(name);
-
-      if (index !== undefined) {
-        return index;
-      }
-    }
-
-    return -1;
+    this.backfillFromDateInput = page.getByTestId("datetime-input").first();
+    this.backfillToDateInput = page.getByTestId("datetime-input").nth(1);
+    this.backfillRunButton = page.getByRole("button", { name: "Run Backfill" 
});
+    this.backfillsTable = page.getByTestId("table-list");
+    this.backfillDateError = page.getByText("Start Date must be before the End 
Date");
+    this.cancelButton = page.getByRole("button", { name: "Cancel backfill" });
+    this.pauseButton = page.getByRole("button", { name: "Pause backfill" });
+    this.unpauseButton = page.getByRole("button", { name: "Unpause backfill" 
});
   }
 
   public static getBackfillsUrl(dagName: string): string {
@@ -108,204 +113,252 @@ export class BackfillPage extends BasePage {
     return `/dags/${dagName}`;
   }
 
-  public async clickCancelButton(): Promise<void> {
-    await this.waitForBackdropClosed();
-    await expect(this.cancelButton).toBeVisible({ timeout: 10_000 });
-    await this.cancelButton.click();
-    await expect(this.cancelButton).not.toBeVisible({ timeout: 30_000 });
-  }
+  public async cancelAllActiveBackfillsViaApi(dagId: string): Promise<void> {
+    const response = await 
this.page.request.get(`${baseUrl}/api/v2/backfills?dag_id=${dagId}&limit=100`, {
+      timeout: 30_000,
+    });
 
-  public async clickPauseButton(): Promise<void> {
-    await this.pauseButton.waitFor({ state: "visible", timeout: 30_000 });
-    await this.pauseButton.scrollIntoViewIfNeeded();
-    await expect(this.pauseButton).toBeEnabled({ timeout: 10_000 });
-    const wasPaused = await this.isBackfillPaused();
+    expect(response.ok()).toBe(true);
+    const data = (await response.json()) as BackfillListApiResponse;
 
-    const responsePromise = this.page
-      .waitForResponse(
-        (response) => {
-          const url = response.url();
-          const status = response.status();
-
-          return url.includes("/backfills/") && (status === 200 || status === 
204);
-        },
-        { timeout: 10_000 },
-      )
-      .catch(() => undefined);
+    for (const backfill of data.backfills) {
+      if (backfill.completed_at === null) {
+        await this.cancelBackfillViaApi(backfill.id);
+      }
+    }
+  }
 
-    await this.pauseButton.click();
-    await responsePromise;
+  public async cancelBackfillViaApi(backfillId: number): Promise<void> {
+    const response = await 
this.page.request.put(`${baseUrl}/api/v2/backfills/${backfillId}/cancel`, {
+      timeout: 30_000,
+    });
 
-    // Wait for aria-label to change
-    const expectedLabel = wasPaused ? "Pause backfill" : "Unpause backfill";
+    expect([200, 409]).toContain(response.status());
+  }
 
-    await 
expect(this.page.locator(`button[aria-label="${expectedLabel}"]`)).toBeVisible({
 timeout: 10_000 });
+  public async clickCancelButton(): Promise<void> {
+    await this.cancelButton.click({ timeout: 10_000 });
+    await expect(this.cancelButton).not.toBeVisible({ timeout: 15_000 });
   }
 
-  public async createBackfill(dagName: string, options: 
CreateBackfillOptions): Promise<void> {
-    const { fromDate, reprocessBehavior, toDate } = options;
+  /** Create a backfill through the UI dialog. Returns the backfill ID. Caller 
must ensure no active backfills exist. */
+  public async createBackfill(dagName: string, options: 
CreateBackfillOptions): Promise<number> {
+    const { fromDate, reprocessBehavior = "none", toDate } = options;
+
+    const uiFromDate = fromDate.slice(0, 16);
+    const uiToDate = toDate.slice(0, 16);
 
     await this.navigateToDagDetail(dagName);
-    await this.waitForNoActiveBackfill();
     await this.openBackfillDialog();
 
     await this.backfillFromDateInput.click();
-    await this.backfillFromDateInput.fill(fromDate);
-    await this.backfillFromDateInput.dispatchEvent("change");
+    await this.backfillFromDateInput.fill(uiFromDate);
+    await this.backfillFromDateInput.press("Tab");
 
     await this.backfillToDateInput.click();
-    await this.backfillToDateInput.fill(toDate);
-    await this.backfillToDateInput.dispatchEvent("change");
-
-    await this.page.waitForTimeout(500);
+    await this.backfillToDateInput.fill(uiToDate);
+    await this.backfillToDateInput.press("Tab");
 
     await this.selectReprocessBehavior(reprocessBehavior);
 
-    const runsWillBeTriggered = this.page.locator("text=/\\d+ runs? will be 
triggered/");
-    const noRunsMatching = this.page.locator("text=/No runs matching/");
+    const runsWillBeTriggered = this.page.getByText(/\d+ runs? will be 
triggered/);
+    const noRunsMatching = this.page.getByText(/No runs matching/);
 
     await expect(runsWillBeTriggered.or(noRunsMatching)).toBeVisible({ 
timeout: 20_000 });
 
-    let previousText = "";
-    let stableCount = 0;
-
-    while (stableCount < 3) {
-      await this.page.waitForTimeout(500);
-      const currentText = (await 
runsWillBeTriggered.or(noRunsMatching).textContent()) ?? "";
-
-      if (currentText === previousText) {
-        stableCount++;
-      } else {
-        stableCount = 0;
-        previousText = currentText;
-      }
-    }
-
-    const hasRuns = await runsWillBeTriggered.isVisible();
-
-    if (!hasRuns) {
+    if (await noRunsMatching.isVisible()) {
       await this.page.keyboard.press("Escape");
 
-      return;
+      throw new Error(
+        `No runs matching: dag=${dagName}, from=${fromDate}, to=${toDate}, 
reprocess=${reprocessBehavior}`,
+      );
     }
 
-    await expect(this.backfillRunButton).toBeVisible({ timeout: 20_000 });
     await expect(this.backfillRunButton).toBeEnabled({ timeout: 10_000 });
-    await this.backfillRunButton.scrollIntoViewIfNeeded();
 
     const responsePromise = this.page.waitForResponse(
       (res) =>
         res.url().includes("/backfills") &&
         !res.url().includes("/dry_run") &&
         res.request().method() === "POST",
-      { timeout: 60_000 },
+      { timeout: 30_000 },
     );
 
-    await this.backfillRunButton.click({ timeout: 20_000 });
+    await this.backfillRunButton.click();
 
     const apiResponse = await responsePromise;
     const status = apiResponse.status();
 
-    if (status === 409) {
-      await this.page.keyboard.press("Escape");
-      await this.waitForBackdropClosed();
-      await this.waitForNoActiveBackfill();
-
-      return this.createBackfill(dagName, options);
-    }
-
     if (status < 200 || status >= 300) {
-      const body = await apiResponse.text().catch(() => "unknown error");
+      const body = await apiResponse.text().catch(() => "unknown");
+
+      await this.page.keyboard.press("Escape");
 
       throw new Error(`Backfill creation failed with status ${status}: 
${body}`);
     }
 
-    const isClosed = await this.backfillRunButton
-      .waitFor({ state: "hidden", timeout: 60_000 })
-      .then(() => true)
-      .catch(() => false);
+    const data = (await apiResponse.json()) as BackfillApiResponse;
 
-    if (!isClosed) {
-      await this.page.keyboard.press("Escape");
-    }
+    return data.id;
+  }
 
-    await this.waitForBackdropClosed();
+  /** Create a backfill via API. On 409, cancels active backfills and retries 
once. */
+  public async createBackfillViaApi(dagId: string, options: 
CreateBackfillOptions): Promise<number> {
+    const { fromDate, maxActiveRuns, reprocessBehavior = "none", toDate } = 
options;
 
-    return;
-  }
+    const body: Record<string, unknown> = {
+      dag_id: dagId,
+      from_date: fromDate,
+      reprocess_behavior: reprocessBehavior,
+      to_date: toDate,
+    };
 
-  public async findBackfillRowByDateRange(
-    identifier: BackfillRowIdentifier,
-    timeout: number = 180_000,
-  ): Promise<Locator> {
-    const { fromDate: expectedFrom, toDate: expectedTo } = identifier;
+    if (maxActiveRuns !== undefined) {
+      body.max_active_runs = maxActiveRuns;
+    }
 
-    await this.backfillsTable.waitFor({ state: "visible", timeout: 10_000 });
-    await this.waitForTableDataLoaded();
+    const response = await 
this.page.request.post(`${baseUrl}/api/v2/backfills`, {
+      data: body,
+      headers: { "Content-Type": "application/json" },
+      timeout: 30_000,
+    });
 
-    const columnMap = await this.getColumnIndexMap();
-    const fromIndex = BackfillPage.findColumnIndex(columnMap, ["From", 
"table.from"]);
-    const toIndex = BackfillPage.findColumnIndex(columnMap, ["To", 
"table.to"]);
+    if (response.status() === 409) {
+      await this.cancelAllActiveBackfillsViaApi(dagId);
+      await this.waitForNoActiveBackfillViaApi(dagId, 30_000);
+      const retryResponse = await 
this.page.request.post(`${baseUrl}/api/v2/backfills`, {
+        data: body,
+        headers: { "Content-Type": "application/json" },
+        timeout: 30_000,
+      });
 
-    if (fromIndex === -1 || toIndex === -1) {
-      const availableColumns = [...columnMap.keys()].join(", ");
+      expect(retryResponse.ok()).toBe(true);
 
-      throw new Error(
-        `Required columns "From" and/or "To" not found. Available columns: 
[${availableColumns}]`,
-      );
+      return ((await retryResponse.json()) as BackfillApiResponse).id;
     }
 
-    let foundRow: Locator | undefined;
+    expect(response.ok()).toBe(true);
 
-    await expect(async () => {
-      await this.page.reload();
-      await this.backfillsTable.waitFor({ state: "visible", timeout: 10_000 });
-      await this.waitForTableDataLoaded();
+    return ((await response.json()) as BackfillApiResponse).id;
+  }
 
-      const rows = this.page.locator("table tbody tr");
-      const rowCount = await rows.count();
+  /**
+   * Create a backfill and immediately pause it. Retries the full create+pause
+   * cycle up to 3 times to handle the race where the scheduler completes the
+   * backfill before the pause call lands.
+   */
+  public async createPausedBackfillViaApi(dagId: string, options: 
CreateBackfillOptions): Promise<number> {
+    for (let attempt = 0; attempt < 3; attempt++) {
+      const backfillId = await this.createBackfillViaApi(dagId, {
+        ...options,
+        maxActiveRuns: 1,
+      });
+
+      const paused = await this.pauseBackfillViaApi(backfillId);
+
+      if (paused) {
+        return backfillId;
+      }
 
-      for (let i = 0; i < rowCount; i++) {
-        const row = rows.nth(i);
-        const cells = row.locator("td");
-        const fromCell = (await cells.nth(fromIndex).textContent()) ?? "";
-        const toCell = (await cells.nth(toIndex).textContent()) ?? "";
+      // Backfill completed before we could pause — cancel and retry.
+      await this.cancelAllActiveBackfillsViaApi(dagId);
+      await this.waitForNoActiveBackfillViaApi(dagId, 30_000);
+    }
 
-        if (datesMatch(fromCell, expectedFrom) && datesMatch(toCell, 
expectedTo)) {
-          foundRow = row;
+    throw new Error(`Failed to create a paused backfill for ${dagId} after 3 
attempts`);
+  }
 
-          return;
-        }
-      }
+  public async findBackfillRowByDateRange(
+    identifier: BackfillRowIdentifier,
+    timeout: number = 120_000,
+  ): Promise<{ columnMap: Map<string, number>; row: Locator }> {
+    const { fromDate: expectedFrom, toDate: expectedTo } = identifier;
+
+    let foundRow: Locator | undefined;
+    let foundColumnMap: Map<string, number> | undefined;
+
+    await expect
+      .poll(
+        async () => {
+          try {
+            if (!(await this.backfillsTable.isVisible())) {
+              return false;
+            }
+
+            const headers = this.backfillsTable.locator("thead th");
+
+            if (!(await headers.first().isVisible())) {
+              return false;
+            }
+
+            const headerTexts = await headers.allTextContents();
+            const columnMap = new Map(headerTexts.map((text, index) => 
[text.trim(), index]));
+            const fromIndex = columnMap.get("From");
+            const toIndex = columnMap.get("To");
+
+            if (fromIndex === undefined || toIndex === undefined) {
+              return false;
+            }
+
+            const rows = this.backfillsTable.locator("tbody tr");
+            const rowCount = await rows.count();
+
+            for (let i = 0; i < rowCount; i++) {
+              const row = rows.nth(i);
+              const cells = row.locator("td");
+              const fromCell = ((await cells.nth(fromIndex).textContent()) ?? 
"").slice(0, 10);
+              const toCell = ((await cells.nth(toIndex).textContent()) ?? 
"").slice(0, 10);
+
+              if (fromCell === expectedFrom.slice(0, 10) && toCell === 
expectedTo.slice(0, 10)) {
+                foundRow = row;
+                foundColumnMap = columnMap;
+
+                return true;
+              }
+            }
+
+            return false;
+          } catch (error: unknown) {
+            console.warn("findBackfillRowByDateRange poll error:", error);
+
+            return false;
+          }
+        },
+        {
+          intervals: [2000, 5000],
+          message: `Backfill row with dates ${expectedFrom} ~ ${expectedTo} 
not found in table`,
+          timeout,
+        },
+      )
+      .toBeTruthy();
 
-      throw new Error("Backfill not yet visible");
-    }).toPass({ timeout });
+    if (!foundRow || !foundColumnMap) {
+      throw new Error(`Backfill row with dates ${expectedFrom} ~ ${expectedTo} 
not found`);
+    }
 
-    // toPass() guarantees foundRow is set when it succeeds
-    return foundRow as Locator;
+    return { columnMap: foundColumnMap, row: foundRow };
   }
 
   public async getBackfillDetailsByDateRange(identifier: 
BackfillRowIdentifier): Promise<BackfillDetails> {
-    const row = await this.findBackfillRowByDateRange(identifier);
+    const { columnMap, row } = await 
this.findBackfillRowByDateRange(identifier);
     const cells = row.locator("td");
-    const columnMap = await this.getColumnIndexMap();
-
-    const fromIndex = BackfillPage.findColumnIndex(columnMap, ["From", 
"table.from"]);
-    const toIndex = BackfillPage.findColumnIndex(columnMap, ["To", 
"table.to"]);
-    const reprocessIndex = BackfillPage.findColumnIndex(columnMap, [
-      "Reprocess Behavior",
-      "backfill.reprocessBehavior",
-    ]);
-    const createdAtIndex = BackfillPage.findColumnIndex(columnMap, ["Created 
at", "table.createdAt"]);
 
-    const [fromDate, toDate, reprocessBehavior, createdAt] = await 
Promise.all([
-      cells.nth(fromIndex === -1 ? 0 : fromIndex).textContent(),
-      cells.nth(toIndex === -1 ? 1 : toIndex).textContent(),
-      cells.nth(reprocessIndex === -1 ? 2 : reprocessIndex).textContent(),
-      cells.nth(createdAtIndex === -1 ? 3 : createdAtIndex).textContent(),
+    const fromIndex = getColumnIndex(columnMap, "From");
+    const toIndex = getColumnIndex(columnMap, "To");
+    const reprocessIndex = getColumnIndex(columnMap, "Reprocess Behavior");
+    const createdAtIndex = getColumnIndex(columnMap, "Created at");
+    const completedAtIndex = getColumnIndex(columnMap, "Completed at");
+
+    const [fromDate, toDate, reprocessBehavior, createdAt, completedAt] = 
await Promise.all([
+      cells.nth(fromIndex).textContent(),
+      cells.nth(toIndex).textContent(),
+      cells.nth(reprocessIndex).textContent(),
+      cells.nth(createdAtIndex).textContent(),
+      cells.nth(completedAtIndex).textContent(),
     ]);
 
     return {
+      completedAt: (completedAt ?? "").trim(),
       createdAt: (createdAt ?? "").trim(),
       fromDate: (fromDate ?? "").trim(),
       reprocessBehavior: (reprocessBehavior ?? "").trim(),
@@ -313,164 +366,129 @@ export class BackfillPage extends BasePage {
     };
   }
 
-  public async getBackfillsTableRows(): Promise<number> {
-    const rows = this.page.locator("table tbody tr");
-
-    try {
-      await rows.first().waitFor({ state: "visible", timeout: 5000 });
-    } catch {
-      return 0;
-    }
-
-    return await rows.count();
-  }
-
-  public async getBackfillStatus(rowIndex: number = 0): Promise<string> {
-    const row = this.page.locator("table tbody tr").nth(rowIndex);
-
-    await expect(row).toBeVisible({ timeout: 10_000 });
-
-    const headers = this.page.locator("table thead th");
-    const headerTexts = await headers.allTextContents();
-    const completedAtIndex = headerTexts.findIndex((text) => 
text.toLowerCase().includes("completed"));
-
-    if (completedAtIndex !== -1) {
-      const completedCell = row.locator("td").nth(completedAtIndex);
-      const completedText = ((await completedCell.textContent()) ?? "").trim();
-
-      return completedText ? "Completed" : "Running";
-    }
-
-    return "Running";
-  }
-
   public getColumnHeader(columnName: string): Locator {
-    return this.page.locator(`th:has-text("${columnName}")`);
-  }
-
-  public async getColumnIndexMap(): Promise<Map<string, number>> {
-    const headers = this.page.locator("table thead th");
-
-    await headers.first().waitFor({ state: "visible", timeout: 10_000 });
-    const headerTexts = await headers.allTextContents();
-
-    return new Map(headerTexts.map((text, index) => [text.trim(), index]));
+    return this.backfillsTable.getByRole("columnheader", { name: columnName });
   }
 
   public getFilterButton(): Locator {
-    return this.page.locator(
-      'button[aria-label*="Filter table columns"], button:has-text("Filter 
table columns")',
-    );
+    return this.page.getByRole("button", { name: /filter table columns/i });
   }
 
   public async getTableColumnCount(): Promise<number> {
-    const headers = this.page.locator("table thead th");
-
-    return await headers.count();
-  }
-
-  public async isBackfillPaused(): Promise<boolean> {
-    await expect(this.pauseButton).toBeVisible({ timeout: 10_000 });
-    const ariaLabel = await this.pauseButton.getAttribute("aria-label");
-
-    return Boolean(ariaLabel?.toLowerCase().includes("unpause"));
+    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: 20_000 });
+    await expect(this.backfillsTable).toBeVisible({ timeout: 15_000 });
   }
 
   public async navigateToDagDetail(dagName: string): Promise<void> {
     await this.navigateTo(BackfillPage.getDagDetailUrl(dagName));
-    await expect(this.triggerButton).toBeVisible({ timeout: 30_000 });
+    await expect(this.triggerButton).toBeVisible({ timeout: 15_000 });
   }
 
   public async openBackfillDialog(): Promise<void> {
-    await expect(this.triggerButton).toBeVisible({ timeout: 20_000 });
-    await this.triggerButton.click();
-
-    await expect(this.backfillModeRadio).toBeVisible({ timeout: 20_000 });
-    await this.backfillModeRadio.click();
-
-    await expect(this.backfillFromDateInput).toBeVisible({ timeout: 20_000 });
+    await this.triggerButton.click({ timeout: 15_000 });
+    await this.backfillModeRadio.click({ timeout: 10_000 });
+    await expect(this.backfillFromDateInput).toBeVisible({ timeout: 10_000 });
   }
 
   public async openFilterMenu(): Promise<void> {
-    const filterButton = this.getFilterButton();
-
-    await filterButton.click();
-
-    const filterMenu = this.page.locator('[role="menu"]');
-
-    await filterMenu.waitFor({ state: "visible", timeout: 5000 });
-  }
-
-  public async selectReprocessBehavior(behavior: ReprocessBehavior): 
Promise<void> {
-    const behaviorLabels: Record<ReprocessBehavior, string> = {
-      "All Runs": "All Runs",
-      "Missing and Errored Runs": "Missing and Errored Runs",
-      "Missing Runs": "Missing Runs",
-    };
-
-    const label = behaviorLabels[behavior];
-    const radioItem = this.page.locator(`label:has-text("${label}")`).first();
-
-    await radioItem.waitFor({ state: "visible", timeout: 5000 });
-    await radioItem.click();
-  }
-
-  public async toggleColumn(columnName: string): Promise<void> {
-    const menuItem = 
this.page.locator(`[role="menuitem"]:has-text("${columnName}")`);
-
-    await menuItem.click();
+    await this.getFilterButton().click();
+    await expect(this.page.getByRole("menu")).toBeVisible({ timeout: 5000 });
   }
 
-  public async waitForBackdropClosed(timeout: number = 30_000): Promise<void> {
-    const backdrop = this.page.locator('[data-part="backdrop"]');
+  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,
+      });
 
-    await expect(async () => {
-      const count = await backdrop.count();
+      if (response.ok()) {
+        return true;
+      }
 
-      if (count === 0) {
-        return;
+      // 409 means the backfill already completed — not retriable.
+      if (response.status() === 409) {
+        return false;
       }
 
-      const state = await backdrop.getAttribute("data-state");
+      await this.page.waitForTimeout(2000);
+    }
 
-      if (state !== "closed") {
-        throw new Error("Backdrop still open");
-      }
-    }).toPass({ timeout });
+    return false;
   }
 
-  public async waitForNoActiveBackfill(timeout: number = 300_000): 
Promise<void> {
-    const { page, triggerButton } = this;
-    const backfillInProgress = page.locator('text="Backfill in progress:"');
+  public async selectReprocessBehavior(behavior: ReprocessBehaviorApi): 
Promise<void> {
+    const label = REPROCESS_API_TO_UI[behavior];
 
-    await expect(async () => {
-      await page.reload();
-      await page.waitForLoadState("domcontentloaded", { timeout: 30_000 });
-      await triggerButton.waitFor({ state: "visible", timeout: 30_000 });
-
-      const isVisible = await backfillInProgress.isVisible();
+    await this.page.locator(`label:has-text("${label}")`).first().click({ 
timeout: 5000 });
+  }
 
-      if (isVisible) {
-        throw new Error("Backfill still in progress");
-      }
-    }).toPass({ intervals: [5000, 10_000, 15_000], timeout });
+  public async toggleColumn(columnName: string): Promise<void> {
+    await this.page.getByRole("menuitem", { name: columnName }).click();
   }
 
-  public async waitForTableDataLoaded(): Promise<void> {
-    const firstCell = this.page.locator("table tbody tr:first-child 
td:first-child");
+  public async togglePauseState(): Promise<void> {
+    await this.pauseOrUnpauseButton.click({ timeout: 10_000 });
+  }
 
-    await expect(firstCell).toBeVisible({ timeout: 30_000 });
-    await expect(async () => {
-      const text = await firstCell.textContent();
+  public async waitForBackfillComplete(backfillId: number, timeout: number = 
120_000): Promise<void> {
+    await expect
+      .poll(
+        async () => {
+          try {
+            const response = await 
this.page.request.get(`${baseUrl}/api/v2/backfills/${backfillId}`, {
+              timeout: 30_000,
+            });
+
+            if (!response.ok()) {
+              return false;
+            }
+            const data = (await response.json()) as BackfillApiResponse;
+
+            return data.completed_at !== null;
+          } catch {
+            return false;
+          }
+        },
+        {
+          intervals: [2000, 5000, 10_000],
+          message: `Backfill ${backfillId} did not complete within 
${timeout}ms`,
+          timeout,
+        },
+      )
+      .toBeTruthy();
+  }
 
-      if (text === null || text.trim() === "") {
-        throw new Error("Table data still loading");
-      }
-    }).toPass({ timeout: 30_000 });
+  public async waitForNoActiveBackfillViaApi(dagId: string, timeout: number = 
120_000): Promise<void> {
+    await expect
+      .poll(
+        async () => {
+          try {
+            const response = await this.page.request.get(
+              `${baseUrl}/api/v2/backfills?dag_id=${dagId}&limit=100`,
+              { timeout: 30_000 },
+            );
+
+            if (!response.ok()) {
+              return false;
+            }
+            const data = (await response.json()) as BackfillListApiResponse;
+
+            return data.backfills.every((b) => b.completed_at !== null);
+          } catch {
+            return false;
+          }
+        },
+        {
+          intervals: [2000, 5000, 10_000],
+          message: `Active backfills for Dag ${dagId} did not clear within 
${timeout}ms`,
+          timeout,
+        },
+      )
+      .toBeTruthy();
   }
 }
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 f9abad46ab3..8babe2f9513 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
@@ -18,253 +18,234 @@
  */
 import { test, expect } from "@playwright/test";
 import { testConfig, AUTH_FILE } from "playwright.config";
-import { BackfillPage } from "tests/e2e/pages/BackfillPage";
-
-const getPastDate = (daysAgo: number): string => {
-  const date = new Date();
-
-  date.setDate(date.getDate() - daysAgo);
-  date.setHours(0, 0, 0, 0);
-
-  return date.toISOString().slice(0, 16);
+import { BackfillPage, REPROCESS_API_TO_UI } from 
"tests/e2e/pages/BackfillPage";
+import type { ReprocessBehaviorApi } from "tests/e2e/pages/BackfillPage";
+
+// Fixed past dates avoid non-determinism from relative date calculations.
+// Controls tests use wide, non-overlapping ranges so the scheduler cannot
+// complete the backfill before the test interacts with it.
+const FIXED_DATES = {
+  controls: {
+    cancel: { from: "2014-01-01T00:00:00Z", to: "2015-01-01T00:00:00Z" },
+    cancelledNoResume: { from: "2016-01-01T00:00:00Z", to: 
"2017-01-01T00:00:00Z" },
+    resumePause: { from: "2012-01-01T00:00:00Z", to: "2013-01-01T00:00:00Z" },
+  },
+  set1: { from: "2020-01-01T00:00:00Z", to: "2020-01-02T00:00:00Z" },
+  set2: { from: "2020-02-01T00:00:00Z", to: "2020-02-03T00:00:00Z" },
+  set3: { from: "2020-03-01T00:00:00Z", to: "2020-03-04T00:00:00Z" },
 };
 
-test.describe("Backfill creation and validation", () => {
-  // Serial mode ensures all tests run on one worker, preventing parallel 
beforeAll conflicts
+// All blocks share the same Dag, so they must run serially to avoid 
cross-block interference.
+test.describe("Backfill", () => {
   test.describe.configure({ mode: "serial" });
-  test.setTimeout(240_000);
 
-  const testDagId = testConfig.testDag.id;
+  test.describe("Backfill creation and validation", () => {
+    test.setTimeout(120_000);
 
-  const backfillConfigs = [
-    { behavior: "All Runs" as const, fromDate: getPastDate(5), toDate: 
getPastDate(4) },
-    { behavior: "Missing Runs" as const, fromDate: getPastDate(8), toDate: 
getPastDate(6) },
-    { behavior: "Missing and Errored Runs" as const, fromDate: 
getPastDate(12), toDate: getPastDate(10) },
-  ];
+    const testDagId = testConfig.testDag.id;
 
-  test.beforeAll(async ({ browser }) => {
-    test.setTimeout(600_000);
+    const backfillConfigs: Array<{
+      behavior: ReprocessBehaviorApi;
+      dates: { from: string; to: string };
+    }> = [
+      { behavior: "completed", dates: FIXED_DATES.set1 },
+      { behavior: "none", dates: FIXED_DATES.set2 },
+      { behavior: "failed", dates: FIXED_DATES.set3 },
+    ];
 
-    const context = await browser.newContext({ storageState: AUTH_FILE });
-    const page = await context.newPage();
-    const setupBackfillPage = new BackfillPage(page);
+    test.beforeAll(async ({ browser }) => {
+      test.setTimeout(300_000);
 
-    for (const config of backfillConfigs) {
-      await setupBackfillPage.createBackfill(testDagId, {
-        fromDate: config.fromDate,
-        reprocessBehavior: config.behavior,
-        toDate: config.toDate,
-      });
+      const context = await browser.newContext({ storageState: AUTH_FILE });
+      const page = await context.newPage();
+      const setupPage = new BackfillPage(page);
 
-      // Wait for backfill to complete on Dag detail page (where the banner is 
visible)
-      await setupBackfillPage.navigateToDagDetail(testDagId);
-      await setupBackfillPage.waitForNoActiveBackfill();
-    }
+      await setupPage.navigateToDagDetail(testDagId);
+      await setupPage.cancelAllActiveBackfillsViaApi(testDagId);
 
-    await context.close();
-  });
+      for (const config of backfillConfigs) {
+        const backfillId = await setupPage.createBackfill(testDagId, {
+          fromDate: config.dates.from,
+          reprocessBehavior: config.behavior,
+          toDate: config.dates.to,
+        });
 
-  test("verify backfill with 'all runs' behavior", async ({ page }) => {
-    const backfillPage = new BackfillPage(page);
+        await setupPage.waitForBackfillComplete(backfillId);
+      }
 
-    await backfillPage.navigateToBackfillsTab(testDagId);
-
-    const config = backfillConfigs[0]!; // All Runs
-
-    const backfillDetails = await backfillPage.getBackfillDetailsByDateRange({
-      fromDate: config.fromDate,
-      toDate: config.toDate,
+      await context.close();
     });
 
-    expect(backfillDetails.fromDate.slice(0, 
10)).toEqual(config.fromDate.slice(0, 10));
-    expect(backfillDetails.toDate.slice(0, 10)).toEqual(config.toDate.slice(0, 
10));
-
-    expect(backfillDetails.createdAt).not.toEqual("");
-    expect(backfillDetails.reprocessBehavior).toEqual("All Runs");
-    const status = await backfillPage.getBackfillStatus();
-
-    expect(status).not.toEqual("");
-  });
-
-  test("verify backfill with 'missing runs' behavior", async ({ page }) => {
-    const backfillPage = new BackfillPage(page);
+    test.afterAll(async ({ browser }) => {
+      const context = await browser.newContext({ storageState: AUTH_FILE });
+      const page = await context.newPage();
+      const cleanupPage = new BackfillPage(page);
 
-    await backfillPage.navigateToBackfillsTab(testDagId);
-
-    const config = backfillConfigs[1]!;
-
-    const backfillDetails = await backfillPage.getBackfillDetailsByDateRange({
-      fromDate: config.fromDate,
-      toDate: config.toDate,
+      await cleanupPage.cancelAllActiveBackfillsViaApi(testDagId);
+      await context.close();
     });
 
-    expect(backfillDetails.fromDate.slice(0, 
10)).toEqual(config.fromDate.slice(0, 10));
-    expect(backfillDetails.toDate.slice(0, 10)).toEqual(config.toDate.slice(0, 
10));
-
-    expect(backfillDetails.createdAt).not.toEqual("");
-    expect(backfillDetails.reprocessBehavior).toEqual("Missing Runs");
-    const status = await backfillPage.getBackfillStatus();
-
-    expect(status).not.toEqual("");
-  });
+    for (const config of backfillConfigs) {
+      test(`verify backfill with '${REPROCESS_API_TO_UI[config.behavior]}' 
behavior`, async ({ page }) => {
+        const backfillPage = new BackfillPage(page);
 
-  test("verify backfill with 'missing and errored runs' behavior", async ({ 
page }) => {
-    const backfillPage = new BackfillPage(page);
+        await backfillPage.navigateToBackfillsTab(testDagId);
 
-    await backfillPage.navigateToBackfillsTab(testDagId);
+        const details = await backfillPage.getBackfillDetailsByDateRange({
+          fromDate: config.dates.from,
+          toDate: config.dates.to,
+        });
 
-    const config = backfillConfigs[2]!;
+        expect(details.fromDate.slice(0, 
10)).toEqual(config.dates.from.slice(0, 10));
+        expect(details.toDate.slice(0, 10)).toEqual(config.dates.to.slice(0, 
10));
+        expect(details.createdAt).not.toEqual("");
+        expect(details.completedAt).not.toEqual("");
+        
expect(details.reprocessBehavior).toEqual(REPROCESS_API_TO_UI[config.behavior]);
+      });
+    }
 
-    const backfillDetails = await backfillPage.getBackfillDetailsByDateRange({
-      fromDate: config.fromDate,
-      toDate: config.toDate,
-    });
+    test("Verify backfill table filters", async ({ page }) => {
+      const backfillPage = new BackfillPage(page);
 
-    expect(backfillDetails.fromDate.slice(0, 
10)).toEqual(config.fromDate.slice(0, 10));
-    expect(backfillDetails.toDate.slice(0, 10)).toEqual(config.toDate.slice(0, 
10));
+      await backfillPage.navigateToBackfillsTab(testDagId);
 
-    expect(backfillDetails.createdAt).not.toEqual("");
-    expect(backfillDetails.reprocessBehavior).toEqual("Missing and Errored 
Runs");
-    const status = await backfillPage.getBackfillStatus();
+      const initialColumnCount = await backfillPage.getTableColumnCount();
 
-    expect(status).not.toEqual("");
-  });
+      expect(initialColumnCount).toBeGreaterThan(0);
+      await expect(backfillPage.getFilterButton()).toBeVisible();
 
-  test("Verify backfill table filters", async ({ page }) => {
-    const backfillPage = new BackfillPage(page);
+      await backfillPage.openFilterMenu();
 
-    await backfillPage.navigateToBackfillsTab(testDagId);
+      const filterMenuItems = page.getByRole("menuitem");
+      const filterMenuCount = await filterMenuItems.count();
 
-    const initialColumnCount = await backfillPage.getTableColumnCount();
+      expect(filterMenuCount).toBeGreaterThan(0);
 
-    expect(initialColumnCount).toBeGreaterThan(0);
-    await expect(backfillPage.getFilterButton()).toBeVisible();
+      const firstMenuItem = filterMenuItems.first();
+      const columnToToggle = (await firstMenuItem.textContent())?.trim() ?? "";
 
-    await backfillPage.openFilterMenu();
+      expect(columnToToggle).not.toBe("");
 
-    const filterMenuItems = backfillPage.page.locator('[role="menuitem"]');
-    const filterMenuCount = await filterMenuItems.count();
+      await backfillPage.toggleColumn(columnToToggle);
+      await page.keyboard.press("Escape");
 
-    expect(filterMenuCount).toBeGreaterThan(0);
+      await 
expect(backfillPage.getColumnHeader(columnToToggle)).not.toBeVisible();
 
-    const firstMenuItem = filterMenuItems.first();
-    const columnToToggle = (await firstMenuItem.textContent())?.trim() ?? "";
+      const newColumnCount = await backfillPage.getTableColumnCount();
 
-    expect(columnToToggle).not.toBe("");
+      expect(newColumnCount).toBeLessThan(initialColumnCount);
 
-    await backfillPage.toggleColumn(columnToToggle);
-    await backfillPage.backfillsTable.click({ position: { x: 5, y: 5 } });
+      await backfillPage.openFilterMenu();
+      await backfillPage.toggleColumn(columnToToggle);
+      await page.keyboard.press("Escape");
 
-    await 
expect(backfillPage.getColumnHeader(columnToToggle)).not.toBeVisible();
+      await expect(backfillPage.getColumnHeader(columnToToggle)).toBeVisible();
 
-    const newColumnCount = await backfillPage.getTableColumnCount();
+      const finalColumnCount = await backfillPage.getTableColumnCount();
 
-    expect(newColumnCount).toBeLessThan(initialColumnCount);
+      expect(finalColumnCount).toBe(initialColumnCount);
+    });
+  });
 
-    await backfillPage.openFilterMenu();
-    await backfillPage.toggleColumn(columnToToggle);
-    await backfillPage.backfillsTable.click({ position: { x: 5, y: 5 } });
+  test.describe("validate date range", () => {
+    test.setTimeout(30_000);
 
-    await expect(backfillPage.getColumnHeader(columnToToggle)).toBeVisible();
+    const testDagId = testConfig.testDag.id;
 
-    const finalColumnCount = await backfillPage.getTableColumnCount();
+    test("verify date range selection (start date, end date)", async ({ page 
}) => {
+      const backfillPage = new BackfillPage(page);
 
-    expect(finalColumnCount).toBe(initialColumnCount);
+      await backfillPage.navigateToDagDetail(testDagId);
+      await backfillPage.openBackfillDialog();
+      await backfillPage.backfillFromDateInput.fill("2025-01-10T00:00");
+      await backfillPage.backfillToDateInput.fill("2025-01-01T00:00");
+      await expect(backfillPage.backfillDateError).toBeVisible();
+    });
   });
-});
 
-test.describe("validate date range", () => {
-  test.setTimeout(60_000);
+  test.describe("Backfill pause, resume, and cancel controls", () => {
+    test.describe.configure({ mode: "serial" });
+    test.setTimeout(120_000);
 
-  const testDagId = testConfig.testDag.id;
+    const testDagId = testConfig.testDag.id;
 
-  test("verify date range selection (start date, end date)", async ({ page }) 
=> {
-    const fromDate = getPastDate(1);
-    const toDate = getPastDate(7);
-    const backfillPage = new BackfillPage(page);
+    let backfillPage: BackfillPage;
 
-    await backfillPage.navigateToDagDetail(testDagId);
-    await backfillPage.openBackfillDialog();
-    await backfillPage.backfillFromDateInput.fill(fromDate);
-    await backfillPage.backfillToDateInput.fill(toDate);
-    await expect(backfillPage.backfillDateError).toBeVisible();
-  });
-});
+    test.beforeEach(async ({ page }) => {
+      backfillPage = new BackfillPage(page);
+      await backfillPage.cancelAllActiveBackfillsViaApi(testDagId);
+      await backfillPage.waitForNoActiveBackfillViaApi(testDagId, 30_000);
+    });
 
-test.describe("Backfill pause, resume, and cancel controls", () => {
-  test.describe.configure({ mode: "serial" });
-  test.setTimeout(180_000);
+    test.afterEach(async () => {
+      await backfillPage.cancelAllActiveBackfillsViaApi(testDagId);
+    });
 
-  const testDagId = testConfig.testDag.id;
-  const controlFromDate = getPastDate(90);
-  const controlToDate = getPastDate(30);
+    test("verify pause and resume backfill", async () => {
+      const dates = FIXED_DATES.controls.resumePause;
 
-  let backfillPage: BackfillPage;
+      // Create + pause atomically to eliminate race with scheduler.
+      await backfillPage.createPausedBackfillViaApi(testDagId, {
+        fromDate: dates.from,
+        reprocessBehavior: "completed",
+        toDate: dates.to,
+      });
 
-  test.beforeEach(async ({ page }) => {
-    backfillPage = new BackfillPage(page);
-    await backfillPage.navigateToDagDetail(testDagId);
+      // Navigate to verify UI reflects the paused state, then test toggle 
cycle.
+      await backfillPage.navigateToDagDetail(testDagId);
+      await expect(backfillPage.unpauseButton).toBeVisible({ timeout: 15_000 
});
 
-    if (await backfillPage.cancelButton.isVisible({ timeout: 5000 }).catch(() 
=> false)) {
-      await backfillPage.clickCancelButton();
-    }
+      await backfillPage.togglePauseState();
+      await expect(backfillPage.pauseButton).toBeVisible({ timeout: 10_000 });
 
-    await backfillPage.createBackfill(testDagId, {
-      fromDate: controlFromDate,
-      reprocessBehavior: "All Runs",
-      toDate: controlToDate,
+      await backfillPage.togglePauseState();
+      await expect(backfillPage.unpauseButton).toBeVisible({ timeout: 10_000 
});
     });
 
-    await expect(async () => {
-      await backfillPage.page.reload();
-      await expect(backfillPage.triggerButton).toBeVisible({ timeout: 10_000 
});
-      await expect(backfillPage.pauseButton).toBeVisible({ timeout: 5000 });
-    }).toPass({ timeout: 60_000 });
-  });
-
-  test.afterEach(async () => {
-    await backfillPage.navigateToDagDetail(testDagId);
-    if (await backfillPage.cancelButton.isVisible({ timeout: 5000 }).catch(() 
=> false)) {
-      await backfillPage.clickCancelButton();
-    }
-  });
+    test("verify cancel backfill", async () => {
+      const dates = FIXED_DATES.controls.cancel;
 
-  test("verify pause and resume backfill", async () => {
-    await backfillPage.clickPauseButton();
-    expect(await backfillPage.isBackfillPaused()).toBe(true);
+      // Create + pause atomically to eliminate race with scheduler.
+      await backfillPage.createPausedBackfillViaApi(testDagId, {
+        fromDate: dates.from,
+        reprocessBehavior: "completed",
+        toDate: dates.to,
+      });
 
-    await backfillPage.clickPauseButton();
-    expect(await backfillPage.isBackfillPaused()).toBe(false);
-  });
+      await backfillPage.navigateToDagDetail(testDagId);
+      await expect(backfillPage.unpauseButton).toBeVisible({ timeout: 15_000 
});
 
-  test("verify cancel backfill", async () => {
-    await backfillPage.clickCancelButton();
-    await expect(backfillPage.pauseButton).not.toBeVisible({ timeout: 10_000 
});
-    await expect(backfillPage.cancelButton).not.toBeVisible({ timeout: 10_000 
});
-  });
+      await backfillPage.clickCancelButton();
+      await expect(backfillPage.pauseOrUnpauseButton).not.toBeVisible({ 
timeout: 10_000 });
+      await expect(backfillPage.cancelButton).not.toBeVisible({ timeout: 
10_000 });
+    });
 
-  test("verify cancelled backfill cannot be resumed", async () => {
-    await backfillPage.clickCancelButton();
-    await expect(backfillPage.pauseButton).not.toBeVisible({ timeout: 10_000 
});
+    test("verify cancelled backfill cannot be resumed", async () => {
+      const dates = FIXED_DATES.controls.cancelledNoResume;
 
-    await backfillPage.page.reload();
-    await expect(backfillPage.triggerButton).toBeVisible({ timeout: 30_000 });
-    await expect(backfillPage.pauseButton).not.toBeVisible({ timeout: 10_000 
});
+      // Setup via API: create and cancel directly (UI cancel is tested above).
+      const backfillId = await backfillPage.createBackfillViaApi(testDagId, {
+        fromDate: dates.from,
+        maxActiveRuns: 1,
+        reprocessBehavior: "completed",
+        toDate: dates.to,
+      });
 
-    await backfillPage.navigateToBackfillsTab(testDagId);
+      await backfillPage.cancelBackfillViaApi(backfillId);
 
-    const row = await backfillPage.findBackfillRowByDateRange({
-      fromDate: controlFromDate,
-      toDate: controlToDate,
-    });
+      // Verify UI: no pause/resume controls visible after cancel.
+      await backfillPage.navigateToDagDetail(testDagId);
+      await expect(backfillPage.pauseOrUnpauseButton).not.toBeVisible({ 
timeout: 10_000 });
 
-    await expect(row).toBeVisible();
+      // Verify: completedAt is set in backfills table.
+      await backfillPage.navigateToBackfillsTab(testDagId);
 
-    const columnMap = await backfillPage.getColumnIndexMap();
-    const completedAtIndex = BackfillPage.findColumnIndex(columnMap, 
["Completed at", "table.completedAt"]);
-    const completedAtCell = row.locator("td").nth(completedAtIndex);
-    const completedAtText = await completedAtCell.textContent();
+      const details = await backfillPage.getBackfillDetailsByDateRange({
+        fromDate: dates.from,
+        toDate: dates.to,
+      });
 
-    expect(completedAtText?.trim()).not.toBe("");
+      expect(details.completedAt).not.toBe("");
+    });
   });
 });


Reply via email to