Files
kandev/apps/web/components/task/chat/stopped-banner-props.test.ts
T
2026-09-07 11:19:09 +01:00

105 lines
3.2 KiB
TypeScript

import { renderHook } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { buildStoppedBannerProps } from "./chat-input-container";
import { shouldHideChatInputForLaunchError, shouldRenderStoppedSessionBanner } from "./types";
import { useComposerProps } from "./use-composer-props";
function composerArgs(errorMessage: string) {
return {
panelState: {
resolvedSessionId: "session-1",
taskId: "task-1",
session: { error_message: errorMessage },
task: null,
taskDescription: "",
planModeEnabled: false,
planModeAvailable: true,
mcpServers: [],
mcpAttachmentHistory: [],
handlePlanModeChange: vi.fn(),
isAgentBusy: false,
supportsSteering: false,
isStarting: false,
isPreparingEnvironment: false,
pendingClarification: null,
pendingCommentsByFile: {},
planComments: [],
pendingPRFeedback: [],
walkthroughComments: [],
messageComments: [],
chatSubmitKey: "enter",
agentCommands: [],
isFailed: true,
isCompleted: false,
needsRecovery: false,
contextItems: [],
planContextEnabled: false,
contextFiles: [],
handleToggleContextFile: vi.fn(),
handleAddContextFile: vi.fn(),
} as never,
composerWorkspaceId: "workspace-1",
isMoving: false,
implementPlanHandler: undefined,
executor: { unavailable: false },
placeholder: "",
handleSubmit: vi.fn(),
handleCancelTurn: vi.fn(),
isSending: false,
showRequestChangesTooltip: false,
onClarificationResolved: vi.fn(),
};
}
describe("stopped-session error propagation", () => {
it("gives the task launch card ownership of a failed session", () => {
expect(
shouldRenderStoppedSessionBanner({
isFailed: true,
isCompleted: false,
executorUnavailable: false,
launchErrorOwned: true,
}),
).toBe(false);
expect(shouldHideChatInputForLaunchError({ isFailed: true, launchErrorOwned: true })).toBe(
true,
);
});
it("threads the sanitized session error from panel state into composer props", () => {
const errorMessage = "pods is forbidden: RBAC denied the request";
const { result } = renderHook(() => useComposerProps(composerArgs(errorMessage)));
expect(result.current.sessionErrorMessage).toBe(errorMessage);
});
it("uses the sanitized session error as recoverable banner copy", () => {
const errorMessage = "pods is forbidden: RBAC denied the request";
expect(
buildStoppedBannerProps({
executorUnavailable: false,
executorUnavailableReason: undefined,
sessionErrorMessage: errorMessage,
}),
).toEqual({ message: errorMessage });
});
it("keeps the causal session error when its executor is also unavailable", () => {
const errorMessage = "pod scheduling failed: 0/1 nodes matched";
expect(
buildStoppedBannerProps({
executorUnavailable: true,
executorUnavailableReason: "failed",
sessionErrorMessage: errorMessage,
}),
).toEqual({
message: errorMessage,
detail: "failed",
resumeLabel: "Restart",
resumingLabel: "Restarting...",
});
});
});