Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 0 additions & 43 deletions airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,49 +82,6 @@ export class DagRunsPage extends BasePage {
expect(await dataLinks.count()).toBeGreaterThan(0);
}

/**
* Verify pagination controls and navigation
*/
public async verifyPagination(limit: number): Promise<void> {
await this.navigateTo(`${DagRunsPage.dagRunsUrl}?offset=0&limit=${limit}`);
await this.page.waitForURL(/.*limit=/, { timeout: 10_000 });
await this.page.waitForLoadState("networkidle");
await this.dagRunsTable.waitFor({ state: "visible", timeout: 10_000 });

const dataLinks = this.dagRunsTable.locator("a[href*='/dags/']");

await expect(dataLinks.first()).toBeVisible({ timeout: 30_000 });

const rows = this.dagRunsTable.locator("tbody tr");

expect(await rows.count()).toBeGreaterThan(0);

const paginationNav = this.page.locator('nav[aria-label="pagination"], [role="navigation"]');

await expect(paginationNav.first()).toBeVisible({ timeout: 10_000 });

const page1Button = this.page.getByRole("button", { name: /page 1|^1$/ });

await expect(page1Button.first()).toBeVisible({ timeout: 5000 });

const page2Button = this.page.getByRole("button", { name: /page 2|^2$/ });
const hasPage2 = await page2Button
.first()
.isVisible()
.catch(() => false);

if (hasPage2) {
await page2Button.first().click();
await this.page.waitForLoadState("networkidle");
await this.dagRunsTable.waitFor({ state: "visible", timeout: 10_000 });

const dataLinksPage2 = this.dagRunsTable.locator("a[href*='/dags/']");
const noDataMessage = this.page.locator("text=/no.*data|no.*runs|no.*results/i");

await expect(dataLinksPage2.first().or(noDataMessage.first())).toBeVisible({ timeout: 30_000 });
}
}

/**
* Verify that run details are displayed in the table row
*/
Expand Down
78 changes: 0 additions & 78 deletions airflow-core/src/airflow/ui/tests/e2e/pages/DagRunsTabPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,57 +21,18 @@ import { BasePage } from "tests/e2e/pages/BasePage";

export class DagRunsTabPage extends BasePage {
public readonly markRunAsButton: Locator;
public readonly nextPageButton: Locator;
public readonly prevPageButton: Locator;
public readonly runsTable: Locator;
public readonly tableRows: Locator;
public readonly triggerButton: Locator;

private currentDagId?: string;
private currentLimit?: number;

public constructor(page: Page) {
super(page);
this.markRunAsButton = page.locator('[data-testid="mark-run-as-button"]').first();
this.nextPageButton = page.locator('[data-testid="next"]');
this.prevPageButton = page.locator('[data-testid="prev"]');
this.runsTable = page.locator('[data-testid="table-list"]');
this.tableRows = this.runsTable.locator("tbody tr");
this.triggerButton = page.locator('[data-testid="trigger-dag-button"]');
}

public async clickNextPage(): Promise<void> {
await this.waitForRunsTableToLoad();
const firstRunLink = this.tableRows.first().locator("a[href*='/runs/']").first();

await expect(firstRunLink).toBeVisible();
const firstRunId = await firstRunLink.textContent();

if (firstRunId === null || firstRunId === "") {
throw new Error("Could not get first run ID before pagination");
}

await this.nextPageButton.click();
await expect(this.tableRows.first()).not.toContainText(firstRunId, { timeout: 10_000 });
await this.ensureUrlParams();
}

public async clickPrevPage(): Promise<void> {
await this.waitForRunsTableToLoad();
const firstRunLink = this.tableRows.first().locator("a[href*='/runs/']").first();

await expect(firstRunLink).toBeVisible();
const firstRunId = await firstRunLink.textContent();

if (firstRunId === null || firstRunId === "") {
throw new Error("Could not get first run ID before pagination");
}

await this.prevPageButton.click();
await expect(this.tableRows.first()).not.toContainText(firstRunId, { timeout: 10_000 });
await this.ensureUrlParams();
}

public async clickRunAndVerifyDetails(): Promise<void> {
const firstRunLink = this.tableRows.first().locator("a[href*='/runs/']").first();

Expand All @@ -90,17 +51,6 @@ export class DagRunsTabPage extends BasePage {
await this.waitForRunsTableToLoad();
}

public async clickRunsTabWithPageSize(dagId: string, pageSize: number): Promise<void> {
this.currentDagId = dagId;
this.currentLimit = pageSize;

await this.navigateTo(`/dags/${dagId}/runs?offset=0&limit=${pageSize}`);
await this.page.waitForURL(/.*\/dags\/[^/]+\/runs.*offset=0&limit=/, {
timeout: 15_000,
});
await this.waitForRunsTableToLoad();
}

public async filterByState(state: string): Promise<void> {
const currentUrl = new URL(this.page.url());

Expand All @@ -110,12 +60,6 @@ export class DagRunsTabPage extends BasePage {
await this.waitForRunsTableToLoad();
}

public async getRowCount(): Promise<number> {
await this.waitForRunsTableToLoad();

return this.tableRows.count();
}

public async markRunAs(state: "failed" | "success"): Promise<void> {
const stateBadge = this.page.locator('[data-testid="state-badge"]').first();

Expand Down Expand Up @@ -269,26 +213,4 @@ export class DagRunsTabPage extends BasePage {

await expect(dataLink.or(noDataMessage)).toBeVisible({ timeout: 30_000 });
}

private async ensureUrlParams(): Promise<void> {
if (this.currentLimit === undefined || this.currentDagId === undefined) {
return;
}

const currentUrl = this.page.url();
const url = new URL(currentUrl);
const hasLimit = url.searchParams.has("limit");
const hasOffset = url.searchParams.has("offset");

if (hasLimit && !hasOffset) {
url.searchParams.set("offset", "0");
await this.navigateTo(url.pathname + url.search);
await this.waitForRunsTableToLoad();
} else if (!hasLimit && !hasOffset) {
url.searchParams.set("offset", "0");
url.searchParams.set("limit", String(this.currentLimit));
await this.navigateTo(url.pathname + url.search);
await this.waitForRunsTableToLoad();
}
}
}
76 changes: 0 additions & 76 deletions airflow-core/src/airflow/ui/tests/e2e/pages/DagsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,11 @@ export class DagsPage extends BasePage {
public readonly failedFilter: Locator;
public readonly needsReviewFilter: Locator;
public readonly operatorFilter: Locator;
public readonly paginationNextButton: Locator;
public readonly paginationPrevButton: Locator;
public readonly queuedFilter: Locator;
public readonly retriesFilter: Locator;
public readonly runningFilter: Locator;
public readonly searchBox: Locator;
public readonly searchInput: Locator;
public readonly sortSelect: Locator;
public readonly stateElement: Locator;
public readonly successFilter: Locator;
public readonly tableViewButton: Locator;
Expand All @@ -61,8 +58,6 @@ export class DagsPage extends BasePage {
// page trigger button has visible text or is icon-only.
this.confirmButton = page.locator('button:has-text("Trigger")').last();
this.stateElement = page.locator('*:has-text("State") + *').first();
this.paginationNextButton = page.locator('[data-testid="next"]');
this.paginationPrevButton = page.locator('[data-testid="prev"]');
this.searchBox = page.getByRole("textbox", { name: /search/i });
this.searchInput = page.getByPlaceholder("Search DAGs");
this.operatorFilter = page.getByRole("combobox").filter({ hasText: /operator/i });
Expand All @@ -71,8 +66,6 @@ export class DagsPage extends BasePage {
// View toggle buttons
this.cardViewButton = page.locator('button[aria-label="Show card view"]');
this.tableViewButton = page.locator('button[aria-label="Show table view"]');
// Sort select (card view only)
this.sortSelect = page.locator('[data-testid="sort-by-select"]');
// Status filter buttons
this.successFilter = page.locator('button:has-text("Success")');
this.failedFilter = page.locator('button:has-text("Failed")');
Expand Down Expand Up @@ -106,75 +99,6 @@ export class DagsPage extends BasePage {
await this.waitForDagList();
}

/**
* Click next page button and wait for list to change
*/
public async clickNextPage(): Promise<void> {
const initialDagNames = await this.getDagNames();

// Set up API listener before action
const responsePromise = this.page
.waitForResponse((resp) => resp.url().includes("/dags") && resp.status() === 200, {
timeout: 30_000,
})
.catch(() => {
/* API might be cached */
});

await this.paginationNextButton.click();

// Wait for API response
await responsePromise;

// Wait for UI to actually change (increased timeout for slower browsers like Firefox)
await expect
.poll(() => this.getDagNames(), {
message: "List did not update after clicking next page",
timeout: 30_000,
})
.not.toEqual(initialDagNames);

await this.waitForDagList();
}

/**
* Click previous page button and wait for list to change
*/
public async clickPrevPage(): Promise<void> {
const initialDagNames = await this.getDagNames();

// Set up API listener before action
const responsePromise = this.page
.waitForResponse((resp) => resp.url().includes("/dags") && resp.status() === 200, {
timeout: 30_000,
})
.catch(() => {
/* API might be cached */
});

await this.paginationPrevButton.click();

// Wait for API response
await responsePromise;

// Wait for UI to actually change (increased timeout for slower browsers like Firefox)
await expect
.poll(() => this.getDagNames(), {
message: "List did not update after clicking prev page",
timeout: 30_000,
})
.not.toEqual(initialDagNames);

await this.waitForDagList();
}

/**
* Click sort select (only works in card view)
*/
public async clickSortSelect(): Promise<void> {
await this.sortSelect.click();
}

public async filterByOperator(operator: string): Promise<void> {
await this.selectDropdownOption(this.operatorFilter, operator);
}
Expand Down
Loading