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 30a9509a888 feat: Improve Playwright test patterns in
dag-runs-tab.spec.ts (#63189)
30a9509a888 is described below
commit 30a9509a8881a2e9fc761ca15b59fd3c203e4f60
Author: Desel72 <[email protected]>
AuthorDate: Wed Mar 11 23:06:08 2026 -0500
feat: Improve Playwright test patterns in dag-runs-tab.spec.ts (#63189)
* feat: Improve Playwright test patterns in dag-runs-tab.spec.t
* Check CI test
* remove package-lock
* Fix Prettier formatting in navigateToDag
---
.../airflow/ui/tests/e2e/pages/DagRunsTabPage.ts | 55 +++++++++++++---------
.../ui/tests/e2e/specs/dag-runs-tab.spec.ts | 2 +-
2 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsTabPage.ts
b/airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsTabPage.ts
index f89130f0a20..61360f923e5 100644
--- a/airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsTabPage.ts
+++ b/airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsTabPage.ts
@@ -27,27 +27,31 @@ export class DagRunsTabPage extends BasePage {
public constructor(page: Page) {
super(page);
- this.markRunAsButton =
page.locator('[data-testid="mark-run-as-button"]').first();
- this.runsTable = page.locator('[data-testid="table-list"]');
- this.tableRows = this.runsTable.locator("tbody tr");
- this.triggerButton = page.locator('[data-testid="trigger-dag-button"]');
+ this.markRunAsButton = page.getByTestId("mark-run-as-button").first();
+ this.runsTable = page.getByTestId("table-list");
+ this.tableRows = this.runsTable.locator("tbody").getByRole("row");
+ this.triggerButton = page.getByTestId("trigger-dag-button");
+ }
+
+ private static escapeRegExp(value: string): string {
+ return value.replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&");
}
public async clickRunAndVerifyDetails(): Promise<void> {
- const firstRunLink =
this.tableRows.first().locator("a[href*='/runs/']").first();
+ const firstRunLink = this.tableRows.first().getByRole("link").first();
await expect(firstRunLink).toBeVisible({ timeout: 10_000 });
await firstRunLink.click();
- await this.page.waitForURL(/.*\/dags\/.*\/runs\/[^/]+$/, { timeout: 15_000
});
+ await expect(this.page).toHaveURL(/.*\/dags\/.*\/runs\/[^/]+$/, { timeout:
15_000 });
await expect(this.markRunAsButton).toBeVisible({ timeout: 10_000 });
}
public async clickRunsTab(): Promise<void> {
- const runsTab = this.page.locator('a[href$="/runs"]');
+ const runsTab = this.page.getByRole("link", { exact: true, name: "Runs" });
await expect(runsTab).toBeVisible({ timeout: 10_000 });
await runsTab.click();
- await this.page.waitForURL(/.*\/dags\/[^/]+\/runs/, { timeout: 15_000 });
+ await expect(this.page).toHaveURL(/.*\/dags\/[^/]+\/runs/, { timeout:
15_000 });
await this.waitForRunsTableToLoad();
}
@@ -56,12 +60,12 @@ export class DagRunsTabPage extends BasePage {
currentUrl.searchParams.set("state", state.toLowerCase());
await this.navigateTo(currentUrl.pathname + currentUrl.search);
- await this.page.waitForURL(/.*state=.*/, { timeout: 15_000 });
+ await expect(this.page).toHaveURL(/.*state=.*/, { timeout: 15_000 });
await this.waitForRunsTableToLoad();
}
public async markRunAs(state: "failed" | "success"): Promise<void> {
- const stateBadge =
this.page.locator('[data-testid="state-badge"]').first();
+ const stateBadge = this.page.getByTestId("state-badge").first();
await expect(stateBadge).toBeVisible({ timeout: 10_000 });
const currentState = await stateBadge.textContent();
@@ -73,7 +77,7 @@ export class DagRunsTabPage extends BasePage {
await expect(this.markRunAsButton).toBeVisible({ timeout: 10_000 });
await this.markRunAsButton.click();
- const stateOption =
this.page.locator(`[data-testid="mark-run-as-${state}"]`);
+ const stateOption = this.page.getByTestId(`mark-run-as-${state}`);
await expect(stateOption).toBeVisible({ timeout: 5000 });
await stateOption.click();
@@ -95,13 +99,18 @@ export class DagRunsTabPage extends BasePage {
public async navigateToDag(dagId: string): Promise<void> {
await this.navigateTo(`/dags/${dagId}`);
- await this.page.waitForURL(`**/dags/${dagId}**`, { timeout: 15_000 });
+ await expect(this.page).toHaveURL(new
RegExp(`/dags/${DagRunsTabPage.escapeRegExp(dagId)}`), {
+ timeout: 15_000,
+ });
await expect(this.triggerButton).toBeVisible({ timeout: 10_000 });
}
public async navigateToRunDetails(dagId: string, runId: string):
Promise<void> {
await this.navigateTo(`/dags/${dagId}/runs/${runId}`);
- await this.page.waitForURL(`**/dags/${dagId}/runs/${runId}**`, { timeout:
15_000 });
+ await expect(this.page).toHaveURL(
+ new
RegExp(`/dags/${DagRunsTabPage.escapeRegExp(dagId)}/runs/${DagRunsTabPage.escapeRegExp(runId)}`),
+ { timeout: 15_000 },
+ );
await expect(this.markRunAsButton).toBeVisible({ timeout: 15_000 });
}
@@ -110,7 +119,7 @@ export class DagRunsTabPage extends BasePage {
currentUrl.searchParams.set("run_id_pattern", pattern);
await this.navigateTo(currentUrl.pathname + currentUrl.search);
- await this.page.waitForURL(/.*run_id_pattern=.*/, { timeout: 15_000 });
+ await expect(this.page).toHaveURL(/.*run_id_pattern=.*/, { timeout: 15_000
});
await this.waitForRunsTableToLoad();
}
@@ -156,7 +165,7 @@ export class DagRunsTabPage extends BasePage {
const rowCount = await rows.count();
for (let i = 0; i < Math.min(rowCount, 5); i++) {
- const stateBadge = rows.nth(i).locator('[data-testid="state-badge"]');
+ const stateBadge = rows.nth(i).getByTestId("state-badge");
await expect(stateBadge).toBeVisible();
await expect(stateBadge).toContainText(expectedState, { ignoreCase: true
});
@@ -168,12 +177,12 @@ export class DagRunsTabPage extends BasePage {
await expect(firstRow).toBeVisible({ timeout: 10_000 });
- const runIdLink = firstRow.locator("a[href*='/runs/']").first();
+ const runIdLink = firstRow.getByRole("link").first();
await expect(runIdLink).toBeVisible();
await expect(runIdLink).not.toBeEmpty();
- const stateBadge = firstRow.locator('[data-testid="state-badge"]');
+ const stateBadge = firstRow.getByTestId("state-badge");
await expect(stateBadge).toBeVisible();
@@ -183,10 +192,10 @@ export class DagRunsTabPage extends BasePage {
}
public async verifyRunsExist(): Promise<void> {
- const runLinks = this.runsTable.locator("a[href*='/runs/']");
+ const firstRow = this.tableRows.first();
- await expect(runLinks.first()).toBeVisible({ timeout: 30_000 });
- await expect(runLinks).not.toHaveCount(0);
+ await expect(firstRow).toBeVisible({ timeout: 30_000 });
+ await expect(this.tableRows).not.toHaveCount(0);
}
public async verifySearchResults(pattern: string): Promise<void> {
@@ -199,7 +208,7 @@ export class DagRunsTabPage extends BasePage {
const count = await rows.count();
for (let i = 0; i < Math.min(count, 5); i++) {
- const runIdLink = rows.nth(i).locator("a[href*='/runs/']").first();
+ const runIdLink = rows.nth(i).getByRole("link").first();
await expect(runIdLink).toContainText(pattern, { ignoreCase: true });
}
@@ -208,9 +217,9 @@ export class DagRunsTabPage extends BasePage {
public async waitForRunsTableToLoad(): Promise<void> {
await expect(this.runsTable).toBeVisible({ timeout: 10_000 });
- const dataLink = this.runsTable.locator("a[href*='/runs/']").first();
+ const firstRow = this.tableRows.first();
const noDataMessage = this.page.getByText(/no.*dag.*runs.*found/i);
- await expect(dataLink.or(noDataMessage)).toBeVisible({ timeout: 30_000 });
+ await expect(firstRow.or(noDataMessage)).toBeVisible({ timeout: 30_000 });
}
}
diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/dag-runs-tab.spec.ts
b/airflow-core/src/airflow/ui/tests/e2e/specs/dag-runs-tab.spec.ts
index d9aef74f547..5c0edc5bd99 100644
--- a/airflow-core/src/airflow/ui/tests/e2e/specs/dag-runs-tab.spec.ts
+++ b/airflow-core/src/airflow/ui/tests/e2e/specs/dag-runs-tab.spec.ts
@@ -59,7 +59,7 @@ test.describe("DAG Runs Tab", () => {
await dagRunsTabPage.navigateToDag(testDagId);
await dagRunsTabPage.clickRunsTab();
- await expect(dagRunsTabPage.page).toHaveURL(/\/dags\/.*\/runs/);
+ await expect(dagRunsTabPage.page).toHaveURL(/.*\/dags\/[^/]+\/runs/);
});
test("verify run details display correctly", async () => {