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
344 lines
14 KiB
Python
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
|