diff --git a/block-kit/README.md b/block-kit/README.md index 9785597..2247c03 100644 --- a/block-kit/README.md +++ b/block-kit/README.md @@ -24,3 +24,15 @@ Read the [docs](https://docs.slack.dev/block-kit/) to learn concepts behind thes - **[Table](https://docs.slack.dev/reference/block-kit/blocks/table-block)**: Displays structured information in a table. [Implementation](./src/blocks/table.py). - **[Task card](https://docs.slack.dev/reference/block-kit/blocks/task-card-block)**: Displays a single task, representing a single action. [Implementation](./src/blocks/task_card.py). - **[Video](https://docs.slack.dev/reference/block-kit/blocks/video-block)**: Displays an embedded video player. [Implementation](./src/blocks/video.py). + +### Composition objects + +- **[Confirmation dialog](https://docs.slack.dev/reference/block-kit/composition-objects/confirmation-dialog-object)**: Defines a dialog that adds a confirmation step to interactive elements. [Implementation](./src/composition_objects/confirmation_dialog.py). +- **[Conversation filter](https://docs.slack.dev/reference/block-kit/composition-objects/conversation-filter-object)**: Defines a filter for the list of options in a conversation selector menu. [Implementation](./src/composition_objects/conversation_filter.py). +- **[Dispatch action configuration](https://docs.slack.dev/reference/block-kit/composition-objects/dispatch-action-configuration-object)**: Defines when a plain-text input element will return a block_actions interaction payload. [Implementation](./src/composition_objects/dispatch_action_configuration.py). +- **[Option](https://docs.slack.dev/reference/block-kit/composition-objects/option-object)**: Defines a single item in a number of item selection elements. [Implementation](./src/composition_objects/option.py). +- **[Option group](https://docs.slack.dev/reference/block-kit/composition-objects/option-group-object)**: Defines a way to group options in a menu. [Implementation](./src/composition_objects/option_group.py). +- **[Slack file](https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object)**: Defines an object containing Slack file information to be used in an image block or image element. [Implementation](./src/composition_objects/slack_file.py). +- **[Text](https://docs.slack.dev/reference/block-kit/composition-objects/text-object)**: Defines an object containing some text. [Implementation](./src/composition_objects/text.py). +- **[Trigger](https://docs.slack.dev/reference/block-kit/composition-objects/trigger-object)**: Defines an object containing trigger information. [Implementation](./src/composition_objects/trigger.py). +- **[Workflow](https://docs.slack.dev/reference/block-kit/composition-objects/workflow-object)**: Defines an object containing workflow information. [Implementation](./src/composition_objects/workflow.py). diff --git a/block-kit/src/composition_objects/__init__.py b/block-kit/src/composition_objects/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/block-kit/src/composition_objects/confirmation_dialog.py b/block-kit/src/composition_objects/confirmation_dialog.py new file mode 100644 index 0000000..d3cfea8 --- /dev/null +++ b/block-kit/src/composition_objects/confirmation_dialog.py @@ -0,0 +1,39 @@ +from slack_sdk.models.blocks import ActionsBlock +from slack_sdk.models.blocks.basic_components import ( + ConfirmObject, + MarkdownTextObject, + PlainTextObject, +) +from slack_sdk.models.blocks.block_elements import ButtonElement + + +def example01() -> ActionsBlock: + """ + Defines a dialog that adds a confirmation step to interactive elements. + https://docs.slack.dev/reference/block-kit/composition-objects/confirmation-dialog-object/ + + An actions block with a button that opens a confirmation dialog. + """ + block = ActionsBlock( + elements=[ + ButtonElement( + text=PlainTextObject(text="Approve", emoji=True), + confirm=ConfirmObject( + title=PlainTextObject(text="Are you sure?"), + text=MarkdownTextObject( + text="Would you not prefer a good game of _chess_?" + ), + confirm=PlainTextObject(text="Do it"), + deny=PlainTextObject(text="Stop, I changed my mind!"), + ), + style="primary", + value="click_me_123", + ), + ButtonElement( + text=PlainTextObject(text="Deny", emoji=True), + style="danger", + value="click_me_123", + ), + ], + ) + return block diff --git a/block-kit/src/composition_objects/conversation_filter.py b/block-kit/src/composition_objects/conversation_filter.py new file mode 100644 index 0000000..a854f4e --- /dev/null +++ b/block-kit/src/composition_objects/conversation_filter.py @@ -0,0 +1,40 @@ +from slack_sdk.models.blocks import InputBlock +from slack_sdk.models.blocks.basic_components import PlainTextObject +from slack_sdk.models.blocks.block_elements import ( + ConversationFilter, + ConversationSelectElement, +) +from slack_sdk.models.views import View + + +def example01() -> View: + """ + Defines a filter for the list of options in a conversation selector menu. + https://docs.slack.dev/reference/block-kit/composition-objects/conversation-filter-object/ + + A modal view whose conversations select filters the listed conversations. + """ + view = View( + type="modal", + title=PlainTextObject(text="My App", emoji=True), + submit=PlainTextObject(text="Submit", emoji=True), + close=PlainTextObject(text="Cancel", emoji=True), + blocks=[ + InputBlock( + element=ConversationSelectElement( + placeholder=PlainTextObject( + text="Select a conversation", emoji=True + ), + filter=ConversationFilter( + include=["public", "mpim"], + exclude_bot_users=True, + ), + ), + label=PlainTextObject( + text="Choose the conversation to publish your result to:", + emoji=True, + ), + ), + ], + ) + return view diff --git a/block-kit/src/composition_objects/dispatch_action_configuration.py b/block-kit/src/composition_objects/dispatch_action_configuration.py new file mode 100644 index 0000000..563da2c --- /dev/null +++ b/block-kit/src/composition_objects/dispatch_action_configuration.py @@ -0,0 +1,26 @@ +from slack_sdk.models.blocks import InputBlock +from slack_sdk.models.blocks.basic_components import ( + DispatchActionConfig, + PlainTextObject, +) +from slack_sdk.models.blocks.block_elements import PlainTextInputElement + + +def example01() -> InputBlock: + """ + Defines when a plain-text input element will return a block_actions interaction payload. + https://docs.slack.dev/reference/block-kit/composition-objects/dispatch-action-configuration-object/ + + An input block whose plain-text input dispatches actions on character entry. + """ + block = InputBlock( + dispatch_action=True, + element=PlainTextInputElement( + multiline=True, + dispatch_action_config=DispatchActionConfig( + trigger_actions_on=["on_character_entered"], + ), + ), + label=PlainTextObject(text="This is a multiline plain-text input", emoji=True), + ) + return block diff --git a/block-kit/src/composition_objects/option.py b/block-kit/src/composition_objects/option.py new file mode 100644 index 0000000..5938550 --- /dev/null +++ b/block-kit/src/composition_objects/option.py @@ -0,0 +1,56 @@ +from slack_sdk.models.blocks import Block, DividerBlock, SectionBlock +from slack_sdk.models.blocks.basic_components import ( + MarkdownTextObject, + Option, + PlainTextObject, +) +from slack_sdk.models.blocks.block_elements import StaticSelectElement + + +def example01() -> Option: + """ + Defines a single item in a number of item selection elements. + https://docs.slack.dev/reference/block-kit/composition-objects/option-object/ + + A single option object. + """ + option = Option( + text=PlainTextObject(text="Save it", emoji=True), + value="value-2", + ) + return option + + +def example02() -> list[Block]: + """ + Options used within a select menu accessory on a section block. + """ + blocks: list[Block] = [ + SectionBlock( + text=MarkdownTextObject(text=":mag: Search results for *Cata*"), + ), + DividerBlock(), + SectionBlock( + text=MarkdownTextObject( + text="**\nUse Case Catalogue for the following departments/roles..." + ), + accessory=StaticSelectElement( + placeholder=PlainTextObject(text="Manage", emoji=True), + options=[ + Option( + text=PlainTextObject(text="Edit it", emoji=True), + value="value-0", + ), + Option( + text=PlainTextObject(text="Read it", emoji=True), + value="value-1", + ), + Option( + text=PlainTextObject(text="Save it", emoji=True), + value="value-2", + ), + ], + ), + ), + ] + return blocks diff --git a/block-kit/src/composition_objects/option_group.py b/block-kit/src/composition_objects/option_group.py new file mode 100644 index 0000000..812387e --- /dev/null +++ b/block-kit/src/composition_objects/option_group.py @@ -0,0 +1,60 @@ +from slack_sdk.models.blocks import Block, DividerBlock, SectionBlock +from slack_sdk.models.blocks.basic_components import ( + MarkdownTextObject, + Option, + OptionGroup, + PlainTextObject, +) +from slack_sdk.models.blocks.block_elements import StaticSelectElement + + +def example01() -> list[Block]: + """ + Defines a way to group options in a menu. + https://docs.slack.dev/reference/block-kit/composition-objects/option-group-object/ + + Option groups used within a select menu accessory on a section block. + """ + blocks: list[Block] = [ + SectionBlock( + text=MarkdownTextObject(text=":mag: Search results for *Cata*"), + ), + DividerBlock(), + SectionBlock( + text=MarkdownTextObject( + text="**\nUse Case Catalogue for the following departments/roles..." + ), + accessory=StaticSelectElement( + placeholder=PlainTextObject(text="Manage", emoji=True), + option_groups=[ + OptionGroup( + label=PlainTextObject(text="Group 1"), + options=[ + Option( + text=PlainTextObject(text="*this is plain_text text*"), + value="value-0", + ), + Option( + text=PlainTextObject(text="*this is plain_text text*"), + value="value-1", + ), + Option( + text=PlainTextObject(text="*this is plain_text text*"), + value="value-2", + ), + ], + ), + OptionGroup( + label=PlainTextObject(text="Group 2"), + options=[ + Option( + text=PlainTextObject(text="*this is plain_text text*"), + value="value-3", + ), + ], + ), + ], + ), + ), + ] + return blocks diff --git a/block-kit/src/composition_objects/slack_file.py b/block-kit/src/composition_objects/slack_file.py new file mode 100644 index 0000000..a6d72a8 --- /dev/null +++ b/block-kit/src/composition_objects/slack_file.py @@ -0,0 +1,33 @@ +from slack_sdk.models.blocks import ImageBlock +from slack_sdk.models.blocks.basic_components import PlainTextObject, SlackFile + + +def example01() -> ImageBlock: + """ + Defines an object containing Slack file information to be used in an image block or image element. + https://docs.slack.dev/reference/block-kit/composition-objects/slack-file-object/ + + An image block referencing a Slack file by URL. + """ + block = ImageBlock( + title=PlainTextObject(text="Please enjoy this photo of a kitten"), + block_id="image4", + slack_file=SlackFile( + url="https://files.slack.com/files-pri/T0123456-F0123456/xyz.png" + ), + alt_text="An incredibly cute kitten.", + ) + return block + + +def example02() -> ImageBlock: + """ + An image block referencing a Slack file by ID. + """ + block = ImageBlock( + title=PlainTextObject(text="Please enjoy this photo of a kitten"), + block_id="image4", + slack_file=SlackFile(id="F0123456"), + alt_text="An incredibly cute kitten.", + ) + return block diff --git a/block-kit/src/composition_objects/text.py b/block-kit/src/composition_objects/text.py new file mode 100644 index 0000000..58977a7 --- /dev/null +++ b/block-kit/src/composition_objects/text.py @@ -0,0 +1,17 @@ +from slack_sdk.models.blocks import SectionBlock +from slack_sdk.models.blocks.basic_components import MarkdownTextObject + + +def example01() -> SectionBlock: + """ + Defines an object containing some text. + https://docs.slack.dev/reference/block-kit/composition-objects/text-object/ + + A section block containing an mrkdwn text object. + """ + block = SectionBlock( + text=MarkdownTextObject( + text="A message *with some bold text* and _some italicized text_." + ) + ) + return block diff --git a/block-kit/src/composition_objects/trigger.py b/block-kit/src/composition_objects/trigger.py new file mode 100644 index 0000000..f70e8af --- /dev/null +++ b/block-kit/src/composition_objects/trigger.py @@ -0,0 +1,42 @@ +from slack_sdk.models.blocks import SectionBlock +from slack_sdk.models.blocks.basic_components import ( + MarkdownTextObject, + PlainTextObject, + Workflow, + WorkflowTrigger, +) +from slack_sdk.models.blocks.block_elements import WorkflowButtonElement + + +def example01() -> SectionBlock: + """ + Defines an object containing trigger information. + https://docs.slack.dev/reference/block-kit/composition-objects/trigger-object/ + + A workflow button whose trigger carries a URL and customizable inputs. + """ + block = SectionBlock( + text=MarkdownTextObject( + text="A message *with some bold text* and _some italicized text_." + ), + accessory=WorkflowButtonElement( + text=PlainTextObject(text="Run Workflow"), + action_id="workflowbutton123", + workflow=Workflow( + trigger=WorkflowTrigger( + url="https://slack.com/shortcuts/Ft0123ABC456/xyz...zyx", + customizable_input_parameters=[ + { + "name": "input_parameter_a", + "value": "Value for input param A", + }, + { + "name": "input_parameter_b", + "value": "Value for input param B", + }, + ], + ), + ), + ), + ) + return block diff --git a/block-kit/src/composition_objects/workflow.py b/block-kit/src/composition_objects/workflow.py new file mode 100644 index 0000000..5fc4048 --- /dev/null +++ b/block-kit/src/composition_objects/workflow.py @@ -0,0 +1,42 @@ +from slack_sdk.models.blocks import SectionBlock +from slack_sdk.models.blocks.basic_components import ( + MarkdownTextObject, + PlainTextObject, + Workflow, + WorkflowTrigger, +) +from slack_sdk.models.blocks.block_elements import WorkflowButtonElement + + +def example01() -> SectionBlock: + """ + Defines an object containing workflow information. + https://docs.slack.dev/reference/block-kit/composition-objects/workflow-object/ + + A workflow button whose workflow references a configured trigger. + """ + block = SectionBlock( + text=MarkdownTextObject( + text="A message *with some bold text* and _some italicized text_." + ), + accessory=WorkflowButtonElement( + text=PlainTextObject(text="Run Workflow"), + action_id="workflowbutton123", + workflow=Workflow( + trigger=WorkflowTrigger( + url="https://slack.com/shortcuts/Ft0123ABC456/xyz...zyx", + customizable_input_parameters=[ + { + "name": "input_parameter_a", + "value": "Value for input param A", + }, + { + "name": "input_parameter_b", + "value": "Value for input param B", + }, + ], + ), + ), + ), + ) + return block diff --git a/block-kit/tests/blocks/test_plan.py b/block-kit/tests/blocks/test_plan.py index e806350..814e590 100644 --- a/block-kit/tests/blocks/test_plan.py +++ b/block-kit/tests/blocks/test_plan.py @@ -25,9 +25,9 @@ def test_example01(): { "type": "text", "text": "Searched database...", - } + }, ], - } + }, ], }, "output": { @@ -40,9 +40,9 @@ def test_example01(): { "type": "text", "text": "Profile data loaded", - } + }, ], - } + }, ], }, }, @@ -67,9 +67,9 @@ def test_example01(): { "type": "text", "text": "15 data points compiled", - } + }, ], - } + }, ], }, }, diff --git a/block-kit/tests/blocks/test_rich_text.py b/block-kit/tests/blocks/test_rich_text.py index fb6ef56..7c4eb20 100644 --- a/block-kit/tests/blocks/test_rich_text.py +++ b/block-kit/tests/blocks/test_rich_text.py @@ -16,9 +16,9 @@ def test_example01(): { "type": "text", "text": "Hello there, I am a basic rich text block!", - } + }, ], - } + }, ], }, { @@ -39,7 +39,7 @@ def test_example01(): }, }, ], - } + }, ], }, { @@ -60,7 +60,7 @@ def test_example01(): }, }, ], - } + }, ], }, { @@ -81,7 +81,7 @@ def test_example01(): }, }, ], - } + }, ], }, ] @@ -101,7 +101,7 @@ def test_example02(): { "type": "text", "text": "My favorite Slack features (in no particular order):", - } + }, ], }, { @@ -221,7 +221,7 @@ def test_example03(): "text": "Pancakes, extra syrup", }, ], - } + }, ], }, ], @@ -241,10 +241,10 @@ def test_example04(): { "type": "text", "text": '{\n "object": {\n "description": "this is an example of a json object"\n }\n}', - } + }, ], "border": 0, - } + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -263,7 +263,7 @@ def test_example05(): { "type": "text", "text": "What we need is good examples in our documentation.", - } + }, ], }, { @@ -288,8 +288,13 @@ def test_example06(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "broadcast", "range": "everyone"}], - } + "elements": [ + { + "type": "broadcast", + "range": "everyone", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -303,8 +308,13 @@ def test_example07(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "color", "value": "#F405B3"}], - } + "elements": [ + { + "type": "color", + "value": "#F405B3", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -318,8 +328,13 @@ def test_example08(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "channel", "channel_id": "C123ABC456"}], - } + "elements": [ + { + "type": "channel", + "channel_id": "C123ABC456", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -339,9 +354,9 @@ def test_example09(): "timestamp": 1720710212, "format": "{date_num} at {time}", "fallback": "timey", - } + }, ], - } + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -377,7 +392,7 @@ def test_example10(): "name": "checkered_flag", }, ], - } + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -391,8 +406,13 @@ def test_example11(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "link", "url": "https://api.slack.com"}], - } + "elements": [ + { + "type": "link", + "url": "https://api.slack.com", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -406,8 +426,13 @@ def test_example12(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "user", "user_id": "U123ABC456"}], - } + "elements": [ + { + "type": "user", + "user_id": "U123ABC456", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) @@ -421,8 +446,13 @@ def test_example13(): "elements": [ { "type": "rich_text_section", - "elements": [{"type": "usergroup", "usergroup_id": "G123ABC456"}], - } + "elements": [ + { + "type": "usergroup", + "usergroup_id": "G123ABC456", + }, + ], + }, ], } assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/blocks/test_table.py b/block-kit/tests/blocks/test_table.py index f8eb942..d527739 100644 --- a/block-kit/tests/blocks/test_table.py +++ b/block-kit/tests/blocks/test_table.py @@ -9,16 +9,29 @@ def test_example01(): expected = { "type": "table", "column_settings": [ - {"is_wrapped": True}, - {"align": "right"}, + { + "is_wrapped": True, + }, + { + "align": "right", + }, ], "rows": [ [ - {"type": "raw_text", "text": "Header A"}, - {"type": "raw_text", "text": "Header B"}, + { + "type": "raw_text", + "text": "Header A", + }, + { + "type": "raw_text", + "text": "Header B", + }, ], [ - {"type": "raw_text", "text": "Data 1A"}, + { + "type": "raw_text", + "text": "Data 1A", + }, { "type": "rich_text", "elements": [ @@ -29,14 +42,17 @@ def test_example01(): "type": "link", "text": "Data 1B", "url": "https://slack.com", - } + }, ], - } + }, ], }, ], [ - {"type": "raw_text", "text": "Data 2A"}, + { + "type": "raw_text", + "text": "Data 2A", + }, { "type": "rich_text", "elements": [ @@ -47,9 +63,9 @@ def test_example01(): "type": "link", "text": "Data 2B", "url": "https://slack.com", - } + }, ], - } + }, ], }, ], diff --git a/block-kit/tests/blocks/test_task_card.py b/block-kit/tests/blocks/test_task_card.py index 802b924..b0a79bd 100644 --- a/block-kit/tests/blocks/test_task_card.py +++ b/block-kit/tests/blocks/test_task_card.py @@ -20,9 +20,9 @@ def test_example01(): { "type": "text", "text": "Found weather data for Chicago from 2 sources", - } + }, ], - } + }, ], }, "sources": [ diff --git a/block-kit/tests/composition_objects/__init__.py b/block-kit/tests/composition_objects/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/block-kit/tests/composition_objects/test_confirmation_dialog.py b/block-kit/tests/composition_objects/test_confirmation_dialog.py new file mode 100644 index 0000000..610f959 --- /dev/null +++ b/block-kit/tests/composition_objects/test_confirmation_dialog.py @@ -0,0 +1,52 @@ +import json + +from src.composition_objects import confirmation_dialog + + +def test_example01(): + block = confirmation_dialog.example01() + actual = block.to_dict() + expected = { + "type": "actions", + "elements": [ + { + "type": "button", + "text": { + "type": "plain_text", + "emoji": True, + "text": "Approve", + }, + "confirm": { + "title": { + "type": "plain_text", + "text": "Are you sure?", + }, + "text": { + "type": "mrkdwn", + "text": "Would you not prefer a good game of _chess_?", + }, + "confirm": { + "type": "plain_text", + "text": "Do it", + }, + "deny": { + "type": "plain_text", + "text": "Stop, I changed my mind!", + }, + }, + "style": "primary", + "value": "click_me_123", + }, + { + "type": "button", + "text": { + "type": "plain_text", + "emoji": True, + "text": "Deny", + }, + "style": "danger", + "value": "click_me_123", + }, + ], + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_conversation_filter.py b/block-kit/tests/composition_objects/test_conversation_filter.py new file mode 100644 index 0000000..c156ce8 --- /dev/null +++ b/block-kit/tests/composition_objects/test_conversation_filter.py @@ -0,0 +1,49 @@ +import json + +from src.composition_objects import conversation_filter + + +def test_example01(): + view = conversation_filter.example01() + actual = view.to_dict() + expected = { + "title": { + "type": "plain_text", + "text": "My App", + "emoji": True, + }, + "submit": { + "type": "plain_text", + "text": "Submit", + "emoji": True, + }, + "type": "modal", + "close": { + "type": "plain_text", + "text": "Cancel", + "emoji": True, + }, + "blocks": [ + { + "type": "input", + "element": { + "type": "conversations_select", + "placeholder": { + "type": "plain_text", + "text": "Select a conversation", + "emoji": True, + }, + "filter": { + "include": ["public", "mpim"], + "exclude_bot_users": True, + }, + }, + "label": { + "type": "plain_text", + "text": "Choose the conversation to publish your result to:", + "emoji": True, + }, + }, + ], + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_dispatch_action_configuration.py b/block-kit/tests/composition_objects/test_dispatch_action_configuration.py new file mode 100644 index 0000000..1a3a0fb --- /dev/null +++ b/block-kit/tests/composition_objects/test_dispatch_action_configuration.py @@ -0,0 +1,25 @@ +import json + +from src.composition_objects import dispatch_action_configuration + + +def test_example01(): + block = dispatch_action_configuration.example01() + actual = block.to_dict() + expected = { + "type": "input", + "dispatch_action": True, + "element": { + "type": "plain_text_input", + "multiline": True, + "dispatch_action_config": { + "trigger_actions_on": ["on_character_entered"], + }, + }, + "label": { + "type": "plain_text", + "text": "This is a multiline plain-text input", + "emoji": True, + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_option.py b/block-kit/tests/composition_objects/test_option.py new file mode 100644 index 0000000..b314112 --- /dev/null +++ b/block-kit/tests/composition_objects/test_option.py @@ -0,0 +1,76 @@ +import json + +from src.composition_objects import option + + +def test_example01(): + obj = option.example01() + actual = obj.to_dict() + expected = { + "text": { + "type": "plain_text", + "emoji": True, + "text": "Save it", + }, + "value": "value-2", + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) + + +def test_example02(): + blocks = option.example02() + actual = [block.to_dict() for block in blocks] + expected = [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": ":mag: Search results for *Cata*", + }, + }, + { + "type": "divider", + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "**\nUse Case Catalogue for the following departments/roles...", + }, + "accessory": { + "type": "static_select", + "placeholder": { + "type": "plain_text", + "emoji": True, + "text": "Manage", + }, + "options": [ + { + "text": { + "type": "plain_text", + "emoji": True, + "text": "Edit it", + }, + "value": "value-0", + }, + { + "text": { + "type": "plain_text", + "emoji": True, + "text": "Read it", + }, + "value": "value-1", + }, + { + "text": { + "type": "plain_text", + "emoji": True, + "text": "Save it", + }, + "value": "value-2", + }, + ], + }, + }, + ] + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_option_group.py b/block-kit/tests/composition_objects/test_option_group.py new file mode 100644 index 0000000..abb141d --- /dev/null +++ b/block-kit/tests/composition_objects/test_option_group.py @@ -0,0 +1,82 @@ +import json + +from src.composition_objects import option_group + + +def test_example01(): + blocks = option_group.example01() + actual = [block.to_dict() for block in blocks] + expected = [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": ":mag: Search results for *Cata*", + }, + }, + { + "type": "divider", + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "**\nUse Case Catalogue for the following departments/roles...", + }, + "accessory": { + "type": "static_select", + "placeholder": { + "type": "plain_text", + "emoji": True, + "text": "Manage", + }, + "option_groups": [ + { + "label": { + "type": "plain_text", + "text": "Group 1", + }, + "options": [ + { + "text": { + "type": "plain_text", + "text": "*this is plain_text text*", + }, + "value": "value-0", + }, + { + "text": { + "type": "plain_text", + "text": "*this is plain_text text*", + }, + "value": "value-1", + }, + { + "text": { + "type": "plain_text", + "text": "*this is plain_text text*", + }, + "value": "value-2", + }, + ], + }, + { + "label": { + "type": "plain_text", + "text": "Group 2", + }, + "options": [ + { + "text": { + "type": "plain_text", + "text": "*this is plain_text text*", + }, + "value": "value-3", + }, + ], + }, + ], + }, + }, + ] + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_slack_file.py b/block-kit/tests/composition_objects/test_slack_file.py new file mode 100644 index 0000000..e9c22f3 --- /dev/null +++ b/block-kit/tests/composition_objects/test_slack_file.py @@ -0,0 +1,39 @@ +import json + +from src.composition_objects import slack_file + + +def test_example01(): + block = slack_file.example01() + actual = block.to_dict() + expected = { + "type": "image", + "title": { + "type": "plain_text", + "text": "Please enjoy this photo of a kitten", + }, + "block_id": "image4", + "slack_file": { + "url": "https://files.slack.com/files-pri/T0123456-F0123456/xyz.png", + }, + "alt_text": "An incredibly cute kitten.", + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) + + +def test_example02(): + block = slack_file.example02() + actual = block.to_dict() + expected = { + "type": "image", + "title": { + "type": "plain_text", + "text": "Please enjoy this photo of a kitten", + }, + "block_id": "image4", + "slack_file": { + "id": "F0123456", + }, + "alt_text": "An incredibly cute kitten.", + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_text.py b/block-kit/tests/composition_objects/test_text.py new file mode 100644 index 0000000..0db4964 --- /dev/null +++ b/block-kit/tests/composition_objects/test_text.py @@ -0,0 +1,16 @@ +import json + +from src.composition_objects import text + + +def test_example01(): + block = text.example01() + actual = block.to_dict() + expected = { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "A message *with some bold text* and _some italicized text_.", + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_trigger.py b/block-kit/tests/composition_objects/test_trigger.py new file mode 100644 index 0000000..b297691 --- /dev/null +++ b/block-kit/tests/composition_objects/test_trigger.py @@ -0,0 +1,39 @@ +import json + +from src.composition_objects import trigger + + +def test_example01(): + block = trigger.example01() + actual = block.to_dict() + expected = { + "type": "section", + "text": { + "text": "A message *with some bold text* and _some italicized text_.", + "type": "mrkdwn", + }, + "accessory": { + "type": "workflow_button", + "text": { + "type": "plain_text", + "text": "Run Workflow", + }, + "action_id": "workflowbutton123", + "workflow": { + "trigger": { + "url": "https://slack.com/shortcuts/Ft0123ABC456/xyz...zyx", + "customizable_input_parameters": [ + { + "name": "input_parameter_a", + "value": "Value for input param A", + }, + { + "name": "input_parameter_b", + "value": "Value for input param B", + }, + ], + }, + }, + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True) diff --git a/block-kit/tests/composition_objects/test_workflow.py b/block-kit/tests/composition_objects/test_workflow.py new file mode 100644 index 0000000..a1ad500 --- /dev/null +++ b/block-kit/tests/composition_objects/test_workflow.py @@ -0,0 +1,39 @@ +import json + +from src.composition_objects import workflow + + +def test_example01(): + block = workflow.example01() + actual = block.to_dict() + expected = { + "type": "section", + "text": { + "text": "A message *with some bold text* and _some italicized text_.", + "type": "mrkdwn", + }, + "accessory": { + "type": "workflow_button", + "text": { + "type": "plain_text", + "text": "Run Workflow", + }, + "action_id": "workflowbutton123", + "workflow": { + "trigger": { + "url": "https://slack.com/shortcuts/Ft0123ABC456/xyz...zyx", + "customizable_input_parameters": [ + { + "name": "input_parameter_a", + "value": "Value for input param A", + }, + { + "name": "input_parameter_b", + "value": "Value for input param B", + }, + ], + }, + }, + }, + } + assert json.dumps(actual, sort_keys=True) == json.dumps(expected, sort_keys=True)