Back to Repositories

Testing Stream Utility Implementation for Video Components in Gradio

This test suite validates the stream utility functions in Gradio’s video handling implementation, focusing on device enumeration, stream management, and video source configuration. The tests ensure proper media device handling and stream setup for video components.

Test Coverage Overview

The test suite provides comprehensive coverage of core media streaming functionality:

  • Device enumeration and filtering
  • Local stream configuration and setup
  • Video stream acquisition with constraints
  • Media device management and filtering
Edge cases include handling of different device types and mock implementations of MediaStream APIs.

Implementation Analysis

The testing approach utilizes Vitest for mocking and assertions, with careful consideration of browser APIs. The implementation employs mock functions for mediaDevices API, providing controlled test environments for stream handling.

Key patterns include Promise-based async testing, spy functionality for method verification, and TypeScript type assertions for media device interfaces.

Technical Details

  • Testing Framework: Vitest
  • Mocking Utilities: vi.fn(), vi.spyOn()
  • Browser API Mocks: MediaStream, mediaDevices
  • TypeScript Interfaces: MediaDeviceInfo
  • DOM Element Testing: video element manipulation

Best Practices Demonstrated

The test suite exemplifies strong testing practices through isolated test cases, comprehensive mocking of browser APIs, and clear test organization.

  • Proper async/await handling
  • Mock cleanup and restoration
  • Type-safe testing with TypeScript
  • Granular test case separation
  • Meaningful assertions and expectations

gradio-app/gradio

js/image/shared/stream_utils.test.ts

            
import { describe, expect, vi } from "vitest";
import {
	get_devices,
	get_video_stream,
	set_available_devices,
	set_local_stream
} from "./stream_utils";
import * as stream_utils from "./stream_utils";

let test_device: MediaDeviceInfo = {
	deviceId: "test-device",
	kind: "videoinput",
	label: "Test Device",
	groupId: "camera",
	toJSON: () => ({
		deviceId: "test-device",
		kind: "videoinput",
		label: "Test Device",
		groupId: "camera"
	})
};

const mock_enumerateDevices = vi.fn(async () => {
	return new Promise<MediaDeviceInfo[]>((resolve) => {
		resolve([test_device]);
	});
});
const mock_getUserMedia = vi.fn(async () => {
	return new Promise<MediaStream>((resolve) => {
		resolve(new MediaStream());
	});
});

window.MediaStream = vi.fn().mockImplementation(() => ({}));

Object.defineProperty(global.navigator, "mediaDevices", {
	value: {
		getUserMedia: mock_getUserMedia,
		enumerateDevices: mock_enumerateDevices
	}
});

describe("stream_utils", () => {
	test("get_devices should enumerate media devices", async () => {
		const devices = await get_devices();
		expect(devices).toEqual([test_device]);
	});

	test("set_local_stream should set the local stream to the video source", () => {
		const mock_stream = {}; // mocked MediaStream obj as it's not available in a node env

		const mock_video_source = {
			srcObject: null,
			muted: false,
			play: vi.fn()
		};

		// @ts-ignore
		set_local_stream(mock_stream, mock_video_source);

		expect(mock_video_source.srcObject).toEqual(mock_stream);
		expect(mock_video_source.muted).toBeTruthy();
		expect(mock_video_source.play).toHaveBeenCalled();
	});

	test("get_video_stream requests user media with the correct constraints and sets the local stream", async () => {
		const mock_video_source = document.createElement("video");
		const mock_stream = new MediaStream();

		global.navigator.mediaDevices.getUserMedia = vi
			.fn()
			.mockResolvedValue(mock_stream);

		await get_video_stream(true, mock_video_source);

		expect(navigator.mediaDevices.getUserMedia).toHaveBeenCalledWith({
			video: { width: { ideal: 1920 }, height: { ideal: 1440 } },
			audio: true
		});

		const spy_set_local_stream = vi.spyOn(stream_utils, "set_local_stream");
		stream_utils.set_local_stream(mock_stream, mock_video_source);

		expect(spy_set_local_stream).toHaveBeenCalledWith(
			mock_stream,
			mock_video_source
		);
		spy_set_local_stream.mockRestore();
	});

	test("set_available_devices should return only video input devices", () => {
		const mockDevices: MediaDeviceInfo[] = [
			{
				deviceId: "camera1",
				kind: "videoinput",
				label: "Camera 1",
				groupId: "camera",
				toJSON: () => ({
					deviceId: "camera1",
					kind: "videoinput",
					label: "Camera 1",
					groupId: "camera"
				})
			},
			{
				deviceId: "camera2",
				kind: "videoinput",
				label: "Camera 2",
				groupId: "camera",
				toJSON: () => ({
					deviceId: "camera2",
					kind: "videoinput",
					label: "Camera 2",
					groupId: "camera"
				})
			},
			{
				deviceId: "audio1",
				kind: "audioinput",
				label: "Audio 2",
				groupId: "audio",
				toJSON: () => ({
					deviceId: "audio1",
					kind: "audioinput",
					label: "Audio 2",
					groupId: "audio"
				})
			}
		];

		const videoDevices = set_available_devices(mockDevices);
		expect(videoDevices).toEqual(mockDevices.splice(0, 2));
	});
});