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

282 lines
9.6 KiB
Python

import uuid
import pytest
from chainlit.action import Action
@pytest.mark.asyncio
class TestAction:
"""Test suite for the Action class."""
async def test_action_initialization_with_required_fields(self):
"""Test Action initialization with only required fields."""
action = Action(
name="test_action",
payload={"key": "value"},
)
assert action.name == "test_action"
assert action.payload == {"key": "value"}
assert action.label == ""
assert action.tooltip == ""
assert action.icon is None
assert action.forId is None
assert isinstance(action.id, str)
# Verify ID is a valid UUID
uuid.UUID(action.id)
async def test_action_initialization_with_all_fields(self):
"""Test Action initialization with all fields provided."""
test_id = str(uuid.uuid4())
action = Action(
name="custom_action",
payload={"param1": "value1", "param2": 42},
label="Click Me",
tooltip="This is a tooltip",
icon="check-circle",
id=test_id,
)
assert action.name == "custom_action"
assert action.payload == {"param1": "value1", "param2": 42}
assert action.label == "Click Me"
assert action.tooltip == "This is a tooltip"
assert action.icon == "check-circle"
assert action.id == test_id
assert action.forId is None
async def test_action_id_auto_generation(self):
"""Test that Action generates unique IDs automatically."""
action1 = Action(name="action1", payload={})
action2 = Action(name="action2", payload={})
assert action1.id != action2.id
# Verify both are valid UUIDs
uuid.UUID(action1.id)
uuid.UUID(action2.id)
async def test_action_to_dict(self):
"""Test Action serialization to dictionary."""
test_id = str(uuid.uuid4())
action = Action(
name="test_action",
payload={"data": "test"},
label="Test Label",
tooltip="Test Tooltip",
icon="star",
id=test_id,
)
action_dict = action.to_dict()
assert action_dict["name"] == "test_action"
assert action_dict["payload"] == {"data": "test"}
assert action_dict["label"] == "Test Label"
assert action_dict["tooltip"] == "Test Tooltip"
assert action_dict["icon"] == "star"
assert action_dict["id"] == test_id
assert action_dict.get("forId") is None
async def test_action_to_dict_with_for_id(self):
"""Test Action serialization includes forId when set."""
action = Action(name="test", payload={})
action.forId = "message_123"
action_dict = action.to_dict()
assert action_dict["forId"] == "message_123"
async def test_action_send(self, mock_chainlit_context):
"""Test Action.send() method emits correct event."""
async with mock_chainlit_context as ctx:
action = Action(
name="send_action",
payload={"test": "data"},
label="Send Test",
)
for_id = "target_message_id"
await action.send(for_id=for_id)
# Verify forId was set
assert action.forId == for_id
# Verify emit was called with correct parameters
ctx.emitter.emit.assert_called_once()
call_args = ctx.emitter.emit.call_args
assert call_args[0][0] == "action"
emitted_dict = call_args[0][1]
assert emitted_dict["name"] == "send_action"
assert emitted_dict["payload"] == {"test": "data"}
assert emitted_dict["label"] == "Send Test"
assert emitted_dict["forId"] == for_id
async def test_action_send_updates_for_id(self, mock_chainlit_context):
"""Test that send() updates the forId field."""
async with mock_chainlit_context:
action = Action(name="test", payload={})
# Initially forId should be None
assert action.forId is None
# Send with first for_id
await action.send(for_id="first_id")
assert action.forId == "first_id"
# Send with different for_id should update
await action.send(for_id="second_id")
assert action.forId == "second_id"
async def test_action_remove(self, mock_chainlit_context):
"""Test Action.remove() method emits correct event."""
async with mock_chainlit_context as ctx:
action = Action(
name="remove_action",
payload={"key": "value"},
label="Remove Test",
)
action.forId = "message_123"
await action.remove()
# Verify emit was called with correct parameters
ctx.emitter.emit.assert_called_once()
call_args = ctx.emitter.emit.call_args
assert call_args[0][0] == "remove_action"
emitted_dict = call_args[0][1]
assert emitted_dict["name"] == "remove_action"
assert emitted_dict["payload"] == {"key": "value"}
assert emitted_dict["forId"] == "message_123"
async def test_action_remove_without_for_id(self, mock_chainlit_context):
"""Test Action.remove() works even without forId set."""
async with mock_chainlit_context as ctx:
action = Action(name="test", payload={})
await action.remove()
ctx.emitter.emit.assert_called_once()
call_args = ctx.emitter.emit.call_args
assert call_args[0][0] == "remove_action"
async def test_action_with_complex_payload(self):
"""Test Action with complex nested payload."""
complex_payload = {
"nested": {
"data": [1, 2, 3],
"info": {"key": "value"},
},
"list": ["a", "b", "c"],
"number": 42,
"boolean": True,
"null": None,
}
action = Action(name="complex", payload=complex_payload)
assert action.payload == complex_payload
action_dict = action.to_dict()
assert action_dict["payload"] == complex_payload
async def test_action_with_empty_payload(self):
"""Test Action with empty payload."""
action = Action(name="empty", payload={})
assert action.payload == {}
assert action.to_dict()["payload"] == {}
async def test_action_with_empty_strings(self):
"""Test Action handles empty strings correctly."""
action = Action(
name="test",
payload={},
label="",
tooltip="",
)
assert action.label == ""
assert action.tooltip == ""
action_dict = action.to_dict()
assert action_dict["label"] == ""
assert action_dict["tooltip"] == ""
async def test_action_serialization_deserialization(self):
"""Test Action can be serialized and deserialized."""
original = Action(
name="serialize_test",
payload={"data": "test"},
label="Test",
tooltip="Tooltip",
icon="icon-name",
)
# Serialize to dict
serialized = original.to_dict()
# Deserialize from dict
deserialized = Action.from_dict(serialized)
assert deserialized.name == original.name
assert deserialized.payload == original.payload
assert deserialized.label == original.label
assert deserialized.tooltip == original.tooltip
assert deserialized.icon == original.icon
assert deserialized.id == original.id
async def test_multiple_actions_with_same_name(self):
"""Test that multiple actions can have the same name but different IDs."""
action1 = Action(name="duplicate", payload={"num": 1})
action2 = Action(name="duplicate", payload={"num": 2})
assert action1.name == action2.name
assert action1.id != action2.id
assert action1.payload != action2.payload
async def test_action_send_multiple_times(self, mock_chainlit_context):
"""Test that an action can be sent multiple times."""
async with mock_chainlit_context as ctx:
action = Action(name="multi_send", payload={})
await action.send(for_id="id1")
await action.send(for_id="id2")
await action.send(for_id="id3")
# Should have been called 3 times
assert ctx.emitter.emit.call_count == 3
# Last forId should be id3
assert action.forId == "id3"
async def test_action_with_special_characters_in_payload(self):
"""Test Action handles special characters in payload."""
special_payload = {
"unicode": "Hello 世界 🌍",
"quotes": 'He said "Hello"',
"newlines": "Line1\nLine2\nLine3",
"tabs": "Col1\tCol2\tCol3",
}
action = Action(name="special", payload=special_payload)
assert action.payload == special_payload
action_dict = action.to_dict()
assert action_dict["payload"] == special_payload
async def test_action_icon_variations(self):
"""Test Action with different icon values."""
# With icon
action_with_icon = Action(name="test", payload={}, icon="check")
assert action_with_icon.icon == "check"
# Without icon (None)
action_no_icon = Action(name="test", payload={}, icon=None)
assert action_no_icon.icon is None
# Default (should be None)
action_default = Action(name="test", payload={})
assert action_default.icon is None