From 698453bda0b4c4bf37119f9994f64228cbf95e9c Mon Sep 17 00:00:00 2001 From: Peter Parente Date: Mon, 8 Jan 2024 23:10:08 -0500 Subject: [PATCH] Add RichTextList element and tests --- blockkit/elements.py | 22 +++++++++++---- blockkit/enums.py | 7 ++++- tests/test_blocks.py | 64 ++++++++++++++++++++++++++++++++++++++++++ tests/test_elements.py | 50 +++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 6 deletions(-) diff --git a/blockkit/elements.py b/blockkit/elements.py index a45a67b..55700f2 100644 --- a/blockkit/elements.py +++ b/blockkit/elements.py @@ -6,7 +6,7 @@ from pydantic.networks import HttpUrl from blockkit.components import Component -from blockkit.enums import Style +from blockkit.enums import ListStyle, Style from blockkit.objects import ( Confirm, DispatchActionConfig, @@ -679,10 +679,6 @@ def __init__( RichTextObject = Union[Text, Emoji] -class RichTextList(Component): - type: str = "rich_text_list" - - class RichTextPreformatted(Component): type: str = "rich_text_preformatted" elements: List[RichTextObject] = Field(..., min_length=1) @@ -705,3 +701,19 @@ class RichTextSection(Component): def __init__(self, *, elements: List[RichTextObject]): super().__init__(elements=elements) + + +class RichTextList(Component): + type: str = "rich_text_list" + elements: List[RichTextSection] = Field(..., min_length=1) + style: Optional[ListStyle] = None + indent: Optional[int] = Field(..., ge=0, le=8) + + def __init__( + self, + *, + elements: List[RichTextSection], + style: Optional[ListStyle] = None, + indent: Optional[int] = None, + ): + super().__init__(elements=elements, style=style, indent=indent) diff --git a/blockkit/enums.py b/blockkit/enums.py index b36a50c..4fb68c7 100644 --- a/blockkit/enums.py +++ b/blockkit/enums.py @@ -1,6 +1,11 @@ from enum import Enum -__all__ = ["Style", "TriggerActionsOn", "Include"] +__all__ = ["ListStyle", "Style", "TriggerActionsOn", "Include"] + + +class ListStyle(str, Enum): + ordered = "ordered" + bullet = "bullet" class Style(str, Enum): diff --git a/tests/test_blocks.py b/tests/test_blocks.py index 6887880..1e0ce70 100644 --- a/tests/test_blocks.py +++ b/tests/test_blocks.py @@ -15,6 +15,7 @@ from blockkit.elements import ( Button, Image, + RichTextList, RichTextPreformatted, RichTextQuote, RichTextSection, @@ -291,6 +292,26 @@ def test_builds_rich_text(): Text(text="a section"), ] ), + RichTextList( + style="ordered", + elements=[ + RichTextSection(elements=[Text(text="a bullet")]), + RichTextSection(elements=[Text(text="a another bullet")]), + ], + ), + RichTextList( + style="ordered", + indent=1, + elements=[ + RichTextSection(elements=[Text(text="a nested bullet")]), + ], + ), + RichTextList( + style="ordered", + elements=[ + RichTextSection(elements=[Text(text="an un-nested bullet")]), + ], + ), ] ).build() == { "type": "rich_text", @@ -313,6 +334,49 @@ def test_builds_rich_text(): {"type": "text", "text": "a section"}, ], }, + { + "type": "rich_text_list", + "style": "ordered", + "elements": [ + { + "type": "rich_text_section", + "elements": [ + {"type": "text", "text": "a bullet"}, + ], + }, + { + "type": "rich_text_section", + "elements": [ + {"type": "text", "text": "a another bullet"}, + ], + }, + ], + }, + { + "type": "rich_text_list", + "style": "ordered", + "indent": 1, + "elements": [ + { + "type": "rich_text_section", + "elements": [ + {"type": "text", "text": "a nested bullet"}, + ], + }, + ], + }, + { + "type": "rich_text_list", + "style": "ordered", + "elements": [ + { + "type": "rich_text_section", + "elements": [ + {"type": "text", "text": "an un-nested bullet"}, + ], + }, + ], + }, ], } diff --git a/tests/test_elements.py b/tests/test_elements.py index 8483e0e..08f5022 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -21,6 +21,7 @@ Overflow, PlainTextInput, RadioButtons, + RichTextList, RichTextPreformatted, RichTextQuote, RichTextSection, @@ -1467,6 +1468,55 @@ def test_empty_rich_text_section_raises_exception(): RichTextSection(elements=[]) +def test_builds_rich_text_list(): + assert RichTextList( + style="ordered", + indent=1, + elements=[ + RichTextSection(elements=[Text(text="My first bullet point")]), + RichTextSection(elements=[Text(text="My second bullet point")]), + ], + ).build() == { + "type": "rich_text_list", + "style": "ordered", + "indent": 1, + "elements": [ + { + "type": "rich_text_section", + "elements": [{"type": "text", "text": "My first bullet point"}], + }, + { + "type": "rich_text_section", + "elements": [{"type": "text", "text": "My second bullet point"}], + }, + ], + } + + +def test_empty_rich_text_list_raises_exception(): + with pytest.raises(ValidationError): + RichTextList(elements=[]) + + +@pytest.fixture(scope="module") +def minimal_rich_text_list_elements(): + return [RichTextSection(elements=[Text(text="a")])] + + +def test_invalid_rich_text_list_style_raises_exception(minimal_rich_text_list_elements): + with pytest.raises(ValidationError): + RichTextList(elements=minimal_rich_text_list_elements, style="invalid") + + +def test_invalid_rich_text_list_indent_raises_exception( + minimal_rich_text_list_elements, +): + with pytest.raises(ValidationError): + RichTextList(elements=minimal_rich_text_list_elements, indent=-1) + with pytest.raises(ValidationError): + RichTextList(elements=minimal_rich_text_list_elements, indent=9) + + def test_builds_timepicker(): assert TimePicker( action_id="action_id",