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
58 changes: 22 additions & 36 deletions airflow-core/src/airflow/ui/tests/e2e/pages/ProvidersPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,70 +16,56 @@
* specific language governing permissions and limitations
* under the License.
*/
import { expect } from "@playwright/test";
import type { Locator, Page } from "@playwright/test";

import { BasePage } from "./BasePage";

export class ProvidersPage extends BasePage {
public readonly adminMenuButton: Locator;
public readonly heading: Locator;
public readonly providersMenuItem: Locator;
public readonly rows: Locator;
public readonly table: Locator;

public constructor(page: Page) {
super(page);

this.adminMenuButton = page.getByRole("button", { name: /^admin$/i });
this.heading = page.getByRole("heading", { name: /^providers$/i });
this.providersMenuItem = page.getByRole("menuitem", { name: /^providers$/i });
this.table = page.getByTestId("table-list");
this.rows = this.table.locator("tbody tr").filter({
has: page.locator("td"),
});
}

public async getRowCount(): Promise<number> {
return this.rows.count();
}

public async getRowDetails(index: number) {
const row = this.rows.nth(index);
const cells = row.locator("td");

const pkg = await cells.nth(0).locator("a").textContent();
const ver = await cells.nth(1).textContent();
const desc = await cells.nth(2).textContent();

return {
description: (desc ?? "").trim(),
packageName: (pkg ?? "").trim(),
version: (ver ?? "").trim(),
};
public descriptionCellAt(index: number): Locator {
return this.rows.nth(index).locator("td").nth(2);
}

public async navigate(): Promise<void> {
await this.navigateTo("/providers");
}

public async waitForLoad(): Promise<void> {
await this.table.waitFor({ state: "visible", timeout: 30_000 });
await this.waitForTableData();
public async navigateFromAdminMenu(): Promise<void> {
await this.navigateTo("/");
await this.adminMenuButton.click();
await expect(this.providersMenuItem).toBeVisible();
await this.providersMenuItem.click();
}

private async waitForTableData(): Promise<void> {
// Wait for actual data links to appear (not skeleton loaders)
await this.page.waitForFunction(
() => {
const table = document.querySelector('[data-testid="table-list"]');

if (!table) {
return false;
}
public packageLinkAt(index: number): Locator {
return this.rows.nth(index).locator("td").nth(0).getByRole("link");
}

// Check for actual links in tbody (real data, not skeleton)
const links = table.querySelectorAll("tbody tr td a");
public versionCellAt(index: number): Locator {
return this.rows.nth(index).locator("td").nth(1);
}

return links.length > 0;
},
undefined,
{ timeout: 30_000 },
);
public async waitForLoad(): Promise<void> {
await expect(this.table).toBeVisible({ timeout: 30_000 });
await expect(this.rows.first()).toBeVisible({ timeout: 30_000 });
Comment thread
choo121600 marked this conversation as resolved.
await expect(this.packageLinkAt(0)).toBeVisible({ timeout: 30_000 });
}
}
44 changes: 17 additions & 27 deletions airflow-core/src/airflow/ui/tests/e2e/specs/providers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,50 +21,40 @@ import { test, expect } from "@playwright/test";
import { ProvidersPage } from "../pages/ProvidersPage";

test.describe("Providers Page", () => {
let providers: ProvidersPage;
let providersPage: ProvidersPage;

test.beforeEach(async ({ page }) => {
providers = new ProvidersPage(page);
await providers.navigate();
await providers.waitForLoad();
providersPage = new ProvidersPage(page);
await providersPage.navigate();
await providersPage.waitForLoad();
});

test("verify providers page heading", async () => {
await expect(providers.heading).toBeVisible();
await expect(providersPage.heading).toBeVisible();
});

test("Verify Providers page is accessible via Admin menu", async ({ page }) => {
await page.goto("/");
await providersPage.navigateFromAdminMenu();
await providersPage.waitForLoad();

await page.getByRole("button", { name: /^admin$/i }).click();

// Click Providers
const providersItem = page.getByRole("menuitem", { name: /^providers$/i });

await expect(providersItem).toBeVisible();
await providersItem.click();

await providers.waitForLoad();
// Assert Providers page loaded
await expect(providers.heading).toBeVisible();
expect(await providers.getRowCount()).toBeGreaterThan(0);
await expect(page).toHaveURL(/\/providers$/);
await expect(providersPage.heading).toBeVisible();
await expect(providersPage.rows).not.toHaveCount(0);
});

test("Verify the providers list displays", async () => {
await expect(providers.table).toBeVisible();
await expect(providersPage.table).toBeVisible();
});

test("Verify package name, version, and description are not blank", async () => {
const count = await providers.getRowCount();

expect(count).toBeGreaterThan(0);
await expect(providersPage.rows).not.toHaveCount(0);

for (let i = 0; i < 2; i++) {
const { description, packageName, version } = await providers.getRowDetails(i);
const count = Math.min(await providersPage.rows.count(), 2);

expect(packageName).not.toEqual("");
expect(version).not.toEqual("");
expect(description).not.toEqual("");
for (let i = 0; i < count; i++) {
await expect(providersPage.packageLinkAt(i)).not.toBeEmpty();
await expect(providersPage.versionCellAt(i)).not.toBeEmpty();
await expect(providersPage.descriptionCellAt(i)).not.toBeEmpty();
}
});
});
Loading