diff --git a/packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx b/packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx index 1ea795b0c3..f11ba3d0dd 100644 --- a/packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx +++ b/packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx @@ -835,15 +835,22 @@ describe("PlanningModeModal", () => { expect(screen.getByTestId("planning-option-other")).toBeInTheDocument(); expect(screen.queryByTestId("planning-other-input")).toBeNull(); + /* + FNXC:PlanningModeOptions 2026-07-18-12:15: + Full Suite shard 3 (29643371961) failed when fireEvent.click(Other) did not flush + isOtherSelected before the synchronous getByTestId(planning-other-input) under CI + load. Await findByTestId after the confirm Other button click (same settle discipline + as multi-select Other) before asserting Continue enablement and the _other payload. + */ const continueButton = screen.getByRole("button", { name: "Continue" }); fireEvent.click(screen.getByTestId("planning-option-other")); - expect(screen.getByTestId("planning-other-input")).toBeInTheDocument(); + const otherInput = await screen.findByTestId("planning-other-input"); expect(continueButton).toBeDisabled(); - fireEvent.change(screen.getByTestId("planning-other-input"), { target: { value: " " } }); + fireEvent.change(otherInput, { target: { value: " " } }); expect(continueButton).toBeDisabled(); - fireEvent.change(screen.getByTestId("planning-other-input"), { + fireEvent.change(otherInput, { target: { value: " Ask a different scoping question " }, }); expect(continueButton).toBeEnabled(); diff --git a/packages/dashboard/src/__tests__/mcp-lane-forwarding.test.ts b/packages/dashboard/src/__tests__/mcp-lane-forwarding.test.ts index 2ea5ece800..81557ae546 100644 --- a/packages/dashboard/src/__tests__/mcp-lane-forwarding.test.ts +++ b/packages/dashboard/src/__tests__/mcp-lane-forwarding.test.ts @@ -3,21 +3,41 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const { createFnAgentMock, resolveMcpServersForStoreMock } = vi.hoisted(() => ({ + /* + FNXC:DashboardTests 2026-07-18-12:20: + Planning defaults clarificationEnabled=false, so createSession forces a summary after the + first question (continueToSummaryAfterSuppressedQuestion). Mock every follow-up prompt as a + complete payload so MCP-forwarding assertions exercise the default product path instead of + throwing Clarification-disabled follow-up did not produce a summary. + */ createFnAgentMock: vi.fn(async () => ({ session: { state: { messages: [] as Array<{ role: string; content: string }> }, prompt: vi.fn(async function (this: { state: { messages: Array<{ role: string; content: string }> } }, _message: string) { + const alreadyAnswered = this.state.messages.some((message) => message.role === "assistant"); this.state.messages.push({ role: "assistant", - content: JSON.stringify({ - type: "question", - data: { - id: "q1", - text: "What should be built?", - type: "text", - required: true, - }, - }), + content: JSON.stringify( + alreadyAnswered + ? { + type: "complete", + data: { + title: "Build a feature", + description: "Materialized MCP planning summary", + suggestedSize: "M", + keyDeliverables: ["docs MCP available"], + }, + } + : { + type: "question", + data: { + id: "q1", + text: "What should be built?", + type: "text", + required: true, + }, + }, + ), }); }), dispose: vi.fn(), diff --git a/packages/dashboard/src/__tests__/planning-answered-question-reemit.test.ts b/packages/dashboard/src/__tests__/planning-answered-question-reemit.test.ts index 748f32d165..cb421b8d61 100644 --- a/packages/dashboard/src/__tests__/planning-answered-question-reemit.test.ts +++ b/packages/dashboard/src/__tests__/planning-answered-question-reemit.test.ts @@ -156,11 +156,22 @@ function setupAgent(behaviors: TurnBehavior[]) { async function startSessionAtFirstQuestion( agent: ReturnType, ): Promise { + /* + FNXC:PlanningRetry 2026-07-18-12:20: + createSessionWithAgent defaults clarificationEnabled=false, which suppresses the first + question into continueToSummaryAfterSuppressedQuestion and consumes the next mock prompt + turn (often the hung turn these re-emit tests need). Opt into clarification so the + multi-question interview invariants under test still run. + */ const sessionId = await createSessionWithAgent( "10.0.2.20", "Plan a feature", "/tmp/project", MOCK_TASK_STORE, + undefined, + undefined, + undefined, + { clarificationEnabled: true }, ); planningStreamManager.consumeInitialTurn(sessionId)?.(); await agent.firstQuestionEmitted;