import { fireEvent, render, screen } from "@testing-library/react";
import { expect, test, vi } from "vitest";
import { InputCount, Sender, SenderButton } from "../src/sender";
test("InputCount displays count and limit", () => {
render(<InputCount count={5} limit={10} />);
const countElement = screen.getByText("5 / 10");
expect(countElement).toBeInTheDocument();
expect(countElement).toHaveClass("text-gray-400");
});
test("InputCount with custom className", () => {
render(<InputCount count={3} limit={5} className="text-sm" />);
const countElement = screen.getByText("3 / 5");
expect(countElement).toHaveClass("text-gray-400", "text-sm");
});
test("SenderButton renders with default icon", () => {
render(<SenderButton />);
const button = screen.getByRole("button");
expect(button).toHaveAttribute("data-slot", "sender-button");
expect(button).toHaveClass("bg-blue-500");
});
test("SenderButton with custom icon", () => {
render(<SenderButton icon={<span>Send</span>} />);
const button = screen.getByRole("button");
expect(button).toHaveTextContent("Send");
});
test("SenderButton shows sending state icon", () => {
render(<SenderButton isSending={true} />);
const button = screen.getByRole("button");
expect(button).toHaveTextContent("■");
});
test("SenderButton shows default arrow icon when not sending", () => {
render(<SenderButton isSending={false} />);
const button = screen.getByRole("button");
expect(button).toHaveTextContent("→");
});
test("Sender renders textarea and send button", () => {
const sendMessage = vi.fn();
render(<Sender sendMessage={sendMessage} placeholder="Type a message..." />);
const textarea = screen.getByPlaceholderText("Type a message...");
expect(textarea).toBeInTheDocument();
const sendButton = screen.getByRole("button", { name: "→" });
expect(sendButton).toBeInTheDocument();
});
test("Sender textarea accepts input", () => {
const sendMessage = vi.fn();
render(<Sender sendMessage={sendMessage} />);
const textarea = screen.getByRole("textbox");
fireEvent.change(textarea, { target: { value: "Hello world" } });
expect(textarea).toHaveValue("Hello world");
});
test("Sender sends message on button click", () => {
const sendMessage = vi.fn();
render(<Sender sendMessage={sendMessage} />);
const textarea = screen.getByRole("textbox");
fireEvent.change(textarea, { target: { value: "Test message" } });
const sendButton = screen.getByRole("button", { name: "→" });
fireEvent.click(sendButton);
expect(sendMessage).toHaveBeenCalledWith({ text: "Test message" });
});
test("Sender does not send empty message", () => {
const sendMessage = vi.fn();
render(<Sender sendMessage={sendMessage} />);
const sendButton = screen.getByRole("button", { name: "→" });
fireEvent.click(sendButton);
expect(sendMessage).not.toHaveBeenCalled();
});
test("Sender trims whitespace before sending", () => {
const sendMessage = vi.fn();
render(<Sender sendMessage={sendMessage} />);
const textarea = screen.getByRole("textbox");
fireEvent.change(textarea, { target: { value: " Trimmed message " } });
const sendButton = screen.getByRole("button", { name: "→" });
fireEvent.click(sendButton);
expect(sendMessage).toHaveBeenCalledWith({ text: "Trimmed message" });
});
test("Sender clears textarea after sending", () => {
const sendMessage = vi.fn();
render(<Sender sendMessage={sendMessage} />);
const textarea = screen.getByRole("textbox");
fireEvent.change(textarea, { target: { value: "Test message" } });
const sendButton = screen.getByRole("button", { name: "→" });
fireEvent.click(sendButton);
expect(textarea).toHaveValue("");
});
test("Sender sends on Enter key press", () => {
const sendMessage = vi.fn();
render(<Sender sendMessage={sendMessage} />);
const textarea = screen.getByRole("textbox");
fireEvent.change(textarea, { target: { value: "Enter message" } });
fireEvent.keyDown(textarea, { key: "Enter", shiftKey: false });
expect(sendMessage).toHaveBeenCalledWith({ text: "Enter message" });
});
test("Sender does not send on Shift+Enter", () => {
const sendMessage = vi.fn();
render(<Sender sendMessage={sendMessage} />);
const textarea = screen.getByRole("textbox");
fireEvent.change(textarea, { target: { value: "New line" } });
fireEvent.keyDown(textarea, { key: "Enter", shiftKey: true });
expect(sendMessage).not.toHaveBeenCalled();
});
test("Sender calls onMessageChange on input", () => {
const onMessageChange = vi.fn();
render(<Sender sendMessage={vi.fn()} onMessageChange={onMessageChange} />);
const textarea = screen.getByRole("textbox");
fireEvent.change(textarea, { target: { value: "Changed" } });
expect(onMessageChange).toHaveBeenCalledWith("Changed");
});
test("Sender calls onSend callback after sending", () => {
const onSend = vi.fn();
const sendMessage = vi.fn();
render(<Sender sendMessage={sendMessage} onSend={onSend} />);
const textarea = screen.getByRole("textbox");
fireEvent.change(textarea, { target: { value: "Callback test" } });
fireEvent.click(screen.getByRole("button", { name: "→" }));
expect(onSend).toHaveBeenCalled();
});
test("Sender renders with initial message", () => {
const sendMessage = vi.fn();
render(<Sender sendMessage={sendMessage} initialMessage="Initial" />);
const textarea = screen.getByRole("textbox");
expect(textarea).toHaveValue("Initial");
});
test("Sender renders toolbar when provided", () => {
const sendMessage = vi.fn();
render(
<Sender
sendMessage={sendMessage}
toolbar={<button type="button">Toolbar Button</button>}
/>,
);
expect(screen.getByText("Toolbar Button")).toBeInTheDocument();
});
test("Sender renders suggestion when provided", () => {
const sendMessage = vi.fn();
const suggestion = vi.fn(() => <div>Suggestion Content</div>);
render(<Sender sendMessage={sendMessage} suggestion={suggestion} />);
expect(suggestion).toHaveBeenCalled();
});