Repository: apache/airflow
File: airflow-core/src/airflow/ui/tests/e2e/pages/TaskInstancesPage.ts (TypeScript)

Code before:
          }
        }
      }
    }
  }

  /**
   * Verify that state filtering works correctly
   */
  public async verifyStateFiltering(expectedState: string): Promise<void> {
    await this.applyFilter("State", expectedState);

    await this.page.waitForURL(/.*state=.*/, { timeout: 10_000 });
    await this.page.waitForLoadState("networkidle");
    await expect(this.taskInstancesTable).toBeVisible();

    const url = this.page.url();

    expect(url).toContain("state=");

    const rowsAfterFilter = this.taskInstancesTable.locator(
      'tbody tr:not(.no-data), div[role="row"]:not(:first-child)',
    );
    const countAfter = await rowsAfterFilter.count();

    if (countAfter === 0) {
      const noDataMessage = this.page.locator("text=/No.*found/i, text=/No.*results/i, text=/Empty/i");

      if ((await noDataMessage.count()) > 0) {
        await expect(noDataMessage.first()).toBeVisible();
      }

      return;
    }

    const firstDataRow = rowsAfterFilter.first();

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

    const cellWithContent = firstDataRow.locator('td, div[role="cell"]').filter({ hasText: /.+/ });

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

    const stateBadges = this.taskInstancesTable.locator('[class*="badge"], [class*="Badge"]');

    await stateBadges.first().waitFor({ state: "visible", timeout: 10_000 });

    const badgeCount = await stateBadges.count();

    expect(badgeCount).toBeGreaterThan(0);


Review comment (suggestion):
should we use

await expect(dataLinks.first().or(noDataMessage.first())).toBeVisible({ timeout: 30_000 }); 

Code after:
   */
  public async verifyTaskDetailsDisplay(): Promise<void> {
    const firstRow = this.taskInstancesTable.locator("tbody tr, div[role='row']:not(:first-child)").first();

    const dagIdLink = firstRow.locator("a[href*='/dags/']").first();

    if ((await dagIdLink.count()) > 0) {
      await expect(dagIdLink).toBeVisible();
      expect((await dagIdLink.textContent())?.trim()).toBeTruthy();
    }

    const allCells = firstRow.locator('td, div[role="cell"]');
    const cellCount = await allCells.count();

    expect(cellCount).toBeGreaterThan(1);

    const runIdLink = firstRow.locator("a[href*='/runs/']").first();

    if ((await runIdLink.count()) > 0) {
      await expect(runIdLink).toBeVisible();
      expect((await runIdLink.textContent())?.trim()).toBeTruthy();
    }

    const stateBadge = firstRow.locator('[class*="badge"], [class*="Badge"], [class*="status"]');

    const hasStateBadge = (await stateBadge.count()) > 0;

    if (hasStateBadge) {
      await expect(stateBadge.first()).toBeVisible();
    } else {
      const allCellsForState = firstRow.locator('td, div[role="cell"]');

      expect(await allCellsForState.count()).toBeGreaterThan(2);
    }

    const timeElements = firstRow.locator("time");

    if ((await timeElements.count()) > 0) {
      await expect(timeElements.first()).toBeVisible();
    } else {
      const dateCells = firstRow.locator('td, div[role="cell"]');
      const dateCellCount = await dateCells.count();

      expect(dateCellCount).toBeGreaterThan(3);
    }
  }

  /**
   * Verify that task instances exist in the table
   */
  public async verifyTaskInstancesExist(): Promise<void> {