Back to Repositories

Testing Radio Component Selection Behavior in gradio-app

This test suite validates the Radio component functionality in a Svelte application using Vitest and Testing Library. It ensures proper rendering, state management, and event handling for radio button groups.

Test Coverage Overview

The test suite provides comprehensive coverage of the Radio component’s core functionality.

Key areas tested include:
  • Initial value rendering and validation
  • Radio button selection state changes
  • Event dispatch on selection
  • Multiple radio group isolation
Edge cases covered include multiple radio groups coexisting on the same page without interference.

Implementation Analysis

The testing approach utilizes Vitest with Testing Library’s user-event simulation for interaction testing. The implementation follows component-driven testing patterns, leveraging Svelte’s component rendering capabilities alongside Testing Library’s role-based queries and event simulation.

Key patterns include role-based element selection, state verification through expect/assert combinations, and async/await for event handling.

Technical Details

Testing tools and setup:
  • Vitest for test runner and assertions
  • @testing-library/user-event for user interaction simulation
  • Custom render utility for Svelte components
  • Cleanup hooks for test isolation
  • Role-based queries for accessibility-focused testing

Best Practices Demonstrated

The test suite exemplifies modern testing best practices with a focus on component isolation and user interaction simulation.

Notable practices include:
  • Proper test cleanup between cases
  • Accessibility-focused element queries
  • Event handling verification
  • Comprehensive state management testing
  • Modular test organization with describe/test blocks

gradio-app/gradio

js/radio/Radio.test.ts

            
import { test, describe, assert, afterEach } from "vitest";

import { cleanup, render } from "@self/tootils";
import event from "@testing-library/user-event";

import Radio from "./Index.svelte";

describe("Radio", () => {
	afterEach(() => cleanup());
	const choices = [
		["dog", "dog"],
		["cat", "cat"],
		["turtle", "turtle"]
	] as [string, string][];

	test("renders provided value", async () => {
		const { getAllByRole, getByTestId } = await render(Radio, {
			choices: choices,
			value: "cat",
			label: "Radio"
		});

		const cat_radio = getAllByRole("radio")[1];

		expect(cat_radio).toBeChecked();

		const radioButtons: HTMLOptionElement[] = getAllByRole(
			"radio"
		) as HTMLOptionElement[];
		assert.equal(radioButtons.length, 3);

		radioButtons.forEach((radioButton: HTMLOptionElement, index) => {
			assert.equal(radioButton.value === choices[index][1], true);
		});
	});

	test("should update the value when a radio is clicked", async () => {
		const { getByDisplayValue, getAllByRole } = await render(Radio, {
			choices: choices,
			value: "cat",
			label: "Radio"
		});

		const dog_radio = getAllByRole("radio")[0];

		await event.click(dog_radio);

		expect(dog_radio).toBeChecked();

		const cat_radio = getAllByRole("radio")[1];

		expect(cat_radio).not.toBeChecked();

		await event.click(getByDisplayValue("turtle"));

		await event.click(cat_radio);

		expect(cat_radio).toBeChecked();
	});

	test("should dispatch the select event when clicks", async () => {
		const { listen, getAllByTestId } = await render(Radio, {
			choices: choices,
			value: "cat",
			label: "Radio"
		});

		const mock = listen("select");
		await event.click(getAllByTestId("dog-radio-label")[0]);
		expect(mock.callCount).toBe(1);
		expect(mock.calls[0][0].detail.data.value).toEqual("dog");
	});

	test("when multiple radios are on the screen, they should not conflict", async () => {
		const { container } = await render(Radio, {
			choices: choices,
			value: "cat",
			label: "Radio"
		});

		const { getAllByLabelText } = await render(
			Radio,
			{
				choices: choices,
				value: "dog",
				label: "Radio"
			},
			container
		);

		const items = getAllByLabelText("dog") as HTMLInputElement[];
		expect([items[0].checked, items[1].checked]).toEqual([false, true]);

		await event.click(items[0]);

		expect([items[0].checked, items[1].checked]).toEqual([true, true]);
		cleanup();
	});
});