Spaces:
Build error
Build error
| import userEvent from "@testing-library/user-event"; | |
| import { fireEvent, render, screen } from "@testing-library/react"; | |
| import { describe, afterEach, vi, it, expect } from "vitest"; | |
| import { ChatInput } from "#/components/features/chat/chat-input"; | |
| describe("ChatInput", () => { | |
| const onSubmitMock = vi.fn(); | |
| afterEach(() => { | |
| vi.clearAllMocks(); | |
| }); | |
| it("should render a textarea", () => { | |
| render(<ChatInput onSubmit={onSubmitMock} />); | |
| expect(screen.getByTestId("chat-input")).toBeInTheDocument(); | |
| expect(screen.getByRole("textbox")).toBeInTheDocument(); | |
| }); | |
| it("should call onSubmit when the user types and presses enter", async () => { | |
| const user = userEvent.setup(); | |
| render(<ChatInput onSubmit={onSubmitMock} />); | |
| const textarea = screen.getByRole("textbox"); | |
| await user.type(textarea, "Hello, world!"); | |
| await user.keyboard("{Enter}"); | |
| expect(onSubmitMock).toHaveBeenCalledWith("Hello, world!"); | |
| }); | |
| it("should call onSubmit when pressing the submit button", async () => { | |
| const user = userEvent.setup(); | |
| render(<ChatInput onSubmit={onSubmitMock} />); | |
| const textarea = screen.getByRole("textbox"); | |
| const button = screen.getByRole("button"); | |
| await user.type(textarea, "Hello, world!"); | |
| await user.click(button); | |
| expect(onSubmitMock).toHaveBeenCalledWith("Hello, world!"); | |
| }); | |
| it("should not call onSubmit when the message is empty", async () => { | |
| const user = userEvent.setup(); | |
| render(<ChatInput onSubmit={onSubmitMock} />); | |
| const button = screen.getByRole("button"); | |
| await user.click(button); | |
| expect(onSubmitMock).not.toHaveBeenCalled(); | |
| await user.keyboard("{Enter}"); | |
| expect(onSubmitMock).not.toHaveBeenCalled(); | |
| }); | |
| it("should not call onSubmit when the message is only whitespace", async () => { | |
| const user = userEvent.setup(); | |
| render(<ChatInput onSubmit={onSubmitMock} />); | |
| const textarea = screen.getByRole("textbox"); | |
| await user.type(textarea, " "); | |
| await user.keyboard("{Enter}"); | |
| expect(onSubmitMock).not.toHaveBeenCalled(); | |
| await user.type(textarea, " \t\n"); | |
| await user.keyboard("{Enter}"); | |
| expect(onSubmitMock).not.toHaveBeenCalled(); | |
| }); | |
| it("should disable submit", async () => { | |
| const user = userEvent.setup(); | |
| render(<ChatInput disabled onSubmit={onSubmitMock} />); | |
| const button = screen.getByRole("button"); | |
| const textarea = screen.getByRole("textbox"); | |
| await user.type(textarea, "Hello, world!"); | |
| expect(button).toBeDisabled(); | |
| await user.click(button); | |
| expect(onSubmitMock).not.toHaveBeenCalled(); | |
| await user.keyboard("{Enter}"); | |
| expect(onSubmitMock).not.toHaveBeenCalled(); | |
| }); | |
| it("should render a placeholder with translation key", () => { | |
| render(<ChatInput onSubmit={onSubmitMock} />); | |
| const textarea = screen.getByPlaceholderText("SUGGESTIONS$WHAT_TO_BUILD"); | |
| expect(textarea).toBeInTheDocument(); | |
| }); | |
| it("should create a newline instead of submitting when shift + enter is pressed", async () => { | |
| const user = userEvent.setup(); | |
| render(<ChatInput onSubmit={onSubmitMock} />); | |
| const textarea = screen.getByRole("textbox"); | |
| await user.type(textarea, "Hello, world!"); | |
| await user.keyboard("{Shift>} {Enter}"); // Shift + Enter | |
| expect(onSubmitMock).not.toHaveBeenCalled(); | |
| // expect(textarea).toHaveValue("Hello, world!\n"); | |
| }); | |
| it("should clear the input message after sending a message", async () => { | |
| const user = userEvent.setup(); | |
| render(<ChatInput onSubmit={onSubmitMock} />); | |
| const textarea = screen.getByRole("textbox"); | |
| const button = screen.getByRole("button"); | |
| await user.type(textarea, "Hello, world!"); | |
| await user.keyboard("{Enter}"); | |
| expect(textarea).toHaveValue(""); | |
| await user.type(textarea, "Hello, world!"); | |
| await user.click(button); | |
| expect(textarea).toHaveValue(""); | |
| }); | |
| it("should hide the submit button", () => { | |
| render(<ChatInput onSubmit={onSubmitMock} showButton={false} />); | |
| expect(screen.queryByRole("button")).not.toBeInTheDocument(); | |
| }); | |
| it("should call onChange when the user types", async () => { | |
| const user = userEvent.setup(); | |
| const onChangeMock = vi.fn(); | |
| render(<ChatInput onSubmit={onSubmitMock} onChange={onChangeMock} />); | |
| const textarea = screen.getByRole("textbox"); | |
| await user.type(textarea, "Hello, world!"); | |
| expect(onChangeMock).toHaveBeenCalledTimes("Hello, world!".length); | |
| }); | |
| it("should have set the passed value", () => { | |
| render(<ChatInput value="Hello, world!" onSubmit={onSubmitMock} />); | |
| const textarea = screen.getByRole("textbox"); | |
| expect(textarea).toHaveValue("Hello, world!"); | |
| }); | |
| it("should display the stop button and trigger the callback", async () => { | |
| const user = userEvent.setup(); | |
| const onStopMock = vi.fn(); | |
| render( | |
| <ChatInput onSubmit={onSubmitMock} button="stop" onStop={onStopMock} />, | |
| ); | |
| const stopButton = screen.getByTestId("stop-button"); | |
| await user.click(stopButton); | |
| expect(onStopMock).toHaveBeenCalledOnce(); | |
| }); | |
| it("should call onFocus and onBlur when the textarea is focused and blurred", async () => { | |
| const user = userEvent.setup(); | |
| const onFocusMock = vi.fn(); | |
| const onBlurMock = vi.fn(); | |
| render( | |
| <ChatInput | |
| onSubmit={onSubmitMock} | |
| onFocus={onFocusMock} | |
| onBlur={onBlurMock} | |
| />, | |
| ); | |
| const textarea = screen.getByRole("textbox"); | |
| await user.click(textarea); | |
| expect(onFocusMock).toHaveBeenCalledOnce(); | |
| await user.tab(); | |
| expect(onBlurMock).toHaveBeenCalledOnce(); | |
| }); | |
| it("should handle text paste correctly", () => { | |
| const onSubmit = vi.fn(); | |
| const onChange = vi.fn(); | |
| render(<ChatInput onSubmit={onSubmit} onChange={onChange} />); | |
| const input = screen.getByTestId("chat-input").querySelector("textarea"); | |
| expect(input).toBeTruthy(); | |
| // Fire paste event with text data | |
| fireEvent.paste(input!, { | |
| clipboardData: { | |
| getData: (type: string) => (type === "text/plain" ? "test paste" : ""), | |
| files: [], | |
| }, | |
| }); | |
| }); | |
| it("should handle image paste correctly", () => { | |
| const onSubmit = vi.fn(); | |
| const onImagePaste = vi.fn(); | |
| render(<ChatInput onSubmit={onSubmit} onImagePaste={onImagePaste} />); | |
| const input = screen.getByTestId("chat-input").querySelector("textarea"); | |
| expect(input).toBeTruthy(); | |
| // Create a paste event with an image file | |
| const file = new File(["dummy content"], "image.png", { | |
| type: "image/png", | |
| }); | |
| // Fire paste event with image data | |
| fireEvent.paste(input!, { | |
| clipboardData: { | |
| getData: () => "", | |
| files: [file], | |
| }, | |
| }); | |
| // Verify image paste was handled | |
| expect(onImagePaste).toHaveBeenCalledWith([file]); | |
| }); | |
| it("should use the default maxRows value", () => { | |
| // We can't directly test the maxRows prop as it's not exposed in the DOM | |
| // Instead, we'll verify the component renders with the default props | |
| render(<ChatInput onSubmit={onSubmitMock} />); | |
| const textarea = screen.getByRole("textbox"); | |
| expect(textarea).toBeInTheDocument(); | |
| // The actual verification of maxRows=16 is handled internally by the TextareaAutosize component | |
| // and affects how many rows the textarea can expand to | |
| }); | |
| it("should not submit when Enter is pressed during IME composition", async () => { | |
| const user = userEvent.setup(); | |
| render(<ChatInput onSubmit={onSubmitMock} />); | |
| const textarea = screen.getByRole("textbox"); | |
| await user.type(textarea, "γγγ«γ‘γ―"); | |
| // Simulate Enter during IME composition | |
| fireEvent.keyDown(textarea, { | |
| key: "Enter", | |
| isComposing: true, | |
| nativeEvent: { isComposing: true }, | |
| }); | |
| expect(onSubmitMock).not.toHaveBeenCalled(); | |
| // Simulate normal Enter after composition is done | |
| fireEvent.keyDown(textarea, { | |
| key: "Enter", | |
| isComposing: false, | |
| nativeEvent: { isComposing: false }, | |
| }); | |
| expect(onSubmitMock).toHaveBeenCalledWith("γγγ«γ‘γ―"); | |
| }); | |
| }); | |