import { render, screen, within, fireEvent } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import { InteractiveChatBox } from "#/components/features/chat/interactive-chat-box"; describe("InteractiveChatBox", () => { const onSubmitMock = vi.fn(); const onStopMock = vi.fn(); beforeAll(() => { global.URL.createObjectURL = vi .fn() .mockReturnValue("blob:http://example.com"); }); afterEach(() => { vi.clearAllMocks(); }); it("should render", () => { render(); const chatBox = screen.getByTestId("interactive-chat-box"); within(chatBox).getByTestId("chat-input"); within(chatBox).getByTestId("upload-image-input"); }); it.fails("should set custom values", () => { render( , ); const chatBox = screen.getByTestId("interactive-chat-box"); const chatInput = within(chatBox).getByTestId("chat-input"); expect(chatInput).toHaveValue("Hello, world!"); }); it("should display the image previews when images are uploaded", async () => { const user = userEvent.setup(); render(); const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" }); const input = screen.getByTestId("upload-image-input"); expect(screen.queryAllByTestId("image-preview")).toHaveLength(0); await user.upload(input, file); expect(screen.queryAllByTestId("image-preview")).toHaveLength(1); const files = [ new File(["(⌐□_□)"], "chucknorris2.png", { type: "image/png" }), new File(["(⌐□_□)"], "chucknorris3.png", { type: "image/png" }), ]; await user.upload(input, files); expect(screen.queryAllByTestId("image-preview")).toHaveLength(3); }); it("should remove the image preview when the close button is clicked", async () => { const user = userEvent.setup(); render(); const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" }); const input = screen.getByTestId("upload-image-input"); await user.upload(input, file); expect(screen.queryAllByTestId("image-preview")).toHaveLength(1); const imagePreview = screen.getByTestId("image-preview"); const closeButton = within(imagePreview).getByRole("button"); await user.click(closeButton); expect(screen.queryAllByTestId("image-preview")).toHaveLength(0); }); it("should call onSubmit with the message and images", async () => { const user = userEvent.setup(); render(); const textarea = within(screen.getByTestId("chat-input")).getByRole( "textbox", ); const input = screen.getByTestId("upload-image-input"); const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" }); await user.upload(input, file); await user.type(textarea, "Hello, world!"); await user.keyboard("{Enter}"); expect(onSubmitMock).toHaveBeenCalledWith("Hello, world!", [file]); // clear images after submission expect(screen.queryAllByTestId("image-preview")).toHaveLength(0); }); it("should disable the submit button", async () => { const user = userEvent.setup(); render( , ); const button = screen.getByRole("button"); expect(button).toBeDisabled(); await user.click(button); expect(onSubmitMock).not.toHaveBeenCalled(); }); it("should display the stop button if set and call onStop when clicked", async () => { const user = userEvent.setup(); render( , ); const stopButton = screen.getByTestId("stop-button"); expect(stopButton).toBeInTheDocument(); await user.click(stopButton); expect(onStopMock).toHaveBeenCalledOnce(); }); it("should handle image upload and message submission correctly", async () => { const user = userEvent.setup(); const onSubmit = vi.fn(); const onStop = vi.fn(); const onChange = vi.fn(); const { rerender } = render( ); // Upload an image via the upload button - this should NOT clear the text input const file = new File(["dummy content"], "test.png", { type: "image/png" }); const input = screen.getByTestId("upload-image-input"); await user.upload(input, file); // Verify text input was not cleared expect(screen.getByRole("textbox")).toHaveValue("test message"); expect(onChange).not.toHaveBeenCalledWith(""); // Submit the message with image const submitButton = screen.getByRole("button", { name: "BUTTON$SEND" }); await user.click(submitButton); // Verify onSubmit was called with the message and image expect(onSubmit).toHaveBeenCalledWith("test message", [file]); // Verify onChange was called to clear the text input expect(onChange).toHaveBeenCalledWith(""); // Simulate parent component updating the value prop rerender( ); // Verify the text input was cleared expect(screen.getByRole("textbox")).toHaveValue(""); // Upload another image - this should NOT clear the text input onChange.mockClear(); await user.upload(input, file); // Verify text input is still empty and onChange was not called expect(screen.getByRole("textbox")).toHaveValue(""); expect(onChange).not.toHaveBeenCalled(); }); });