fix(web): Remove re-throw from loadConversation to prevent unhandled rejections
- Make loadConversation fully self-contained like sendMessage (handle errors internally via state, onError callback, and structured logging) - Remove duplicate try/catch+log from Chat.tsx imperative handle - Replace re-throw tests with delegation and no-throw tests - Add hook-level loadConversation error path tests (getIdea rejection) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -103,7 +103,7 @@ describe("Chat", () => {
|
||||
});
|
||||
|
||||
describe("loadConversation via ref", () => {
|
||||
it("should successfully load a conversation", async () => {
|
||||
it("should delegate to useChat.loadConversation", async () => {
|
||||
const mockLoadConversation = vi.fn().mockResolvedValue(undefined);
|
||||
mockUseChat.mockReturnValue(
|
||||
createMockUseChatReturn({ loadConversation: mockLoadConversation })
|
||||
@@ -117,9 +117,10 @@ describe("Chat", () => {
|
||||
expect(mockLoadConversation).toHaveBeenCalledWith("conv-123");
|
||||
});
|
||||
|
||||
it("should log error context and re-throw on network failure", async () => {
|
||||
const networkError = new Error("Network request failed");
|
||||
const mockLoadConversation = vi.fn().mockRejectedValue(networkError);
|
||||
it("should not re-throw when useChat.loadConversation handles errors internally", async () => {
|
||||
// useChat.loadConversation handles errors internally (sets error state, logs, calls onError)
|
||||
// and does NOT re-throw, so the imperative handle should resolve cleanly
|
||||
const mockLoadConversation = vi.fn().mockResolvedValue(undefined);
|
||||
mockUseChat.mockReturnValue(
|
||||
createMockUseChatReturn({ loadConversation: mockLoadConversation })
|
||||
);
|
||||
@@ -127,57 +128,13 @@ describe("Chat", () => {
|
||||
const ref = createRef<ChatRef>();
|
||||
render(<Chat ref={ref} />);
|
||||
|
||||
await expect(ref.current?.loadConversation("conv-123")).rejects.toThrow(
|
||||
"Network request failed"
|
||||
);
|
||||
|
||||
expect(consoleSpy).toHaveBeenCalledWith(
|
||||
"Failed to load conversation",
|
||||
expect.objectContaining({
|
||||
error: networkError,
|
||||
conversationId: "conv-123",
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("should log error context and re-throw on API error (500)", async () => {
|
||||
const apiError = new Error("Internal Server Error");
|
||||
const mockLoadConversation = vi.fn().mockRejectedValue(apiError);
|
||||
mockUseChat.mockReturnValue(
|
||||
createMockUseChatReturn({ loadConversation: mockLoadConversation })
|
||||
);
|
||||
|
||||
const ref = createRef<ChatRef>();
|
||||
render(<Chat ref={ref} />);
|
||||
|
||||
await expect(ref.current?.loadConversation("conv-456")).rejects.toThrow(
|
||||
"Internal Server Error"
|
||||
);
|
||||
|
||||
expect(consoleSpy).toHaveBeenCalledWith(
|
||||
"Failed to load conversation",
|
||||
expect.objectContaining({
|
||||
conversationId: "conv-456",
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("should re-throw error for caller to handle", async () => {
|
||||
const mockLoadConversation = vi.fn().mockRejectedValue(new Error("Auth failed"));
|
||||
mockUseChat.mockReturnValue(
|
||||
createMockUseChatReturn({ loadConversation: mockLoadConversation })
|
||||
);
|
||||
|
||||
const ref = createRef<ChatRef>();
|
||||
render(<Chat ref={ref} />);
|
||||
|
||||
// Verify the error propagates to the caller
|
||||
await expect(ref.current?.loadConversation("conv-789")).rejects.toThrow("Auth failed");
|
||||
// Should resolve without throwing
|
||||
await expect(ref.current?.loadConversation("conv-123")).resolves.toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("sendMessage delegation", () => {
|
||||
it("should delegate to useChat.sendMessage without extra error handling", async () => {
|
||||
it("should delegate to useChat.sendMessage", async () => {
|
||||
const mockSendMessage = vi.fn().mockResolvedValue(undefined);
|
||||
mockUseChat.mockReturnValue(createMockUseChatReturn({ sendMessage: mockSendMessage }));
|
||||
|
||||
|
||||
@@ -94,12 +94,7 @@ export const Chat = forwardRef<ChatRef, ChatProps>(function Chat(
|
||||
// Expose methods to parent via ref
|
||||
useImperativeHandle(ref, () => ({
|
||||
loadConversation: async (cId: string): Promise<void> => {
|
||||
try {
|
||||
await loadConversation(cId);
|
||||
} catch (err) {
|
||||
console.error("Failed to load conversation", { error: err, conversationId: cId });
|
||||
throw err;
|
||||
}
|
||||
await loadConversation(cId);
|
||||
},
|
||||
startNewConversation: (projectId?: string | null): void => {
|
||||
startNewConversation(projectId);
|
||||
|
||||
Reference in New Issue
Block a user