Repository: line/line-bot-sdk-python
Pull request #205 (2019-08-28 15:41:22)

Flex Message Update 1
#204 

- add new fields for Flex message
- add tests
- add an example using a new spec of Flex message


Patch:
diff --git a/examples/flask-kitchensink/app.py b/examples/flask-kitchensink/app.py
index 8fb48ef..b47d77a 100644
--- a/examples/flask-kitchensink/app.py
+++ b/examples/flask-kitchensink/app.py
@@ -16,6 +16,7 @@ from __future__ import unicode_literals
 
 import datetime
 import errno
+import json
 import os
 import sys
 import tempfile
@@ -332,6 +333,137 @@ def handle_text_message(event):
             event.reply_token,
             message
         )
+    elif text == 'flex_update_1':
+        bubble_string = """
+        {
+          "type": "bubble",
+          "body": {
+            "type": "box",
+            "layout": "vertical",
+            "contents": [
+              {
+                "type": "image",
+                "url": "https://line-objects-dev.com/flex/bg/eiji-k-1360395-unsplash.jpg",
+                "position": "relative",
+                "size": "full",
+                "aspectMode": "cover",
+                "aspectRatio": "1:1",
+                "gravity": "center"
+              },
+              {
+                "type": "box",
+                "layout": "horizontal",
+                "contents": [
+                  {
+                    "type": "box",
+                    "layout": "vertical",
+                    "contents": [
+                      {
+                        "type": "text",
+                        "text": "Brown Hotel",
+                        "weight": "bold",
+                        "size": "xl",
+                        "color": "#ffffff"
+                      },
+                      {
+                        "type": "box",
+                        "layout": "baseline",
+                        "margin": "md",
+                        "contents": [
+                          {
+                            "type": "icon",
+                            "size": "sm",
+                            "url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"
+                          },
+                          {
+                            "type": "icon",
+                            "size": "sm",
+                            "url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"
+                          },
+                          {
+                            "type": "icon",
+                            "size": "sm",
+                            "url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"
+                          },
+                          {
+                            "type": "icon",
+                            "size": "sm",
+                            "url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png"
+                          },
+                          {
+                            "type": "icon",
+                            "size": "sm",
+                            "url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gray_star_28.png"
+                          },
+                          {
+                            "type": "text",
+                            "text": "4.0",
+                            "size": "sm",
+                            "color": "#d6d6d6",
+                            "margin": "md",
+                            "flex": 0
+                          }
+                        ]
+                      }
+                    ]
+                  },
+                  {
+                    "type": "box",
+                    "layout": "vertical",
+                    "contents": [
+                      {
+                        "type": "text",
+                        "text": "¥62,000",
+                        "color": "#a9a9a9",
+                        "decoration": "line-through",
+                        "align": "end"
+                      },
+                      {
+                        "type": "text",
+                        "text": "¥42,000",
+                        "color": "#ebebeb",
+                        "size": "xl",
+                        "align": "end"
+                      }
+                    ]
+                  }
+                ],
+                "position": "absolute",
+                "offsetBottom": "0px",
+                "offsetStart": "0px",
+                "offsetEnd": "0px",
+                "backgroundColor": "#00000099",
+                "paddingAll": "20px"
+              },
+              {
+                "type": "box",
+                "layout": "vertical",
+                "contents": [
+                  {
+                    "type": "text",
+                    "text": "SALE",
+                    "color": "#ffffff"
+                  }
+                ],
+                "position": "absolute",
+                "backgroundColor": "#ff2600",
+                "cornerRadius": "20px",
+                "paddingAll": "5px",
+                "offsetTop": "10px",
+                "offsetEnd": "10px",
+                "paddingStart": "10px",
+                "paddingEnd": "10px"
+              }
+            ],
+            "paddingAll": "0px"
+          }
+        }
+        """
+        message = FlexSendMessage(alt_text="hello", contents=json.loads(bubble_string))
+        line_bot_api.reply_message(
+            event.reply_token,
+            message
+        )
     elif text == 'quick_reply':
         line_bot_api.reply_message(
             event.reply_token,
diff --git a/linebot/models/__init__.py b/linebot/models/__init__.py
index a83fcf8..e13b920 100644
--- a/linebot/models/__init__.py
+++ b/linebot/models/__init__.py
@@ -69,7 +69,8 @@ from .flex_message import (  # noqa
     ImageComponent,
     SeparatorComponent,
     SpacerComponent,
-    TextComponent
+    TextComponent,
+    SpanComponent
 )
 from .imagemap import (  # noqa
     ImagemapSendMessage,
diff --git a/linebot/models/flex_message.py b/linebot/models/flex_message.py
index 8994bd2..7b9d337 100644
--- a/linebot/models/flex_message.py
+++ b/linebot/models/flex_message.py
@@ -28,7 +28,7 @@ from .send_messages import SendMessage
 class FlexSendMessage(SendMessage):
     """FlexSendMessage.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#flex-message
+    https://developers.line.biz/en/reference/messaging-api/#flex-message
 
     Flex Messages are messages with a customizable layout.
     You can customize the layout freely by combining multiple elements.
@@ -58,7 +58,7 @@ class FlexSendMessage(SendMessage):
 class FlexContainer(with_metaclass(ABCMeta, Base)):
     """FlexContainer.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#container
+    https://developers.line.biz/en/reference/messaging-api/#container
 
     A container is the top-level structure of a Flex Message.
     """
@@ -76,45 +76,51 @@ class FlexContainer(with_metaclass(ABCMeta, Base)):
 class BubbleContainer(FlexContainer):
     """BubbleContainer.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#bubble-container
+    https://developers.line.biz/en/reference/messaging-api/#bubble
 
     This is a container that contains one message bubble.
     It can contain four blocks: header, hero, body, and footer.
     """
 
-    def __init__(self, direction=None, header=None, hero=None, body=None, footer=None, styles=None,
-                 **kwargs):
+    def __init__(self, size=None, direction=None, header=None, hero=None,
+                 body=None, footer=None, styles=None, action=None, **kwargs):
         """__init__ method.
 
+        :param str size: The size of the bubble. `nano`, `micro`, `kilo`, `mega`, or `giga`.
         :param str direction: Text directionality and the order of components
             in horizontal boxes in the container
         :param header: Header block
         :type header: :py:class:`linebot.models.flex_message.BoxComponent`
         :param hero: Hero block
         :type hero: :py:class:`linebot.models.flex_message.ImageComponent`
+            | :py:class:`linebot.models.flex_message.BoxComponent`
         :param body: Body block
         :type body: :py:class:`linebot.models.flex_message.BoxComponent`
         :param footer: Footer block
         :type footer: :py:class:`linebot.models.flex_message.BoxComponent`
         :param styles: Style of each block
         :type styles: :py:class:`linebot.models.flex_message.BubbleStyle`
+        :param action: Action performed when this button is tapped
+        :type action: list[T <= :py:class:`linebot.models.actions.Action`]
         :param kwargs:
         """
         super(BubbleContainer, self).__init__(**kwargs)
 
         self.type = 'bubble'
+        self.size = size
         self.direction = direction
         self.header = self.get_or_new_from_json_dict(header, BoxComponent)
         self.hero = self.get_or_new_from_json_dict(hero, ImageComponent)
         self.body = self.get_or_new_from_json_dict(body, BoxComponent)
         self.footer = self.get_or_new_from_json_dict(footer, BoxComponent)
         self.styles = self.get_or_new_from_json_dict(styles, BubbleStyle)
+        self.action = get_action(action)
 
 
 class BubbleStyle(with_metaclass(ABCMeta, Base)):
     """BubbleStyle.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#objects-for-the-block-style
+    https://developers.line.biz/en/reference/messaging-api/#bubble-style
     """
 
     def __init__(self, header=None, hero=None, body=None, footer=None, **kwargs):
@@ -141,7 +147,7 @@ class BubbleStyle(with_metaclass(ABCMeta, Base)):
 class BlockStyle(with_metaclass(ABCMeta, Base)):
     """BlockStyle.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#objects-for-the-block-style
+    https://developers.line.biz/en/reference/messaging-api/#block-style
     """
 
     def __init__(self, background_color=None, separator=None, separator_color=None, **kwargs):
@@ -164,7 +170,7 @@ class BlockStyle(with_metaclass(ABCMeta, Base)):
 class CarouselContainer(FlexContainer):
     """CarouselContainer.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#carousel-container
+    https://developers.line.biz/en/reference/messaging-api/#f-carousel
 
     This is a container that contains multiple bubble containers, or message bubbles.
     The bubbles will be shown in order by scrolling horizontally.
@@ -193,7 +199,7 @@ class CarouselContainer(FlexContainer):
 class FlexComponent(with_metaclass(ABCMeta, Base)):
     """FlexComponent.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#component
+    https://developers.line.biz/en/reference/messaging-api/#component
 
     Components are objects that compose a Flex Message container.
     """
@@ -211,29 +217,92 @@ class FlexComponent(with_metaclass(ABCMeta, Base)):
 class BoxComponent(FlexComponent):
     """BoxComponent.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#box-component
+    https://developers.line.biz/en/reference/messaging-api/#box
 
     This is a component that defines the layout of child components.
     You can also include a box in a box.
     """
 
-    def __init__(self, layout=None, contents=None, flex=None, spacing=None, margin=None, **kwargs):
+    def __init__(self,
+                 layout=None,
+                 contents=None,
+                 background_color=None,
+                 border_color=None,
+                 border_width=None,
+                 corner_radius=None,
+                 width=None,
+                 height=None,
+                 flex=None,
+                 spacing=None,
+                 margin=None,
+                 padding_all=None,
+                 padding_top=None,
+                 padding_bottom=None,
+                 padding_start=None,
+                 padding_end=None,
+                 position=None,
+                 offset_top=None,
+                 offset_bottom=None,
+                 offset_start=None,
+                 offset_end=None,
+                 action=None,
+                 **kwargs):
         """__init__ method.
 
         :param str layout: The placement style of components in this box
         :param contents: Components in this box
+        :type contents: list[T <= :py:class:`linebot.models.flex_message.FlexComponent`]
+        :param str background_color: Background color of the block
+        :param str border_color: Color of box border
+        :param str border_width: Width of box border
+        :param str corner_radius: Radius at the time of rounding the corners of the border
+        :param str width: Width of the box
+        :param str height: Height of the box
         :param float flex: The ratio of the width or height of this box within the parent box
+            and the previous component in the parent box
         :param str spacing: Minimum space between components in this box
         :param str margin: Minimum space between this box
-            and the previous component in the parent box
+        :param str padding_all: Free space between the borders of this box and the child element
+        :param str padding_top: Free space between the border at the upper end of this box
+            and the upper end of the child element
+        :param str padding_bottom: Free space between the border at the lower end of this box
+            and the lower end of the child element
+        :param str padding_start: Free space between the border at the left end of this box
+            and the left end of the child element
+        :param str padding_end: Free space between the border at the right end of this box
+            and the right end of the child element
+        :param str position: Reference position for placing this box
+        :param str offset_top: The top offset
+        :param str offset_bottom: The bottom offset
+        :param str offset_start: The left offset
+        :param str offset_end: The right offset
+        :param action: Action performed when this button is tapped
+        :type action: list[T <= :py:class:`linebot.models.actions.Action`]
         :param kwargs:
         """
         super(BoxComponent, self).__init__(**kwargs)
         self.type = 'box'
         self.layout = layout
+        self.background_color = background_color
+        self.border_color = border_color
+        self.border_width = border_width
+        self.corner_radius = corner_radius
+        self.width = width
+        self.height = height
         self.flex = flex
         self.spacing = spacing
         self.margin = margin
+        self.padding_all = padding_all
+        self.padding_top = padding_top
+        self.padding_bottom = padding_bottom
+        self.padding_start = padding_start
+        self.padding_end = padding_end
+        self.position = position
+        self.offset_top = offset_top
+        self.offset_bottom = offset_bottom
+        self.offset_start = offset_start
+        self.offset_end = offset_end
+        self.action = get_action(action)
 
         new_contents = []
         if contents:
@@ -245,6 +314,7 @@ class BoxComponent(FlexComponent):
                         'filler': FillerComponent,
                         'icon': IconComponent,
                         'image': ImageComponent,
+                        'span': SpanComponent,
                         'separator': SeparatorComponent,
                         'spacer': SpacerComponent,
                         'text': TextComponent
@@ -256,14 +326,26 @@ class BoxComponent(FlexComponent):
 class ButtonComponent(FlexComponent):
     """ButtonComponent.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#button-component
+    https://developers.line.biz/en/reference/messaging-api/#button
 
     This component draws a button.
     When the user taps a button, a specified action is performed.
     """
 
-    def __init__(self, action=None, flex=None, margin=None, height=None, style=None, color=None,
-                 gravity=None, **kwargs):
+    def __init__(self,
+                 action=None,
+                 flex=None,
+                 margin=None,
+                 position=None,
+                 offset_top=None,
+                 offset_bottom=None,
+                 offset_start=None,
+                 offset_end=None,
+                 height=None,
+                 style=None,
+                 color=None,
+                 gravity=None,
+                 **kwargs):
         """__init__ method.
 
         :param action: Action performed when this button is tapped
@@ -271,6 +353,11 @@ class ButtonComponent(FlexComponent):
         :param float flex: The ratio of the width or height of this component within the parent box
         :param str margin: Minimum space between this component
             and the previous component in the parent box
+        :param str position: Reference position for placing this box
+        :param str offset_top: The top offset
+        :param str offset_bottom: The bottom offset
+        :param str offset_start: The left offset
+        :param str offset_end: The right offset
         :param str height: Height of the button
         :param str style: Style of the button
         :param str color: Character color when the style property is link.
@@ -284,6 +371,11 @@ class ButtonComponent(FlexComponent):
         self.action = get_action(action)
         self.flex = flex
         self.margin = margin
+        self.position = position
+        self.offset_top = offset_top
+        self.offset_bottom = offset_bottom
+        self.offset_start = offset_start
+        self.offset_end = offset_end
         self.height = height
         self.style = style
         self.color = color
@@ -293,29 +385,40 @@ class ButtonComponent(FlexComponent):
 class FillerComponent(FlexComponent):
     """FillerComponent.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#filler-component
+    https://developers.line.biz/en/reference/messaging-api/#filler
 
     This is an invisible component to fill extra space between components.
     """
 
-    def __init__(self, **kwargs):
+    def __init__(self, flex=None, **kwargs):
         """__init__ method.
 
         :param kwargs:
         """
         super(FillerComponent, self).__init__(**kwargs)
         self.type = 'filler'
+        self.flex = flex
 
 
 class IconComponent(FlexComponent):
     """IconComponent.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#icon-component
+    https://developers.line.biz/en/reference/messaging-api/#icon
 
     This component draws an icon.
     """
 
-    def __init__(self, url=None, margin=None, size=None, aspect_ratio=None, **kwargs):
+    def __init__(self,
+                 url=None,
+                 margin=None,
+                 position=None,
+                 offset_top=None,
+                 offset_bottom=None,
+                 offset_start=None,
+                 offset_end=None,
+                 size=None,
+                 aspect_ratio=None,
+                 **kwargs):
         """__init__ method.
 
         :param str url: Image URL
@@ -323,6 +426,11 @@ class IconComponent(FlexComponent):
             Image format: JPEG or PNG
         :param str margin: Minimum space between this component
             and the previous component in the parent box
+        :param str position: Reference position for placing this box
+        :param str offset_top: The top offset
+        :param str offset_bottom: The bottom offset
+        :param str offset_start: The left offset
+        :param str offset_end: The right offset
         :param str size: Maximum size of the icon width
         :param str aspect_ratio: Aspect ratio of the icon
         :param kwargs:
@@ -331,6 +439,11 @@ class IconComponent(FlexComponent):
         self.type = 'icon'
         self.url = url
         self.margin = margin
+        self.position = position
+        self.offset_top = offset_top
+        self.offset_bottom = offset_bottom
+        self.offset_start = offset_start
+        self.offset_end = offset_end
         self.size = size
         self.aspect_ratio = aspect_ratio
 
@@ -338,13 +451,27 @@ class IconComponent(FlexComponent):
 class ImageComponent(FlexComponent):
     """ImageComponent.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#image-component
+    https://developers.line.biz/en/reference/messaging-api/#f-image
 
     This component draws an image.
     """
 
-    def __init__(self, url=None, flex=None, margin=None, align=None, gravity=None, size=None,
-                 aspect_ratio=None, aspect_mode=None, background_color=None, action=None,
+    def __init__(self,
+                 url=None,
+                 flex=None,
+                 margin=None,
+                 position=None,
+                 offset_top=None,
+                 offset_bottom=None,
+                 offset_start=None,
+                 offset_end=None,
+                 align=None,
+                 gravity=None,
+                 size=None,
+                 aspect_ratio=None,
+                 aspect_mode=None,
+                 background_color=None,
+                 action=None,
                  **kwargs):
         """__init__ method.
 
@@ -354,6 +481,11 @@ class ImageComponent(FlexComponent):
         :param float flex: The ratio of the width or height of this component within the parent box
         :param str margin: Minimum space between this component
             and the previous component in the parent box
+        :param str position: Reference position for placing this box
+        :param str offset_top: The top offset
+        :param str offset_bottom: The bottom offset
+        :param str offset_start: The left offset
+        :param str offset_end: The right offset
         :param str align: Horizontal alignment style
         :param str gravity: Vertical alignment style
         :param str size: Maximum size of the image width
@@ -369,6 +501,11 @@ class ImageComponent(FlexComponent):
         self.url = url
         self.flex = flex
         self.margin = margin
+        self.position = position
+        self.offset_top = offset_top
+        self.offset_bottom = offset_bottom
+        self.offset_start = offset_start
+        self.offset_end = offset_end
         self.align = align
         self.gravity = gravity
         self.size = size
@@ -381,7 +518,7 @@ class ImageComponent(FlexComponent):
 class SeparatorComponent(FlexComponent):
     """SeparatorComponent.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#separator-component
+    https://developers.line.biz/en/reference/messaging-api/#separator
 
     This component draws a separator between components in the parent box.
     """
@@ -403,7 +540,7 @@ class SeparatorComponent(FlexComponent):
 class SpacerComponent(FlexComponent):
     """SpacerComponent.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#spacer-component
+    https://developers.line.biz/en/reference/messaging-api/#spacer
 
     This is an invisible component that places a fixed-size space
     at the beginning or end of the box
@@ -420,33 +557,96 @@ class SpacerComponent(FlexComponent):
         self.size = size
 
 
+class SpanComponent(FlexComponent):
+    """SpanComponent.
+
+    https://developers.line.biz/en/reference/messaging-api/#span
+
+    This component renders multiple text strings with different designs in one row.
+    """
+
+    def __init__(self,
+                 text=None,
+                 color=None,
+                 size=None,
+                 weight=None,
+                 style=None,
+                 decoration=None,
+                 **kwargs):
+        r"""__init__ method.
+
+        :param str text: Text
+        :param str color: Font color
+        :param str size: Font size
+        :param str weight: Font weight
+        :param str style: Style of the text
+        :param str decoration: Decoration of the text
+        :param kwargs:
+        """
+        super(SpanComponent, self).__init__(**kwargs)
+        self.type = 'span'
+        self.text = text
+        self.size = size
+        self.weight = weight
+        self.color = color
+        self.style = style
+        self.decoration = decoration
+
+
 class TextComponent(FlexComponent):
     """TextComponent.
 
-    https://developers.line.me/en/docs/messaging-api/reference/#text-component
+    https://developers.line.biz/en/reference/messaging-api/#f-text
 
     This component draws text. You can format the text.
     """
 
-    def __init__(self, text=None, flex=None, margin=None, size=None, align=None, gravity=None,
-                 wrap=None, maxLines=None, weight=None,
-                 color=None, action=None, **kwargs):
+    def __init__(self,
+                 text=None,
+                 contents=None,
+                 flex=None,
+                 margin=None,
+                 position=None,
+                 offset_top=None,
+                 offset_bottom=None,
+                 offset_start=None,
+                 offset_end=None,
+                 size=None,
+                 align=None,
+                 gravity=None,
+                 wrap=None,
+                 max_lines=None,
+                 weight=None,
+                 color=None,
+                 action=None,
+                 style=None,
+                 decoration=None,
+                 **kwargs):
         r"""__init__ method.
 
         :param str text: Text
+        :param contents: Array of spans
+        :type contents: list[T <= :py:class:`linebot.models.flex_message.SpanComponent`]
         :param float flex: The ratio of the width or height of this component within the parent box
         :param str margin: Minimum space between this component
             and the previous component in the parent box
+        :param str position: Reference position for placing this box
+        :param str offset_top: The top offset
+        :param str offset_bottom: The bottom offset
+        :param str offset_start: The left offset
+        :param str offset_end: The right offset
         :param str size: Font size
         :param str align: Horizontal alignment style
         :param str gravity: Vertical alignment style
         :param bool wrap: rue to wrap text. The default value is False.
             If set to True, you can use a new line character (\n) to begin on a new line.
-        :param int maxLines: Max number of lines
+        :param int max_lines: Max number of lines
         :param str weight: Font weight
         :param str color: Font color
         :param action: Action performed when this image is tapped
         :type action: list[T <= :py:class:`linebot.models.actions.Action`]
+        :param str style: Style of the text
+        :param str decoration: Decoration of the text
         :param kwargs:
         """
         super(TextComponent, self).__init__(**kwargs)
@@ -454,11 +654,23 @@ class TextComponent(FlexComponent):
         self.text = text
         self.flex = flex
         self.margin = margin
+        self.position = position
+        self.offset_top = offset_top
+        self.offset_bottom = offset_bottom
+        self.offset_start = offset_start
+        self.offset_end = offset_end
         self.size = size
         self.align = align
         self.gravity = gravity
         self.wrap = wrap
-        self.maxLines = maxLines
+        self.max_lines = max_lines
         self.weight = weight
         self.color = color
         self.action = get_action(action)
+        self.style = style
+        self.decoration = decoration
+
+        if contents:
+            self.contents = [self.get_or_new_from_json_dict(it, SpanComponent) for it in contents]
+        else:
+            self.contents = None
diff --git a/tox.ini b/tox.ini
index ff2a9d5..a246c3b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -27,4 +27,4 @@ basepython = python3.7
 deps =
     six
     flake8
-commands = flake8 tests/ examples/
+commands = flake8 tests/ examples/ --max-line-length=120


Test patch:
diff --git a/tests/models/serialize_test_case.py b/tests/models/serialize_test_case.py
index a9dee1e..d9fdeea 100644
--- a/tests/models/serialize_test_case.py
+++ b/tests/models/serialize_test_case.py
@@ -37,6 +37,7 @@ class SerializeTestCase(unittest.TestCase):
     LOCATION = 'location'
     FLEX = 'flex'
     SPACER = 'spacer'
+    SPAN = 'span'
     BUBBLE = 'bubble'
     CAROUSEL = 'carousel'
     BOX = 'box'
diff --git a/tests/models/test_flex_message.py b/tests/models/test_flex_message.py
index eaa7d0b..ad752fc 100644
--- a/tests/models/test_flex_message.py
+++ b/tests/models/test_flex_message.py
@@ -30,6 +30,7 @@ from linebot.models import (
     FillerComponent,
     IconComponent,
     SpacerComponent,
+    SpanComponent,
     URIAction,
 )
 from tests.models.serialize_test_case import SerializeTestCase
@@ -44,7 +45,7 @@ class TestFlexMessage(SerializeTestCase):
                     body=BoxComponent(
                         layout='vertical',
                         contents=[
-                            TextComponent(text='hello', wrap=True, maxLines=1),
+                            TextComponent(text='hello', wrap=True, max_lines=1),
                             TextComponent(text='world')
                         ]
                     )
@@ -140,7 +141,11 @@ class TestFlexMessage(SerializeTestCase):
                 ImageComponent(url='https://example.com/flex/images/image.jpg'),
                 SeparatorComponent(),
                 TextComponent(text='Text in the box'),
-            ]
+            ],
+            'background_color': '#00000000',
+            'border_width': 'light',
+            'corner_radius': 'xs',
+            'flex': 2
         }
 
         self.assertEqual(
@@ -162,7 +167,9 @@ class TestFlexMessage(SerializeTestCase):
         )
 
     def test_filler_component(self):
-        arg = {}
+        arg = {
+            'flex': 2
+        }
         self.assertEqual(
             self.serialize_as_dict(arg, type=self.FILLER),
             FillerComponent(**arg).as_json_dict()
@@ -192,7 +199,8 @@ class TestFlexMessage(SerializeTestCase):
 
     def test_separator_component(self):
         arg = {
-            'color': '#000000'
+            'color': '#000000',
+            'margin': 'xxl'
         }
         self.assertEqual(
             self.serialize_as_dict(arg, type=self.SEPARATOR),
@@ -208,12 +216,31 @@ class TestFlexMessage(SerializeTestCase):
             SpacerComponent(**arg).as_json_dict()
         )
 
+    def test_span_component(self):
+        arg = {
+            'type': 'span',
+            'text': '蛙',
+            'size': 'xxl',
+            'weight': 'bold',
+            'style': 'italic',
+            'color': '#4f8f00',
+            'decoration': 'underline'
+        }
+        self.assertEqual(
+            self.serialize_as_dict(arg, type=self.SPAN),
+            SpanComponent(**arg).as_json_dict()
+        )
+
     def test_text_component(self):
         arg = {
             'text': 'Hello, World!',
             'size': 'xl',
             'weight': 'bold',
-            'color': '#0000ff'
+            'color': '#0000ff',
+            'position': 'relative',
+            'offset_top': '10px',
+            'decoration': 'underline',
+            'max_lines': 2
         }
         self.assertEqual(
             self.serialize_as_dict(arg, type=self.TEXT),