Files
gradio-app--gradio/js/tootils
Gradio PR Bot 0fd56c10c7 chore: update versions (#13691)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-29 19:25:34 +00:00
..
2026-07-16 16:57:19 -04:00
2026-07-29 19:25:34 +00:00
2026-07-29 19:25:34 +00:00
2026-03-30 13:14:52 +00:00

@gradio/tootils

Unit testing utilities for Gradio Svelte components. Built on top of @testing-library/dom and vitest.

render

Mounts a Gradio component into the DOM with all required shared props (dispatcher, i18n, theme, etc.) pre-configured. Returns query helpers, event utilities, and lifecycle controls.

import { render } from "@self/tootils";
import MyComponent from "./Index.svelte";

const result = await render(MyComponent, {
  value: "hello",
  label: "My input"
});

Signature

function render(
  Component,
  props?,
  options?: { container?: HTMLElement }
): Promise<RenderResult>

Component

The Svelte component to mount. Accepts either a component constructor directly or a module with a default export.

props

Component props, excluding gradio and loading_status (which are provided automatically). You can override loading_status if needed:

await render(MyComponent, {
  value: "hello",
  loading_status: { status: "pending", /* ... */ }
});

Props listed in allowed_shared_props (from @gradio/utils) are separated out and passed via shared_props. All other props are passed as component-level props.

options.container

The parent DOM element to mount into. Defaults to document.body.

Return value

render returns a promise that resolves to an object combining @testing-library/dom query helpers with Gradio-specific utilities:

DOM queries

All @testing-library/dom query functions are bound to the container and available directly on the result:

const { getByText, getByLabelText, queryByRole } = await render(MyComponent, {
  label: "Name"
});

const input = getByLabelText("Name");

See the @testing-library/dom docs for the full list.

container

The root DOM element the component was mounted into.

component

The mounted Svelte component instance.

listen

Creates a vi.fn() mock that records all dispatched events for a given event name.

const { listen } = await render(MyComponent, { value: "" });

const change = listen("change");

// interact with the component...

expect(change).toHaveBeenCalledTimes(1);
expect(change).toHaveBeenCalledWith("new value");
Retrospective mode

By default, listen only captures events dispatched after it is called. If a component emits events during mount (before listen can be called), pass { retrospective: true } to replay all buffered events onto the mock:

const { listen } = await render(MyComponent, { value: "hi" });

// "change" may have fired during mount — retrospective replays it
const change = listen("change", { retrospective: true });

expect(change).toHaveBeenCalledWith("hi");

All dispatched events are buffered from the moment the dispatcher is created (before mount), so retrospective mode has access to the complete event history.

set_data

Simulates the Gradio server sending new data to the component (as if via a backend update). Waits for two Svelte ticks to allow all reactive updates and side-effect events to settle before returning:

const { set_data, listen } = await render(MyComponent, { value: "" });

const change = listen("change");
await set_data({ value: "updated" });

expect(change).toHaveBeenCalledWith("updated");

get_data

Retrieves the component's current data as reported by its internal get_data handler:

const { get_data } = await render(MyComponent, { value: "hello" });

const data = await get_data();
expect(data.value).toBe("hello");

debug

Prints a pretty-formatted DOM tree of the container (or a specific element) to the console. Useful for debugging test failures:

const result = await render(MyComponent, { value: "hello" });

result.debug(); // prints full container
result.debug(someElement); // prints specific element

unmount

Removes the component from the DOM:

const { unmount } = await render(MyComponent, { value: "hello" });

// ...assertions...

unmount();

cleanup

Unmounts all components mounted via render and removes their DOM nodes. Call this in an afterEach hook to prevent test pollution:

import { cleanup } from "@self/tootils";

afterEach(() => {
  cleanup();
});

fireEvent

An async wrapper around @testing-library/dom's fireEvent. Each event method waits for two Svelte ticks after firing, ensuring reactive state updates and any resulting event emissions have settled before your assertions run:

import { render, fireEvent } from "@self/tootils";

const { getByRole } = await render(MyComponent, { value: "" });

const input = getByRole("textbox");
await fireEvent.input(input, { target: { value: "hello" } });
await fireEvent.blur(input);

// state has settled — safe to assert

All standard DOM event methods are available (click, input, change, focus, blur, keyDown, etc.).

download_file

Clicks an element and captures the resulting file download. This triggers a real browser download via Playwright's download event API — the file is actually downloaded and its content is readable.

Works with both download patterns used in Gradio components:

  • Static <a download href="..."> links (DownloadLink, FilePreview, etc.)
  • Programmatic downloads that create an anchor, set .href/.download, and call .click() (DownloadButton, Gallery, Code, etc.)
import { render, download_file } from "@self/tootils/render";

const { container } = await render(FileComponent, {
  value: { url: "/files/data.csv", orig_name: "data.csv" }
});

const { suggested_filename, content } = await download_file("a[download]");

expect(suggested_filename).toBe("data.csv");
expect(content).toContain("col1,col2");

Signature

function download_file(
  selector: string,
  options?: { timeout?: number }
): Promise<{ suggested_filename: string; content: string | null }>

selector

A CSS selector for the element to click. The click triggers the download.

options.timeout

How long to wait for the download event (default 5000ms). If no download is triggered within this window, the promise rejects.

Return value

  • suggested_filename — the filename the browser would save the file as (from the download attribute or Content-Disposition header)
  • content — the text content of the downloaded file, or null if the file couldn't be read

How it works

This utility uses a Vitest browser command that runs server-side with access to the Playwright Page object. It sets up page.waitForEvent("download") before clicking the element, so the download event is never missed regardless of timing. The downloaded file is saved to a temp path by Playwright and its content is read back.

upload_file

Sets files on an <input type="file"> element using real file fixtures. Triggers the browser's native change event.

import { render, upload_file, mock_client, TEST_JPG } from "@self/tootils/render";

const { listen } = await render(ImageUpload, { interactive: true, client: mock_client() });
const upload = listen("upload");

await upload_file(TEST_JPG);

await vi.waitFor(() => expect(upload).toHaveBeenCalled());

Signature

function upload_file(
  files: FileData | FileData[],
  selector?: string  // default: 'input[type="file"]'
): Promise<void>

drop_file

Simulates dragging and dropping files onto an element. Reads fixture files from disk, constructs a real DataTransfer with File objects, and dispatches dragenter, dragover, and drop events on the target.

import { render, drop_file, mock_client, TEST_JPG } from "@self/tootils/render";

const { listen } = await render(ImageUpload, { interactive: true, client: mock_client() });
const upload = listen("upload");

await drop_file(TEST_JPG, "[aria-label='Click to upload or drop files']");

await vi.waitFor(() => expect(upload).toHaveBeenCalled());

Signature

function drop_file(
  files: FileData | FileData[],
  selector: string
): Promise<void>

mock_client

Creates a mock client suitable for components that use file uploads. The upload mock echoes back the input FileData unchanged, and the stream mock returns a no-op event source.

import { render, mock_client } from "@self/tootils/render";

await render(FileComponent, {
  interactive: true,
  root: "http://localhost:7860",
  client: mock_client()
});

Test fixtures

Pre-built FileData instances pointing to existing test files in test/test_files/. Use these as value props or with upload_file/drop_file:

Export File MIME type
TEST_TXT alphabet.txt text/plain
TEST_JPG cheetah1.jpg image/jpeg
TEST_PNG bus.png image/png
TEST_MP4 video_sample.mp4 video/mp4
TEST_WAV audio_sample.wav audio/wav
TEST_PDF sample_file.pdf application/pdf
import { render, TEST_PNG } from "@self/tootils/render";

// As a component value
await render(ImageComponent, { value: TEST_PNG });

// As an upload fixture
await upload_file(TEST_PNG);

Each fixture has path, url, orig_name, size, and mime_type set. The URLs are served by the Vite dev server during tests.

Re-exports

Everything from @testing-library/dom is re-exported, so you can import query utilities, screen, within, etc. directly:

import { screen, within } from "@self/tootils";