Files
wehub-resource-sync b7f52be4c9
CI / Run CI (push) Has been cancelled
CI / check-backend (push) Has been cancelled
CI / check-frontend (push) Has been cancelled
CI / tests (push) Has been cancelled
CI / e2e-tests (push) Has been cancelled
Copilot Setup Steps / copilot-setup-steps (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:48:47 +08:00

344 lines
14 KiB
Python

import pytest
from chainlit.chat_settings import ChatSettings
from chainlit.input_widget import (
Checkbox,
NumberInput,
Select,
Slider,
Switch,
Tab,
TextInput,
)
@pytest.mark.asyncio
class TestChatSettings:
"""Test suite for ChatSettings class."""
async def test_chat_settings_initialization(self, mock_chainlit_context):
"""Test ChatSettings initialization with input widgets."""
async with mock_chainlit_context:
switch = Switch(id="enable_feature", label="Enable Feature")
slider = Slider(id="temperature", label="Temperature", initial=0.7)
settings = ChatSettings(inputs=[switch, slider])
assert len(settings.inputs) == 2
assert settings.inputs[0] == switch
assert settings.inputs[1] == slider
async def test_chat_settings_with_empty_inputs(self, mock_chainlit_context):
"""Test ChatSettings with empty inputs list."""
async with mock_chainlit_context:
settings = ChatSettings(inputs=[])
assert settings.inputs == []
async def test_chat_settings_settings_method(self, mock_chainlit_context):
"""Test ChatSettings.settings() method returns initial values."""
async with mock_chainlit_context:
switch = Switch(id="enable_feature", label="Enable", initial=True)
slider = Slider(id="temperature", label="Temperature", initial=0.7)
text = TextInput(id="model", label="Model", initial="gpt-4")
settings = ChatSettings(inputs=[switch, slider, text])
result = settings.settings()
assert result["enable_feature"] is True
assert result["temperature"] == 0.7
assert result["model"] == "gpt-4"
async def test_chat_settings_with_tabs(self, mock_chainlit_context):
"""Test ChatSettings with Tab containers."""
async with mock_chainlit_context:
# Create inputs for tabs
switch1 = Switch(id="switch1", label="Switch 1", initial=True)
slider1 = Slider(id="slider1", label="Slider 1", initial=5)
switch2 = Switch(id="switch2", label="Switch 2", initial=False)
text2 = TextInput(id="text2", label="Text 2", initial="value")
# Create tabs
tab1 = Tab(id="tab1", label="Tab 1", inputs=[switch1, slider1])
tab2 = Tab(id="tab2", label="Tab 2", inputs=[switch2, text2])
settings = ChatSettings(inputs=[tab1, tab2])
assert len(settings.inputs) == 2
assert isinstance(settings.inputs[0], Tab)
assert isinstance(settings.inputs[1], Tab)
async def test_chat_settings_settings_with_tabs(self, mock_chainlit_context):
"""Test ChatSettings.settings() collects values from tabs."""
async with mock_chainlit_context:
switch1 = Switch(id="switch1", label="Switch 1", initial=True)
slider1 = Slider(id="slider1", label="Slider 1", initial=5)
switch2 = Switch(id="switch2", label="Switch 2", initial=False)
text2 = TextInput(id="text2", label="Text 2", initial="value")
tab1 = Tab(id="tab1", label="Tab 1", inputs=[switch1, slider1])
tab2 = Tab(id="tab2", label="Tab 2", inputs=[switch2, text2])
settings = ChatSettings(inputs=[tab1, tab2])
result = settings.settings()
# Should collect all inputs from all tabs
assert result["switch1"] is True
assert result["slider1"] == 5
assert result["switch2"] is False
assert result["text2"] == "value"
async def test_chat_settings_send(self, mock_chainlit_context):
"""Test ChatSettings.send() method."""
async with mock_chainlit_context as ctx:
switch = Switch(id="enable", label="Enable", initial=True)
slider = Slider(id="temp", label="Temperature", initial=0.8)
settings = ChatSettings(inputs=[switch, slider])
result = await settings.send()
# Verify settings were returned
assert result["enable"] is True
assert result["temp"] == 0.8
# Verify emitter methods were called
ctx.emitter.set_chat_settings.assert_called_once_with(result)
ctx.emitter.emit.assert_called_once()
# Verify emit was called with correct arguments
call_args = ctx.emitter.emit.call_args
assert call_args[0][0] == "chat_settings"
assert len(call_args[0][1]) == 2 # Two inputs
async def test_chat_settings_refresh(self, mock_chainlit_context):
"""Test ChatSettings.refresh() emits UI without updating session."""
async with mock_chainlit_context as ctx:
switch = Switch(id="enable", label="Enable", initial=True)
slider = Slider(id="temp", label="Temperature", initial=0.8)
settings = ChatSettings(inputs=[switch, slider])
result = await settings.refresh()
assert result["enable"] is True
assert result["temp"] == 0.8
ctx.emitter.set_chat_settings.assert_not_called()
ctx.emitter.emit.assert_called_once()
call_args = ctx.emitter.emit.call_args
assert call_args[0][0] == "chat_settings"
assert len(call_args[0][1]) == 2
async def test_chat_settings_send_with_tabs(self, mock_chainlit_context):
"""Test ChatSettings.send() with tabs."""
async with mock_chainlit_context as ctx:
switch = Switch(id="switch1", label="Switch", initial=True)
slider = Slider(id="slider1", label="Slider", initial=5)
tab = Tab(id="tab1", label="Settings", inputs=[switch, slider])
settings = ChatSettings(inputs=[tab])
result = await settings.send()
# Verify settings collected from tab
assert result["switch1"] is True
assert result["slider1"] == 5
# Verify emitter was called
ctx.emitter.set_chat_settings.assert_called_once()
ctx.emitter.emit.assert_called_once()
async def test_chat_settings_with_all_widget_types(self, mock_chainlit_context):
"""Test ChatSettings with all widget types."""
async with mock_chainlit_context:
widgets = [
Switch(id="switch", label="Switch", initial=True),
Slider(id="slider", label="Slider", initial=5, min=0, max=10),
Select(
id="select",
label="Select",
values=["a", "b", "c"],
initial_index=1,
),
TextInput(id="text", label="Text", initial="hello"),
NumberInput(id="number", label="Number", initial=42.0),
Checkbox(id="checkbox", label="Checkbox", initial=False),
]
settings = ChatSettings(inputs=widgets)
result = settings.settings()
assert result["switch"] is True
assert result["slider"] == 5
assert result["select"] == "b"
assert result["text"] == "hello"
assert result["number"] == 42.0
assert result["checkbox"] is False
async def test_chat_settings_with_nested_tabs(self, mock_chainlit_context):
"""Test ChatSettings.settings() with nested structure."""
async with mock_chainlit_context:
# Create multiple tabs with different inputs
tab1_inputs = [
Switch(id="t1_switch", label="T1 Switch", initial=True),
Slider(id="t1_slider", label="T1 Slider", initial=3),
]
tab2_inputs = [
TextInput(id="t2_text", label="T2 Text", initial="test"),
Checkbox(id="t2_check", label="T2 Check", initial=True),
]
tab1 = Tab(id="tab1", label="Tab 1", inputs=tab1_inputs)
tab2 = Tab(id="tab2", label="Tab 2", inputs=tab2_inputs)
settings = ChatSettings(inputs=[tab1, tab2])
result = settings.settings()
# All inputs from all tabs should be collected
assert result["t1_switch"] is True
assert result["t1_slider"] == 3
assert result["t2_text"] == "test"
assert result["t2_check"] is True
assert len(result) == 4
async def test_chat_settings_only_widgets_or_only_tabs(self, mock_chainlit_context):
"""Test that ChatSettings accepts either all widgets or all tabs, not mixed."""
async with mock_chainlit_context:
# Test with only widgets
widgets = [
Switch(id="switch", label="Switch", initial=True),
Slider(id="slider", label="Slider", initial=7),
]
settings_widgets = ChatSettings(inputs=widgets)
result_widgets = settings_widgets.settings()
assert result_widgets["switch"] is True
assert result_widgets["slider"] == 7
# Test with only tabs
tab1 = Tab(
id="tab1",
label="Tab 1",
inputs=[Switch(id="t1_switch", label="Switch", initial=False)],
)
tab2 = Tab(
id="tab2",
label="Tab 2",
inputs=[Slider(id="t2_slider", label="Slider", initial=3)],
)
settings_tabs = ChatSettings(inputs=[tab1, tab2])
result_tabs = settings_tabs.settings()
assert result_tabs["t1_switch"] is False
assert result_tabs["t2_slider"] == 3
async def test_chat_settings_with_none_initial_values(self, mock_chainlit_context):
"""Test ChatSettings with widgets having None initial values."""
async with mock_chainlit_context:
text = TextInput(id="text", label="Text", initial=None)
number = NumberInput(id="number", label="Number", initial=None)
select = Select(
id="select", label="Select", values=["a", "b"], initial_value=None
)
settings = ChatSettings(inputs=[text, number, select])
result = settings.settings()
assert result["text"] is None
assert result["number"] is None
assert result["select"] is None
@pytest.mark.asyncio
class TestChatSettingsEdgeCases:
"""Test suite for ChatSettings edge cases."""
async def test_chat_settings_empty_tabs(self, mock_chainlit_context):
"""Test ChatSettings with empty tabs."""
async with mock_chainlit_context:
empty_tab = Tab(id="empty", label="Empty Tab", inputs=[])
settings = ChatSettings(inputs=[empty_tab])
result = settings.settings()
assert result == {}
async def test_chat_settings_duplicate_ids(self, mock_chainlit_context):
"""Test ChatSettings behavior with duplicate IDs (last one wins)."""
async with mock_chainlit_context:
switch1 = Switch(id="duplicate", label="Switch 1", initial=True)
switch2 = Switch(id="duplicate", label="Switch 2", initial=False)
settings = ChatSettings(inputs=[switch1, switch2])
result = settings.settings()
# Last value should win
assert result["duplicate"] is False
async def test_chat_settings_send_returns_settings(self, mock_chainlit_context):
"""Test that send() returns the settings dictionary."""
async with mock_chainlit_context:
switch = Switch(id="test", label="Test", initial=True)
settings = ChatSettings(inputs=[switch])
result = await settings.send()
assert isinstance(result, dict)
assert "test" in result
assert result["test"] is True
async def test_chat_settings_to_dict_serialization(self, mock_chainlit_context):
"""Test that inputs are properly serialized in send()."""
async with mock_chainlit_context as ctx:
switch = Switch(id="switch", label="Switch", initial=True)
slider = Slider(id="slider", label="Slider", initial=5)
settings = ChatSettings(inputs=[switch, slider])
await settings.send()
# Check that emit was called with serialized inputs
call_args = ctx.emitter.emit.call_args
inputs_content = call_args[0][1]
assert len(inputs_content) == 2
assert inputs_content[0]["type"] == "switch"
assert inputs_content[0]["id"] == "switch"
assert inputs_content[1]["type"] == "slider"
assert inputs_content[1]["id"] == "slider"
async def test_chat_settings_with_complex_tab_structure(
self, mock_chainlit_context
):
"""Test ChatSettings with complex tab structure."""
async with mock_chainlit_context:
# Create a complex structure with multiple tabs
tab1 = Tab(
id="general",
label="General",
inputs=[
Switch(id="enabled", label="Enabled", initial=True),
TextInput(id="name", label="Name", initial="MyApp"),
],
)
tab2 = Tab(
id="advanced",
label="Advanced",
inputs=[
Slider(id="timeout", label="Timeout", initial=30, min=0, max=60),
Select(
id="mode",
label="Mode",
values=["dev", "prod"],
initial_index=0,
),
],
)
settings = ChatSettings(inputs=[tab1, tab2])
result = settings.settings()
assert result["enabled"] is True
assert result["name"] == "MyApp"
assert result["timeout"] == 30
assert result["mode"] == "dev"
assert len(result) == 4