This is an automated email from the ASF dual-hosted git repository. rahulvats pushed a commit to branch fix-e2e-tests in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 6dfbc9ff16471e79df52d8a7ff608e573a5a2673 Author: vatsrahul1001 <[email protected]> AuthorDate: Wed Feb 25 17:41:19 2026 +0530 fix flaky tests and increase workers to 5 for CI --- airflow-core/src/airflow/ui/playwright.config.ts | 4 +- .../src/airflow/ui/tests/e2e/pages/BackfillPage.ts | 2 +- .../airflow/ui/tests/e2e/pages/ConnectionsPage.ts | 75 ++++++++++++++++------ .../airflow/ui/tests/e2e/pages/DagCalendarTab.ts | 13 ++-- .../src/airflow/ui/tests/e2e/pages/DagRunsPage.ts | 6 +- .../airflow/ui/tests/e2e/pages/DagRunsTabPage.ts | 24 +++---- .../src/airflow/ui/tests/e2e/pages/DagsPage.ts | 15 +++-- .../airflow/ui/tests/e2e/specs/backfill.spec.ts | 8 +-- .../airflow/ui/tests/e2e/specs/connections.spec.ts | 28 +++++--- .../ui/tests/e2e/specs/dag-audit-log.spec.ts | 4 +- .../ui/tests/e2e/specs/dag-grid-view.spec.ts | 2 +- .../airflow/ui/tests/e2e/specs/dag-runs.spec.ts | 1 + .../airflow/ui/tests/e2e/specs/events-page.spec.ts | 2 +- .../src/airflow/ui/tests/e2e/specs/pools.spec.ts | 1 + .../airflow/ui/tests/e2e/specs/task-logs.spec.ts | 6 +- .../airflow/ui/tests/e2e/specs/variable.spec.ts | 7 +- 16 files changed, 128 insertions(+), 70 deletions(-) diff --git a/airflow-core/src/airflow/ui/playwright.config.ts b/airflow-core/src/airflow/ui/playwright.config.ts index 2ca34e47ef6..fb8d6b8faf2 100644 --- a/airflow-core/src/airflow/ui/playwright.config.ts +++ b/airflow-core/src/airflow/ui/playwright.config.ts @@ -112,7 +112,7 @@ export default defineConfig({ timeout: 30_000, use: { - actionTimeout: 10_000, + actionTimeout: 30_000, baseURL: process.env.AIRFLOW_UI_BASE_URL ?? "http://localhost:28080", screenshot: "only-on-failure", trace: "on-first-retry", @@ -120,5 +120,5 @@ export default defineConfig({ viewport: undefined, }, - workers: process.env.CI !== undefined && process.env.CI !== "" ? 2 : undefined, + workers: process.env.CI !== undefined && process.env.CI !== "" ? 5 : undefined, }); 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..19f8d5e8a42 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/pages/BackfillPage.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/pages/BackfillPage.ts @@ -383,7 +383,7 @@ export class BackfillPage extends BasePage { 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: 60_000 }); } public async openBackfillDialog(): Promise<void> { diff --git a/airflow-core/src/airflow/ui/tests/e2e/pages/ConnectionsPage.ts b/airflow-core/src/airflow/ui/tests/e2e/pages/ConnectionsPage.ts index ebad0e1d2cf..24b07656698 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/pages/ConnectionsPage.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/pages/ConnectionsPage.ts @@ -104,11 +104,10 @@ export class ConnectionsPage extends BasePage { // Click the Add button to create a new connection public async clickAddButton(): Promise<void> { - await expect(this.addButton).toBeVisible({ timeout: 5000 }); - await expect(this.addButton).toBeEnabled({ timeout: 5000 }); + await expect(this.addButton).toBeVisible({ timeout: 10_000 }); + await expect(this.addButton).toBeEnabled({ timeout: 10_000 }); await this.addButton.click(); - // Wait for form to load - await expect(this.connectionForm).toBeVisible({ timeout: 10_000 }); + await expect(this.connectionForm).toBeVisible({ timeout: 30_000 }); } // Click edit button for a specific connection @@ -145,7 +144,23 @@ export class ConnectionsPage extends BasePage { // Create a new connection with full workflow public async createConnection(details: ConnectionDetails): Promise<void> { - await this.clickAddButton(); + await expect(async () => { + // Dismiss any open dialog before retrying + const closeButton = this.page.locator('[data-scope="dialog"] button[aria-label="Close"]'); + + if (await closeButton.isVisible({ timeout: 1000 }).catch(() => false)) { + await closeButton.click(); + await expect(this.connectionForm).not.toBeVisible({ timeout: 5000 }); + } + + await this.clickAddButton(); + + // Wait for the connection type select to be interactive (chakra-react-select) + const selectTrigger = this.getConnectionTypeSelectTrigger(); + + await expect(selectTrigger).toBeVisible({ timeout: 15_000 }); + }).toPass({ timeout: 60_000, intervals: [1_000, 2_000, 5_000] }); + await this.fillConnectionForm(details); await this.saveConnection(); await this.waitForConnectionsListLoad(); @@ -210,22 +225,7 @@ export class ConnectionsPage extends BasePage { } if (details.conn_type !== undefined && details.conn_type !== "") { - // Click the select field to open the dropdown - const selectCombobox = this.page.getByRole("combobox").first(); - - await expect(selectCombobox).toBeEnabled({ timeout: 25_000 }); - - await selectCombobox.click({ timeout: 3000 }); - - // Wait for options to appear and click the matching option - const option = this.page.getByRole("option", { name: new RegExp(details.conn_type, "i") }).first(); - - await option.click({ timeout: 2000 }).catch(() => { - // If option click fails, try typing in the input - if (details.conn_type !== undefined && details.conn_type !== "") { - void this.page.keyboard.type(details.conn_type); - } - }); + await this.selectConnectionType(details.conn_type); } if (details.host !== undefined && details.host !== "") { @@ -274,6 +274,39 @@ export class ConnectionsPage extends BasePage { } } + // Get the connection type select trigger (chakra-react-select custom component) + public getConnectionTypeSelectTrigger(): Locator { + const connTypeGroup = this.connectionForm + .locator("fieldset, [role='group']") + .filter({ hasText: /Connection Type/ }) + .first(); + + return connTypeGroup; + } + + public async selectConnectionType(connType: string): Promise<void> { + const connTypeGroup = this.getConnectionTypeSelectTrigger(); + + await expect(connTypeGroup).toBeVisible({ timeout: 30_000 }); + + // Wait for the loading spinner to disappear (connection types are fetched from API) + const spinner = this.connectionForm.locator('[data-testid="spinner"], .chakra-spinner').first(); + + await expect(spinner).toBeHidden({ timeout: 60_000 }).catch(() => {}); + + // Click on the select control area, using force to bypass any remaining overlay + const selectArea = connTypeGroup.locator("div").filter({ hasText: /Select Connection Type|Connection Type/i }).last(); + + await selectArea.click({ force: true, timeout: 10_000 }); + + await this.page.keyboard.type(connType, { delay: 50 }); + + const option = this.page.getByRole("option", { name: new RegExp(connType, "i") }).first(); + + await expect(option).toBeVisible({ timeout: 10_000 }); + await option.click(); + } + // Get connection count from current page public async getConnectionCount(): Promise<number> { const ids = await this.getConnectionIds(); diff --git a/airflow-core/src/airflow/ui/tests/e2e/pages/DagCalendarTab.ts b/airflow-core/src/airflow/ui/tests/e2e/pages/DagCalendarTab.ts index 15864274430..19d8101b04f 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/pages/DagCalendarTab.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/pages/DagCalendarTab.ts @@ -69,10 +69,15 @@ export class DagCalendarTab extends BasePage { for (let i = 0; i < count; i++) { const cell = this.activeCells.nth(i); - await cell.hover(); - await expect(this.tooltip).toBeVisible({ timeout: 20_000 }); - - const text = ((await this.tooltip.textContent()) ?? "").toLowerCase(); + let text = ""; + + await expect(async () => { + await this.page.mouse.move(0, 0); + await cell.hover({ force: true }); + await expect(this.tooltip).toBeVisible({ timeout: 5_000 }); + text = ((await this.tooltip.textContent({ timeout: 5_000 })) ?? "").toLowerCase(); + expect(text.length).toBeGreaterThan(0); + }).toPass({ timeout: 30_000, intervals: [500, 1_000, 2_000] }); if (text.includes("success")) states.push("success"); if (text.includes("failed")) states.push("failed"); diff --git a/airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsPage.ts b/airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsPage.ts index 8ace70b132e..b7448e1d45c 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsPage.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsPage.ts @@ -36,13 +36,13 @@ export class DagRunsPage extends BasePage { */ public async navigate(): Promise<void> { await this.navigateTo(DagRunsPage.dagRunsUrl); - await this.page.waitForURL(/.*dag_runs/, { timeout: 15_000 }); - await this.dagRunsTable.waitFor({ state: "visible", timeout: 10_000 }); + await this.page.waitForURL(/.*dag_runs/, { timeout: 30_000 }); + await this.dagRunsTable.waitFor({ state: "visible", timeout: 30_000 }); const dataLink = this.dagRunsTable.locator("a[href*='/dags/']").first(); const noDataMessage = this.page.locator('text="No Dag Runs found"'); - await expect(dataLink.or(noDataMessage)).toBeVisible({ timeout: 30_000 }); + await expect(dataLink.or(noDataMessage)).toBeVisible({ timeout: 60_000 }); } /** 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..108a1ee6450 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsTabPage.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsTabPage.ts @@ -36,10 +36,10 @@ export class DagRunsTabPage extends BasePage { public async clickRunAndVerifyDetails(): Promise<void> { const firstRunLink = this.tableRows.first().locator("a[href*='/runs/']").first(); - await expect(firstRunLink).toBeVisible({ timeout: 10_000 }); + await expect(firstRunLink).toBeVisible({ timeout: 30_000 }); await firstRunLink.click(); - await this.page.waitForURL(/.*\/dags\/.*\/runs\/[^/]+$/, { timeout: 15_000 }); - await expect(this.markRunAsButton).toBeVisible({ timeout: 10_000 }); + await this.page.waitForURL(/.*\/dags\/.*\/runs\/[^/]+$/, { timeout: 30_000 }); + await expect(this.markRunAsButton).toBeVisible({ timeout: 30_000 }); } public async clickRunsTab(): Promise<void> { @@ -84,7 +84,7 @@ export class DagRunsTabPage extends BasePage { const responsePromise = this.page.waitForResponse( (response) => response.url().includes("dagRuns") && response.request().method() === "PATCH", - { timeout: 10_000 }, + { timeout: 30_000 }, ); await confirmButton.click(); @@ -95,8 +95,8 @@ 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.triggerButton).toBeVisible({ timeout: 10_000 }); + await this.page.waitForURL(`**/dags/${dagId}**`, { timeout: 30_000 }); + await expect(this.triggerButton).toBeVisible({ timeout: 30_000 }); } public async navigateToRunDetails(dagId: string, runId: string): Promise<void> { @@ -115,16 +115,16 @@ export class DagRunsTabPage extends BasePage { } public async triggerDagRun(): Promise<string | undefined> { - await expect(this.triggerButton).toBeVisible({ timeout: 10_000 }); + await expect(this.triggerButton).toBeVisible({ timeout: 30_000 }); await this.triggerButton.click(); const dialog = this.page.getByRole("dialog"); - await expect(dialog).toBeVisible({ timeout: 8000 }); + await expect(dialog).toBeVisible({ timeout: 15_000 }); const confirmButton = dialog.getByRole("button", { name: "Trigger" }); - await expect(confirmButton).toBeVisible({ timeout: 5000 }); + await expect(confirmButton).toBeVisible({ timeout: 10_000 }); const responsePromise = this.page.waitForResponse( (response) => { @@ -133,7 +133,7 @@ export class DagRunsTabPage extends BasePage { return method === "POST" && url.includes("dagRuns") && !url.includes("hitlDetails"); }, - { timeout: 15_000 }, + { timeout: 30_000 }, ); await confirmButton.click(); @@ -206,11 +206,11 @@ export class DagRunsTabPage extends BasePage { } public async waitForRunsTableToLoad(): Promise<void> { - await expect(this.runsTable).toBeVisible({ timeout: 10_000 }); + await expect(this.runsTable).toBeVisible({ timeout: 30_000 }); const dataLink = this.runsTable.locator("a[href*='/runs/']").first(); const noDataMessage = this.page.getByText(/no.*dag.*runs.*found/i); - await expect(dataLink.or(noDataMessage)).toBeVisible({ timeout: 30_000 }); + await expect(dataLink.or(noDataMessage)).toBeVisible({ timeout: 60_000 }); } } diff --git a/airflow-core/src/airflow/ui/tests/e2e/pages/DagsPage.ts b/airflow-core/src/airflow/ui/tests/e2e/pages/DagsPage.ts index 5f510b797b1..9732f390759 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/pages/DagsPage.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/pages/DagsPage.ts @@ -258,6 +258,7 @@ export class DagsPage extends BasePage { */ public async navigateToDagDetail(dagName: string): Promise<void> { await this.navigateTo(DagsPage.getDagDetailUrl(dagName)); + await this.page.waitForLoadState("networkidle", { timeout: 60_000 }).catch(() => {}); } public async navigateToDagTasks(dagId: string): Promise<void> { @@ -339,7 +340,7 @@ export class DagsPage extends BasePage { */ public async triggerDag(dagName: string): Promise<string | null> { await this.navigateToDagDetail(dagName); - await expect(this.triggerButton).toBeVisible({ timeout: 10_000 }); + await expect(this.triggerButton).toBeVisible({ timeout: 30_000 }); await this.triggerButton.click(); const dagRunId = await this.handleTriggerDialog(); @@ -406,7 +407,7 @@ export class DagsPage extends BasePage { } await this.page.goto(DagsPage.getDagRunDetailsUrl(dagName, dagRunId), { - timeout: 15_000, + timeout: 30_000, waitUntil: "domcontentloaded", }); @@ -543,7 +544,7 @@ export class DagsPage extends BasePage { // Wait for any of these elements to appear await expect(cardList.or(tableList).or(noDagFound).or(fallbackTable)).toBeVisible({ - timeout: 30_000, + timeout: 60_000, }); // If empty state is shown, consider the list as successfully rendered @@ -554,7 +555,7 @@ export class DagsPage extends BasePage { // Wait for loading to complete (skeletons to disappear) const skeleton = this.page.locator('[data-testid="skeleton"]'); - await expect(skeleton).toHaveCount(0, { timeout: 30_000 }); + await expect(skeleton).toHaveCount(0, { timeout: 60_000 }); // Now wait for actual DAG content based on current view const isCardView = await cardList.isVisible().catch(() => false); @@ -563,17 +564,17 @@ export class DagsPage extends BasePage { // Card view: wait for dag-id elements const dagCards = this.page.locator('[data-testid="dag-id"]'); - await dagCards.first().waitFor({ state: "visible", timeout: 30_000 }); + await dagCards.first().waitFor({ state: "visible", timeout: 60_000 }); } else { // Table view: prefer table-list testid, fallback to any <table> element const rowsInTableList = tableList.locator("tbody tr"); if ((await rowsInTableList.count().catch(() => 0)) > 0) { - await rowsInTableList.first().waitFor({ state: "visible", timeout: 30_000 }); + await rowsInTableList.first().waitFor({ state: "visible", timeout: 60_000 }); } else { const anyTableRows = fallbackTable.locator("tbody tr"); - await anyTableRows.first().waitFor({ state: "visible", timeout: 30_000 }); + await anyTableRows.first().waitFor({ state: "visible", timeout: 60_000 }); } } } 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..cd2913ae3cb 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 @@ -193,7 +193,7 @@ test.describe("validate date range", () => { test.describe("Backfill pause, resume, and cancel controls", () => { test.describe.configure({ mode: "serial" }); - test.setTimeout(180_000); + test.setTimeout(300_000); const testDagId = testConfig.testDag.id; const controlFromDate = getPastDate(90); @@ -217,9 +217,9 @@ test.describe("Backfill pause, resume, and cancel controls", () => { 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 }); + await expect(backfillPage.triggerButton).toBeVisible({ timeout: 30_000 }); + await expect(backfillPage.pauseButton).toBeVisible({ timeout: 30_000 }); + }).toPass({ timeout: 180_000 }); }); test.afterEach(async () => { diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/connections.spec.ts b/airflow-core/src/airflow/ui/tests/e2e/specs/connections.spec.ts index 9d2493f8aab..59db6e22900 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/specs/connections.spec.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/specs/connections.spec.ts @@ -70,7 +70,10 @@ test.describe("Connections Page - List and Display", () => { test("should display connections with correct columns", async () => { await connectionsPage.navigate(); - // Check that we have at least one row + await expect + .poll(() => connectionsPage.getConnectionCount(), { timeout: 30_000 }) + .toBeGreaterThan(0); + const count = await connectionsPage.getConnectionCount(); expect(count).toBeGreaterThan(0); @@ -91,6 +94,7 @@ test.describe("Connections Page - List and Display", () => { }); test.describe("Connections Page - CRUD Operations", () => { + test.describe.configure({ mode: "serial" }); let connectionsPage: ConnectionsPage; const { baseUrl } = testConfig.connection; const timestamp = Date.now(); @@ -281,6 +285,10 @@ test.describe("Connections Page - Search and Filter", () => { test("should filter connections by search term", async () => { await connectionsPage.navigate(); + await expect + .poll(() => connectionsPage.getConnectionCount(), { timeout: 30_000 }) + .toBeGreaterThan(0); + const initialCount = await connectionsPage.getConnectionCount(); expect(initialCount).toBeGreaterThan(0); @@ -313,30 +321,30 @@ test.describe("Connections Page - Search and Filter", () => { test.setTimeout(120_000); await connectionsPage.navigate(); - const initialCount = await connectionsPage.getConnectionCount(); - - expect(initialCount).toBeGreaterThan(0); + await expect + .poll(() => connectionsPage.getConnectionCount(), { timeout: 30_000 }) + .toBeGreaterThan(0); - // Search for something await connectionsPage.searchConnections("production"); - // Wait for search results await expect .poll( async () => { const count = await connectionsPage.getConnectionCount(); - return count > 0; // Just verify we have some results + return count > 0; }, { intervals: [500], timeout: 10_000 }, ) .toBe(true); + const filteredCount = await connectionsPage.getConnectionCount(); + // Clear search await connectionsPage.searchConnections(""); - const finalCount = await connectionsPage.getConnectionCount(); - - expect(finalCount).toBeGreaterThanOrEqual(initialCount); + await expect + .poll(() => connectionsPage.getConnectionCount(), { timeout: 15_000 }) + .toBeGreaterThanOrEqual(filteredCount); }); }); diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/dag-audit-log.spec.ts b/airflow-core/src/airflow/ui/tests/e2e/specs/dag-audit-log.spec.ts index 2cf5f1c341c..10897ae1f35 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/specs/dag-audit-log.spec.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/specs/dag-audit-log.spec.ts @@ -31,7 +31,7 @@ test.describe("DAG Audit Log", () => { test.setTimeout(60_000); test.beforeAll(async ({ browser }) => { - test.setTimeout(3 * 60 * 1000); + test.setTimeout(5 * 60 * 1000); const context = await browser.newContext({ storageState: AUTH_FILE }); const page = await context.newPage(); const setupDagsPage = new DagsPage(page); @@ -54,7 +54,7 @@ test.describe("DAG Audit Log", () => { return rows.length >= minCount; }, expectedEventCount, - { timeout: 60_000 }, + { timeout: 120_000 }, ); await context.close(); diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/dag-grid-view.spec.ts b/airflow-core/src/airflow/ui/tests/e2e/specs/dag-grid-view.spec.ts index 15d0191a7c5..7c4fa2bce50 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/specs/dag-grid-view.spec.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/specs/dag-grid-view.spec.ts @@ -26,7 +26,7 @@ test.describe("DAG Grid View", () => { const testDagId = testConfig.testDag.id; test.beforeAll(async ({ browser }) => { - test.setTimeout(3 * 60 * 1000); + test.setTimeout(5 * 60 * 1000); const context = await browser.newContext({ storageState: AUTH_FILE }); const page = await context.newPage(); const setupDagsPage = new DagsPage(page); diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/dag-runs.spec.ts b/airflow-core/src/airflow/ui/tests/e2e/specs/dag-runs.spec.ts index 5567ba6d58b..2cce6645915 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/specs/dag-runs.spec.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/specs/dag-runs.spec.ts @@ -28,6 +28,7 @@ test.describe("DAG Runs Page", () => { const testDagId2 = "example_python_operator"; test.beforeAll(async ({ browser }) => { + test.setTimeout(3 * 60 * 1000); const context = await browser.newContext({ storageState: AUTH_FILE }); const page = await context.newPage(); const baseUrl = process.env.AIRFLOW_UI_BASE_URL ?? "http://localhost:8080"; diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/events-page.spec.ts b/airflow-core/src/airflow/ui/tests/e2e/specs/events-page.spec.ts index d8638e7026a..68c07ad0016 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/specs/events-page.spec.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/specs/events-page.spec.ts @@ -120,7 +120,7 @@ test.describe("Events with Generated Data", () => { for (const event of filteredEvents) { expect(event.toLowerCase()).toContain("cli"); } - }).toPass({ timeout: 20_000 }); + }).toPass({ timeout: 60_000 }); }); test("verify filter by DAG ID", async () => { diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/pools.spec.ts b/airflow-core/src/airflow/ui/tests/e2e/specs/pools.spec.ts index 93574487557..d7166960a9c 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/specs/pools.spec.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/specs/pools.spec.ts @@ -21,6 +21,7 @@ import { AUTH_FILE } from "playwright.config"; import { PoolsPage } from "tests/e2e/pages/PoolsPage"; test.describe("Pools Page", () => { + test.describe.configure({ mode: "serial" }); test.setTimeout(60_000); let poolsPage: PoolsPage; diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/task-logs.spec.ts b/airflow-core/src/airflow/ui/tests/e2e/specs/task-logs.spec.ts index f68881126e7..ee2bef7d278 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/specs/task-logs.spec.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/specs/task-logs.spec.ts @@ -78,7 +78,11 @@ test.describe("Verify task logs display", () => { await expect(virtualizedList).toBeVisible({ timeout: 30_000 }); - await expect(virtualizedList).toContainText(/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}]/); + const logItems = page.locator('[data-testid^="virtualized-item-"]'); + + await expect(logItems.first()).toBeVisible({ timeout: 30_000 }); + + await expect(virtualizedList).toContainText(/\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}]/, { timeout: 15_000 }); }); test("Verify log settings", async ({ page }) => { diff --git a/airflow-core/src/airflow/ui/tests/e2e/specs/variable.spec.ts b/airflow-core/src/airflow/ui/tests/e2e/specs/variable.spec.ts index d3498ab477b..4ed925c4de6 100644 --- a/airflow-core/src/airflow/ui/tests/e2e/specs/variable.spec.ts +++ b/airflow-core/src/airflow/ui/tests/e2e/specs/variable.spec.ts @@ -22,6 +22,7 @@ import { AUTH_FILE } from "playwright.config"; import { VariablePage } from "../pages/VariablePage"; test.describe("Variables Page", () => { + test.describe.configure({ mode: "serial" }); let variablesPage: VariablePage; let createVariables = 3; @@ -110,7 +111,11 @@ test.describe("Variables Page", () => { throw new Error("No variable available for edit test"); } - await variablesPage.rowByKey(target.key).getByRole("button", { name: /edit/i }).click(); + const targetRow = variablesPage.rowByKey(target.key); + + await expect(targetRow).toBeVisible({ timeout: 15_000 }); + await targetRow.scrollIntoViewIfNeeded(); + await targetRow.getByRole("button", { name: /edit/i }).click({ timeout: 15_000 }); await expect(page.getByRole("heading", { name: /edit/i })).toBeVisible();
