Testing Chatbot Component Functionality in Gradio
This test suite validates the Chatbot component functionality in Gradio, covering message rendering, media handling, and user interactions. It ensures proper display and behavior of chat messages across different content types and states.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
gradio-app/gradio
js/chatbot/Chatbot.test.ts
import { test, describe, assert, afterEach, vi } from "vitest";
import { cleanup, render, fireEvent } from "@self/tootils";
import Chatbot from "./Index.svelte";
import type { LoadingStatus } from "@gradio/statustracker";
import type { FileData } from "@gradio/client";
const loading_status: LoadingStatus = {
eta: 0,
queue_position: 1,
queue_size: 1,
status: "complete",
scroll_to_output: false,
visible: true,
fn_index: 0,
show_progress: "full"
};
describe("Chatbot", () => {
afterEach(() => cleanup());
test("renders user and bot messages", async () => {
const { getAllByTestId } = await render(Chatbot, {
loading_status,
label: "chatbot",
value: [["user message one", "bot message one"]],
latex_delimiters: [{ left: "$$", right: "$$", display: true }]
});
const bot = getAllByTestId("user")[0];
const user = getAllByTestId("bot")[0];
assert.exists(bot);
assert.exists(user);
});
test("null messages are not visible", async () => {
const { getByRole, container } = await render(Chatbot, {
loading_status,
label: "chatbot",
value: [[null, null]],
latex_delimiters: [{ left: "$$", right: "$$", display: true }]
});
const chatbot = getByRole("log");
const userButton = container.querySelector(".user button");
const botButton = container.querySelector(".bot button");
assert.notExists(userButton);
assert.notExists(botButton);
assert.isFalse(chatbot.innerHTML.includes("button"));
});
test("empty string messages are visible", async () => {
const { container } = await render(Chatbot, {
loading_status,
label: "chatbot",
value: [["", ""]],
latex_delimiters: [{ left: "$$", right: "$$", display: true }]
});
const userButton = container.querySelector(".user button");
const botButton = container.querySelector(".bot button");
assert.exists(userButton);
assert.exists(botButton);
});
test("renders additional message as they are passed", async () => {
const { component, getAllByTestId } = await render(Chatbot, {
loading_status,
label: "chatbot",
value: [["user message one", "bot message one"]],
latex_delimiters: [{ left: "$$", right: "$$", display: true }]
});
await component.$set({
value: [
["user message one", "bot message one"],
["user message two", "bot message two"]
]
});
const user_2 = getAllByTestId("user");
const bot_2 = getAllByTestId("bot");
assert.equal(user_2.length, 2);
assert.equal(bot_2.length, 2);
assert.exists(user_2[1]);
assert.exists(bot_2[1]);
});
test.skip("renders image bot and user messages", async () => {
const { component, getAllByTestId, debug } = await render(Chatbot, {
loading_status,
label: "chatbot",
value: undefined,
latex_delimiters: []
});
let value: [string | FileData | null, string | FileData | null][] = Array(
2
).fill([
{
file: {
path: "https://gradio-builds.s3.amazonaws.com/demo-files/cheetah1.jpg",
url: "https://gradio-builds.s3.amazonaws.com/demo-files/cheetah1.jpg",
mime_type: "image/jpeg",
alt_text: null
}
}
]);
await component.$set({
value: value
});
const image = getAllByTestId("chatbot-image") as HTMLImageElement[];
debug(image[0]);
assert.isTrue(image[0].src.includes("cheetah1.jpg"));
assert.isTrue(image[1].src.includes("cheetah1.jpg"));
});
test.skip("renders video bot and user messages", async () => {
const { component, getAllByTestId } = await render(Chatbot, {
loading_status,
label: "chatbot",
latex_delimiters: [],
theme_mode: "dark"
});
let value: Array<[string | FileData | null, string | FileData | null]> =
Array(2).fill([
{
file: {
path: "https://gradio-builds.s3.amazonaws.com/demo-files/video_sample.mp4",
url: "https://gradio-builds.s3.amazonaws.com/demo-files/video_sample.mp4",
mime_type: "video/mp4",
alt_text: null
}
}
]);
await component.$set({
value: value
});
const video = getAllByTestId("chatbot-video") as HTMLVideoElement[];
assert.isTrue(video[0].src.includes("video_sample.mp4"));
assert.isTrue(video[1].src.includes("video_sample.mp4"));
});
test.skip("renders audio bot and user messages", async () => {
const { component, getAllByTestId } = await render(Chatbot, {
loading_status,
label: "chatbot",
latex_delimiters: [],
theme_mode: "dark"
});
let value = Array(2).fill([
{
file: {
path: "https://gradio-builds.s3.amazonaws.com/demo-files/audio_sample.wav",
url: "https://gradio-builds.s3.amazonaws.com/demo-files/audio_sample.wav",
mime_type: "audio/wav",
alt_text: null
}
}
]);
await component.$set({
value: value
});
const audio = getAllByTestId("chatbot-audio") as HTMLAudioElement[];
assert.isTrue(audio[0].src.includes("audio_sample.wav"));
assert.isTrue(audio[1].src.includes("audio_sample.wav"));
});
test("renders hyperlinks to file bot and user messages", async () => {
const { component, getAllByTestId } = await render(Chatbot, {
loading_status,
label: "chatbot",
latex_delimiters: []
});
let value = Array(2).fill([
{
file: {
path: "https://gradio-builds.s3.amazonaws.com/demo-files/titanic.csv",
url: "https://gradio-builds.s3.amazonaws.com/demo-files/titanic.csv",
mime_type: "text/csv",
alt_text: null
}
}
]);
await component.$set({
value: value
});
const file_link = getAllByTestId("chatbot-file") as HTMLAnchorElement[];
assert.isTrue(file_link[0].href.includes("titanic.csv"));
assert.isTrue(file_link[0].href.includes("titanic.csv"));
});
test("renders copy all messages button and copies all messages to clipboard", async () => {
// mock the clipboard API
const clipboard_write_text_mock = vi.fn().mockResolvedValue(undefined);
Object.defineProperty(navigator, "clipboard", {
value: { writeText: clipboard_write_text_mock },
configurable: true,
writable: true
});
const { getByLabelText } = await render(Chatbot, {
loading_status,
label: "chatbot",
value: [["user message one", "bot message one"]],
show_copy_all_button: true
});
const copy_button = getByLabelText("Copy conversation");
fireEvent.click(copy_button);
expect(clipboard_write_text_mock).toHaveBeenCalledWith(
expect.stringContaining("user: user message one")
);
expect(clipboard_write_text_mock).toHaveBeenCalledWith(
expect.stringContaining("assistant: bot message one")
);
});
});