From 37eb4bffd3c5933bfb51ca5280b087ca496f70e1 Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Sun, 14 Jun 2026 08:13:06 +0000 Subject: [PATCH] fix(e2e): assert echo runtime received A2A request in chat-desktop specs (core#2796 follow-up) PR #2830 removed the obsolete activity-log assertion and its echo-runtime delay, but the E2E Chat promotion-readiness note still listed "server never asserts it received the request" as blocking promotion. Wire the exposed EchoRuntime.lastRequest into the desktop chat round-trip tests so an optimistic client-side render cannot green the lane without a real A2A request reaching the fixture. - Expose echoRuntime to chat-desktop.spec.ts tests instead of hiding it inside the cleanup closure. - Assert lastRequest is populated and matches the sent text for text, history, and file-attachment round-trips. - Move the server-received item from STILL BLOCKS PROMOTION to NOW FAIL-CLOSED in e2e-chat.yml. Co-Authored-By: Claude --- .gitea/workflows/e2e-chat.yml | 8 +++----- canvas/e2e/chat-desktop.spec.ts | 30 +++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/.gitea/workflows/e2e-chat.yml b/.gitea/workflows/e2e-chat.yml index 4e6e887d7..98a90688d 100644 --- a/.gitea/workflows/e2e-chat.yml +++ b/.gitea/workflows/e2e-chat.yml @@ -124,12 +124,10 @@ jobs: # renamed/moved spec or stray test.only can no longer green the lane. # - REQUIRE-LIVE guard in "Run Playwright E2E tests" → chat==true must # actually execute >=1 test, else exit 1. + # - chat-desktop.spec.ts asserts echo-runtime.lastRequest after each + # round-trip, so an optimistic client-side render cannot pass without + # a real A2A request reaching the server (core#2796 follow-up). # STILL BLOCKS PROMOTION: - # - The echo round-trip asserts on rendered "Echo: ..." text but never - # asserts the echo runtime actually RECEIVED the A2A request - # (fixtures/echo-runtime.ts exposes lastRequest, unused) — an - # optimistic client-side render could pass without a real round-trip. - # Add a server-received assertion before required. # - The "No-op pass" path (detect-changes chat!=true) is a legitimate # paths-filter skip, but a required gate needs it to be a neutral # check, not a green "success", so a skipped heavy lane can't be diff --git a/canvas/e2e/chat-desktop.spec.ts b/canvas/e2e/chat-desktop.spec.ts index aa48f6db9..bdd423f9e 100644 --- a/canvas/e2e/chat-desktop.spec.ts +++ b/canvas/e2e/chat-desktop.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from "@playwright/test"; import type { Page } from "@playwright/test"; -import { startEchoRuntime } from "./fixtures/echo-runtime"; +import { startEchoRuntime, type EchoRuntime } from "./fixtures/echo-runtime"; import { seedWorkspace, startHeartbeat, cleanupWorkspace, runPsql } from "./fixtures/chat-seed"; /** Enter the Org-map view so the Canvas (React Flow graph) mounts. */ @@ -14,17 +14,18 @@ test.describe("Desktop ChatTab", () => { let cleanup: () => Promise = async () => {}; let workspaceId = ""; let workspaceName = ""; + let echoRuntime: EchoRuntime; test.beforeAll(async () => { - const echo = await startEchoRuntime(); - const ws = await seedWorkspace(echo.baseURL); + echoRuntime = await startEchoRuntime(); + const ws = await seedWorkspace(echoRuntime.baseURL); workspaceId = ws.id; workspaceName = ws.name; const stopHeartbeat = startHeartbeat(ws.id, ws.authToken); cleanup = async () => { stopHeartbeat(); - await echo.stop(); + await echoRuntime.stop(); }; }); @@ -86,6 +87,11 @@ test.describe("Desktop ChatTab", () => { await expect(chat.getByText("What is the weather?", { exact: true })).toBeVisible({ timeout: 5_000 }); await expect(chat.getByText("Echo: What is the weather?")).toBeVisible({ timeout: 15_000 }); + + // Regression guard: assert the echo runtime actually RECEIVED the A2A + // request, not just that the UI rendered something that looks like an echo. + expect(echoRuntime.lastRequest).not.toBeNull(); + expect(echoRuntime.lastRequest!.text).toBe("What is the weather?"); }); test("history persists across reload", async ({ page }) => { @@ -96,6 +102,10 @@ test.describe("Desktop ChatTab", () => { await expect(chat.getByText("Echo: Persistence test")).toBeVisible({ timeout: 15_000 }); + // Confirm the round-trip reached the echo runtime before reloading. + expect(echoRuntime.lastRequest).not.toBeNull(); + expect(echoRuntime.lastRequest!.text).toBe("Persistence test"); + await page.reload(); await enterMapView(page); await page.waitForSelector(".react-flow__node", { timeout: 10_000 }); @@ -126,6 +136,11 @@ test.describe("Desktop ChatTab", () => { await page.getByRole("button", { name: /Send/ }).first().click(); await expect(chat.getByText("Echo: Please read this file")).toBeVisible({ timeout: 15_000 }); + + // Confirm the file payload reached the echo runtime, not just the UI. + expect(echoRuntime.lastRequest).not.toBeNull(); + expect(echoRuntime.lastRequest!.text).toBe("Please read this file"); + expect(echoRuntime.lastRequest!.files).toHaveLength(1); }); }); @@ -133,17 +148,18 @@ test.describe("Desktop ChatTab — Markdown rendering", () => { let cleanup: () => Promise = async () => {}; let workspaceId = ""; let workspaceName = ""; + let echoRuntime: EchoRuntime; test.beforeAll(async () => { - const echo = await startEchoRuntime(); - const ws = await seedWorkspace(echo.baseURL); + echoRuntime = await startEchoRuntime(); + const ws = await seedWorkspace(echoRuntime.baseURL); workspaceId = ws.id; workspaceName = ws.name; const stopHeartbeat = startHeartbeat(ws.id, ws.authToken); cleanup = async () => { stopHeartbeat(); - await echo.stop(); + await echoRuntime.stop(); }; }); -- 2.52.0