Files
Charon/docs/plans/archive/ci_test_cleanup_spec.md
2026-02-19 16:34:10 +00:00

4.0 KiB

CI/CD Test Remix & Stabilization Plan

Status: Draft Owner: DevOps / QA Context: Fixing flaky E2E tests in proxy-hosts.spec.ts identified in CI Remediation Report.

1. Problem Analysis

Symptoms

  1. "Add Proxy Host" Modal Failure: Test clicks "Add Proxy Host" but dialog doesn't appear.
  2. Empty State Detection Failure: Test asserts "Empty State OR Table" visible, but fails (neither visible).
  3. Spinner Timeouts: Loading state tests are flaky.

Root Cause

Mismatched Loading Indicators:

  • The test helper waitForLoadingComplete waits for .animate-spin (loading spinner).
  • The ProxyHosts page uses SkeletonTable (pulse animation) for its initial loading state.
  • Result: waitForLoadingComplete returns immediately because no spinner is found. The test proceeds while the Skeleton is still visible.
  • Impact:
    • Empty State Test: Fails because checking for EmptyState/Table happens while Skeleton is still rendered.
    • Add Host Test: The click might verify, but the page is currently rendering/hydrating/transitioning, causing flaky behavior or race conditions.

2. Remediation Specification

Objective

Make proxy-hosts.spec.ts robust by accurately detecting the page's "ready" state and using precise selectors.

Tasks

Phase 1: Selector Hardening

  • Target specific "Add" button: Use data-testid or precise hierarchy to distinguish the Header button from the Empty State button (though logic allows either, precision helps debugging).
  • Consolidate Button Interaction: Ensure we are waiting for the button to be interactive.

Phase 2: Loading State Logic Update

  • Detect Skeleton: Add logic to wait for SkeletonTable (or .animate-pulse, .skeleton) to disappear.
  • Update Test Flow:
    • beforeEach: Wait for Table OR Empty State to be visible (implies Skeleton is gone).
    • should show loading skeleton: Update to assert presence of role="status" or .animate-pulse selector instead of .animate-spin.

Phase 3: Empty State Verification

  • Explicit Assertion: Instead of catch(() => false), use expect(locator).toBeVisible() inside a test.step that handles the conditional logic gracefully (e.g., using Promise.race or checking count before assertion).
  • Wait for transition: Ensure test waits for the transition from loading=true to loading=false.

3. Implementation Steps

Step 1: Update tests/utils/wait-helpers.ts (Optional)

Consider adding waitForSkeletonComplete if this pattern is common. For now, local handling in proxy-hosts.spec.ts is sufficient.

Step 2: Rewrite tests/core/proxy-hosts.spec.ts

Modify beforeEach and specific tests:

// Proposed Change for beforeEach
test.beforeEach(async ({ page, adminUser }) => {
  await loginUser(page, adminUser);
  await page.goto('/proxy-hosts');

  // Wait for REAL content availability, bypassing Skeleton
  const table = page.getByRole('table');
  const emptyState = page.getByRole('heading', { name: 'No proxy hosts' });
  const addHostBtn = page.getByRole('button', { name: 'Add Proxy Host' }).first();

  // Wait for either table OR empty state to be visible
  await expect(async () => {
      const tableVisible = await table.isVisible();
      const emptyVisible = await emptyState.isVisible();
      expect(tableVisible || emptyVisible).toBeTruthy();
  }).toPass({ timeout: 10000 });

  await expect(addHostBtn).toBeVisible();
});

Step 3: Fix "Loading Skeleton" Test

Target the actual Skeleton element:

test('should show loading skeleton while fetching data', async ({ page }) => {
    await page.reload();
    // Verify Skeleton exists
    const skeleton = page.locator('.animate-pulse'); // or specific skeleton selector
    await expect(skeleton.first()).toBeVisible();

    // Then verify it disappears
    await expect(skeleton.first()).not.toBeVisible();
});

4. Verification

  1. Run npx playwright test tests/core/proxy-hosts.spec.ts --project=chromium
  2. Ensure 0% flake rate.