Ctrl K
ComunidadGuías…

tests/e2e/diff-rendering-observability.spec.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { expect, test } from "@playwright/test";
import { enableScopedE2EAuth, scopedPath } from "./helpers/auth";
import { emptyAutomationFailuresResponse } from "./helpers/activation-fixtures";
import {
  connectedUser,
  fulfillJson,
  mockBaseApp,
  modelId,
  repo,
} from "./helpers/diff-rendering-fixtures";

test("observability renders nested tool output diffs with the shared viewer", async ({
  page,
}) => {
  const now = new Date().toISOString();
  const patch = [
    "diff --git a/src/agent.ts b/src/agent.ts",
    "index 1111111..2222222 100644",
    "--- a/src/agent.ts",
    "+++ b/src/agent.ts",
    "@@ -1 +1 @@",
    "-export const mode = 'idle'",
    "+export const mode = 'ready'",
    "",
  ].join("\n");

  // Register the base mocks FIRST: Playwright matches routes in reverse
  // registration order (last registered wins), so the observability-specific
  // mocks below must come after mockBaseApp's empty-calls defaults.
  await enableScopedE2EAuth(page);
  await mockBaseApp(page);
  await page.route("**/api/realtime/events?*", (route) =>
    route.fulfill({ status: 204 })
  );

  await page.route("**/api/observability/calls*", (route) =>
    fulfillJson(route, {
      calls: [
        {
          id: "call-1",
          user_id: connectedUser.id,
          type: "chat",
          model: modelId,
          input_tokens: 10,
          output_tokens: 12,
          total_tokens: 22,
          duration_ms: 1200,
          started_at: now,
          completed_at: now,
          status: "success",
          error: null,
          conversation_id: "conversation-1",
          job_run_id: null,
          repo_id: repo.id,
          tool_calls_count: 1,
          tool_calls: [
            {
              name: "git_diff",
              input_preview: '{"repo":"acme/demo-app"}',
              input: { repo: repo.full_name },
              output_preview: "diff --git a/src/agent.ts b/src/agent.ts",
              output: { stdout: patch },
              duration_ms: 75,
            },
          ],
          metadata: { repo: repo.full_name },
        },
      ],
      total: 1,
      page: 1,
      limit: 20,
    })
  );
  await page.route(/\/api\/observability\/call-events(?:\?.*)?$/, (route) =>
    fulfillJson(route, { events: [] })
  );
  await page.route("**/api/observability/stats*", (route) =>
    fulfillJson(route, {
      summary: {
        total_calls: 1,
        total_tokens: 22,
        total_cost: 0,
        cost_today: 0,
        reconciliation_pending: 0,
        avg_duration_ms: 1200,
        success_rate: 1,
        calls_today: 1,
        tokens_today: 22,
        sandbox_time_ms: 0,
        sandbox_active: 0,
        sandbox_total: 0,
        job_runs_total: 0,
        job_runs_running: 0,
        job_runs_pending: 0,
        job_runs_stale_pending: 0,
        job_runs_failed_in_range: 0,
        job_runs_repaired_in_range: 0,
        job_runs_success_rate_in_range: 0,
        suppressed_in_range: 0,
        deferred_in_range: 0,
        start_failed_in_range: 0,
        limit_allowed_in_range: 0,
        limit_denied_in_range: 0,
        oldest_pending_age_ms: 0,
      },
      by_model: [],
      by_type: [],
    })
  );
  await page.route(
    /\/api\/observability\/automation-events(?:\?.*)?$/,
    (route) =>
      fulfillJson(route, {
        events: [],
        total: 0,
        page: 1,
        limit: 25,
      })
  );
  await page.route(
    /\/api\/observability\/automation-failures(?:\?.*)?$/,
    (route) => fulfillJson(route, emptyAutomationFailuresResponse)
  );
  await page.route(/\/api\/observability\/jobs(?:\?.*)?$/, (route) =>
    fulfillJson(route, {
      jobs: [],
      total: 0,
      page: 1,
      limit: 25,
    })
  );

  // Expand the call row via the call_id query param instead of clicking the
  // row: the row-toggle handler navigates through buildObservabilityHref's
  // unscoped "/observability?..." href, which only works in production because
  // proxy.ts rescue-redirects it back into the scope — the e2e bypass skips
  // that rescue, so a click would strand the test on a bogus
  // "/observability" scope.
  await page.goto(scopedPath("observability?call_id=call-1"));
  await page.waitForLoadState("networkidle");

  await expect(
    page.getByRole("heading", { name: "Observability", level: 1 })
  ).toBeVisible();
  // The call_id deep link lands the table tab group on the Activity tab.
  await expect(page.getByRole("tab", { name: /^Usage/ })).toHaveAttribute(
    "aria-selected",
    "true"
  );
  await expect(page.getByRole("row", { name: /minimax-m2\.5/i })).toBeVisible();

  await expect(page.getByText("Diff source: stdout")).toBeVisible();
  await expect(page.getByText("src/agent.ts")).toBeVisible();
  await expect(page.getByText("export const mode = 'ready'")).toBeVisible();
});