├── .coveragerc ├── .coverage ├── .gitignore ├── tests ├── __init__.py ├── mocks.py ├── test_native_action.py ├── test_base.py ├── test_silent_action.py ├── test_button.py ├── test_silent.py ├── test_carousel_item.py ├── test_form.py ├── test_text.py ├── test_system.py ├── test_carousel.py ├── test_actionable.py └── test_form_field.py ├── hsl_builder ├── elements │ ├── __init__.py │ ├── silent_action.py │ ├── carousel_item.py │ ├── actionable.py │ └── form_field.py ├── __init__.py ├── text.py ├── native_action.py ├── silent.py ├── button.py ├── base.py ├── system.py ├── form.py └── carousel.py ├── setup.py └── README.md /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = hsl_builder -------------------------------------------------------------------------------- /.coverage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellohaptik/python-hsl/develop/.coverage -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.pyc 3 | *.egg-info/ 4 | dist/ 5 | build/ 6 | htmlcov/ 7 | *.coverage -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | from .test_actionable import * 2 | from .test_base import * 3 | from .test_button import * 4 | from .test_carousel import * 5 | from .test_carousel_item import * 6 | from .test_form import * 7 | from .test_form_field import * 8 | from .test_native_action import * 9 | from .test_silent import * 10 | from .test_silent_action import * 11 | from .test_system import * 12 | from .test_text import * 13 | -------------------------------------------------------------------------------- /hsl_builder/elements/__init__.py: -------------------------------------------------------------------------------- 1 | from .form_field import FormField, FormFieldType, FormKeyboardType 2 | from .actionable import Actionable, ActionableType, URI 3 | from .carousel_item import CarouselItem 4 | from .silent_action import SilentAction 5 | 6 | __all__=[ 7 | 'FormField', 8 | 'Actionable', 9 | 'SilentAction', 10 | 'CarouselItem', 11 | 'ActionableType', 12 | 'URI', 13 | 'FormFieldType', 14 | 'FormKeyboardType' 15 | ] 16 | -------------------------------------------------------------------------------- /tests/mocks.py: -------------------------------------------------------------------------------- 1 | from hsl_builder.elements import Actionable, FormField, CarouselItem, SilentAction 2 | 3 | class MockActionable(Actionable): 4 | 5 | def __init__(self): 6 | pass 7 | 8 | 9 | class MockFormField(FormField): 10 | 11 | def __init__(self): 12 | pass 13 | 14 | class MockCarouselItem(CarouselItem): 15 | 16 | def __init__(self): 17 | pass 18 | 19 | class MockSilentAction(SilentAction): 20 | 21 | def __init__(self): 22 | pass 23 | 24 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup,find_packages 2 | 3 | 4 | with open("README.md", "r") as fh: 5 | long_description = fh.read() 6 | 7 | setup( 8 | name='hsl_builder', 9 | version='0.0.1-beta', 10 | description='HSL Builder for creating hsl elements', 11 | license='MIT', 12 | long_description=long_description, 13 | long_description_content_type="text/markdown", 14 | packages=find_packages(exclude=('tests',)), 15 | zip_safe=False, 16 | url="https://github.com/hellohaptik/python-hsl") 17 | -------------------------------------------------------------------------------- /hsl_builder/__init__.py: -------------------------------------------------------------------------------- 1 | from .button import Button 2 | from .carousel import Carousel, CarouselWidth 3 | from .form import Form 4 | from .native_action import NativeAction 5 | from .silent import Silent 6 | from .text import Text 7 | from .system import System, SystemEvents 8 | from .base import BaseElement 9 | 10 | 11 | __all__= [ 12 | 'Button', 13 | 'CarouselWidth', 14 | 'Carousel', 15 | 'Form', 16 | 'NativeAction', 17 | 'Silent', 18 | 'Text', 19 | 'System', 20 | 'SystemEvents', 21 | 'BaseElement' 22 | ] 23 | -------------------------------------------------------------------------------- /hsl_builder/text.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from .base import BaseElement 3 | from .elements.actionable import Actionable 4 | 5 | class Text(BaseElement): 6 | """ 7 | Create simple text message HSL 8 | """ 9 | def __init__(self,text): 10 | super().__init__(text,'TEXT') 11 | self.quick_replies: List[Actionable] = [] 12 | def to_hsl(self): 13 | """ 14 | Generate HSL message 15 | """ 16 | hsl = super().to_hsl() 17 | data = { 18 | 'quick_replies': [qr.to_hsl() for qr in self.quick_replies] 19 | } 20 | hsl['data'] = data 21 | 22 | return hsl 23 | -------------------------------------------------------------------------------- /hsl_builder/native_action.py: -------------------------------------------------------------------------------- 1 | from .base import BaseElement 2 | 3 | 4 | class NativeAction(BaseElement): 5 | """ 6 | Create Native Action HSL Message. 7 | Native Actions are used to communicate with the parent app in which SDK is integrated 8 | 9 | Attributes 10 | ---------- 11 | method : str 12 | the method name for the native action 13 | """ 14 | def __init__(self,text: str, method: str): 15 | super().__init__(text,'NATIVE_ACTION') 16 | self.method = method 17 | 18 | def to_hsl(self): 19 | """ 20 | Generate HSL dict 21 | """ 22 | hsl = super().to_hsl() 23 | data = { 24 | 'method': self.method 25 | } 26 | hsl['data'] = data 27 | 28 | return hsl 29 | -------------------------------------------------------------------------------- /hsl_builder/silent.py: -------------------------------------------------------------------------------- 1 | from .base import BaseElement 2 | from typing import List 3 | 4 | from .elements import SilentAction 5 | 6 | class Silent(BaseElement): 7 | """ 8 | Create Silent Message HSL 9 | 10 | Attributes 11 | ---------- 12 | actions : List[SilentAction] 13 | list of silent acitons to be taken 14 | """ 15 | def __init__(self,text: str): 16 | super().__init__(text,'SILENT') 17 | self.actions: List[SilentAction] = [] 18 | 19 | def to_hsl(self): 20 | """ 21 | Generate HSL dict 22 | """ 23 | hsl = super().to_hsl() 24 | data = { 25 | 'silent_actions': [action.to_hsl() for action in self.actions] 26 | } 27 | hsl['data'] = data 28 | 29 | return hsl 30 | -------------------------------------------------------------------------------- /hsl_builder/button.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from .base import BaseElement 3 | from .elements.actionable import Actionable 4 | 5 | class Button(BaseElement): 6 | """ 7 | Create Button HSL Elements 8 | 9 | Attributes 10 | ---------- 11 | actionables : List[Actionable] 12 | list of actionables that will be added to the button 13 | 14 | """ 15 | def __init__(self,text): 16 | super().__init__(text,'BUTTON') 17 | self.actionables: List[Actionable] = [] 18 | 19 | def to_hsl(self): 20 | """ 21 | Generate HSL dict 22 | """ 23 | hsl = super().to_hsl() 24 | data = { 25 | 'items': [actionable.to_hsl() for actionable in self.actionables] 26 | } 27 | hsl['data'] = data 28 | 29 | return hsl 30 | -------------------------------------------------------------------------------- /hsl_builder/base.py: -------------------------------------------------------------------------------- 1 | class BaseElement(object): 2 | """ 3 | Base Class containing common properties for all HSL Messages 4 | 5 | Attributes 6 | ---------- 7 | text : str 8 | text for the message to be displayed to the user 9 | 10 | type : str 11 | type of the HSL Message 12 | 13 | voice_text : str 14 | this text will be spoken out if tts is enabled 15 | """ 16 | 17 | def __init__(self, text: str, hsl_type: str): 18 | self.text: str = text 19 | self.type: str = hsl_type 20 | self.voice_text: str = "" 21 | 22 | def to_hsl(self): 23 | """ 24 | Generate HSL dict 25 | """ 26 | return { 27 | 'text': self.text, 28 | 'type': self.type, 29 | 'voice_text': self.voice_text 30 | } 31 | -------------------------------------------------------------------------------- /hsl_builder/system.py: -------------------------------------------------------------------------------- 1 | from .base import BaseElement 2 | from enum import unique,Enum 3 | 4 | @unique 5 | class SystemEvents(Enum): 6 | PINNED = 'chat_pinned' 7 | COMPLETE = 'chat_complete' 8 | 9 | class System(BaseElement): 10 | """ 11 | create system messages hsl 12 | 13 | Attributes 14 | ---------- 15 | event_name : SystemEvents 16 | the type of the System Event to be sent 17 | 18 | payload : dict 19 | additonal data sent as payload 20 | """ 21 | def __init__(self,text :str,event_name: SystemEvents): 22 | super().__init__(text,'SYSTEM') 23 | self.event = event_name 24 | self.payload = {} 25 | 26 | def to_hsl(self): 27 | hsl = super().to_hsl() 28 | data = { 29 | 'event_name': self.event.value, 30 | 'payload': self.payload 31 | } 32 | hsl['data'] = data 33 | 34 | return hsl 35 | -------------------------------------------------------------------------------- /tests/test_native_action.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase,main 2 | import mock 3 | 4 | from hsl_builder import NativeAction 5 | 6 | class NativeActionTest(TestCase): 7 | 8 | def setUp(self): 9 | self.native = NativeAction("title", "METHOD") 10 | 11 | def test_initialization(self): 12 | """ 13 | verify that native_action is initialized with the correct options 14 | """ 15 | self.assertEqual(self.native.text, "title") 16 | self.assertEqual(self.native.type, "NATIVE_ACTION") 17 | self.assertEqual(self.native.method, "METHOD") 18 | 19 | def test_hsl_default(self): 20 | """ 21 | verify the default hsl generated 22 | """ 23 | self.assertDictEqual(self.native.to_hsl(),{ 24 | 'text': 'title', 25 | 'type': 'NATIVE_ACTION', 26 | 'voice_text': '', 27 | 'data': { 28 | 'method': 'METHOD' 29 | } 30 | }) 31 | 32 | if __name__ == '__main__': 33 | main() 34 | -------------------------------------------------------------------------------- /hsl_builder/elements/silent_action.py: -------------------------------------------------------------------------------- 1 | class SilentAction(object): 2 | """ 3 | Create Silent Actions for Silent Message HSl 4 | 5 | Attributes 6 | ---------- 7 | type : str 8 | Type of silent action. 9 | 10 | via_name : str 11 | via_name of the corresponding business. 12 | 13 | 14 | action_id : str 15 | id of the silent action. 16 | 17 | data : dict 18 | options that will be sent as payload 19 | """ 20 | 21 | def __init__(self, action_type: str, id: int, via_name: str): 22 | self.type: str = action_type 23 | self.via_name: str = via_name 24 | self.action_id: int = id 25 | self.data: dict = {} 26 | 27 | def to_hsl(self) -> dict: 28 | """ 29 | Generate HSL dict 30 | """ 31 | self.data['Id'] = self.action_id 32 | self.data['via_name'] = self.via_name 33 | return { 34 | "type": self.type, 35 | "data": self.data 36 | } 37 | -------------------------------------------------------------------------------- /hsl_builder/form.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from .elements.form_field import FormField 4 | 5 | 6 | class Form(object): 7 | """ 8 | Create HSL Form message. 9 | 10 | Attributes 11 | ---------- 12 | title : str 13 | the title of the form. 14 | 15 | subtitle : str 16 | Sub title for the form for showing more info 17 | 18 | fields : List[FormField] 19 | list of formfields that will be added to the form 20 | 21 | """ 22 | def __init__(self,text: str, subtitle: str): 23 | self.title: str = text 24 | self.type: str = 'FORM' 25 | self.subtitle: str = subtitle 26 | self.fields: List[FormField] = [] 27 | 28 | def to_hsl(self): 29 | """ 30 | Generate HSL dict 31 | """ 32 | hsl = { 33 | 'title': self.title, 34 | 'type': self.type, 35 | 'subtitle': self.subtitle 36 | } 37 | data = { 38 | 'fields': [field.to_hsl() for field in self.fields] 39 | } 40 | hsl['data'] = data 41 | 42 | return hsl 43 | -------------------------------------------------------------------------------- /tests/test_base.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase,main 2 | import mock 3 | 4 | from hsl_builder import BaseElement 5 | 6 | class BaseTest(TestCase): 7 | 8 | def setUp(self): 9 | self.base = BaseElement("title", "type") 10 | 11 | def test_initialization(self): 12 | """ 13 | verify that base is initialized with correct options 14 | """ 15 | self.assertEqual(self.base.text, "title") 16 | self.assertEqual(self.base.type, "type") 17 | 18 | def test_hsl_default(self): 19 | """ 20 | verify the default hsl generated 21 | """ 22 | self.assertDictEqual(self.base.to_hsl(),{ 23 | 'text': 'title', 24 | 'type': 'type', 25 | 'voice_text': '' 26 | }) 27 | 28 | def test_hsl_voice(self): 29 | """ 30 | verify that voice text is updated in the hsl 31 | """ 32 | self.base.voice_text = "voice" 33 | self.assertDictEqual(self.base.to_hsl(),{ 34 | 'text': 'title', 35 | 'type': 'type', 36 | 'voice_text': 'voice' 37 | }) 38 | 39 | if __name__ == '__main__': 40 | main() 41 | -------------------------------------------------------------------------------- /hsl_builder/carousel.py: -------------------------------------------------------------------------------- 1 | from enum import Enum,unique 2 | from typing import List 3 | 4 | from .base import BaseElement 5 | from .elements.carousel_item import CarouselItem 6 | 7 | @unique 8 | class CarouselWidth(Enum): 9 | THIN = 'THIN' 10 | MEDIUM = 'MEDIUM' 11 | FAT = 'FAT' 12 | BIG = 'BIG' 13 | 14 | 15 | class Carousel(BaseElement): 16 | """ 17 | Create Carousel HSL message 18 | 19 | Attributes 20 | ---------- 21 | aspect_ratio : float 22 | used to determine the height of the carousel 23 | 24 | width : `CarouselWidth` 25 | The width of each carousel Item 26 | 27 | items : List[CarouselItem] 28 | list of carousel items for the carousel 29 | """ 30 | def __init__(self,text): 31 | super().__init__(text,'CAROUSEL') 32 | self.aspect_ratio: float = 1.0 33 | self.width: CarouselWidth = CarouselWidth.THIN 34 | self.items: List[CarouselItem] = [] 35 | 36 | def to_hsl(self): 37 | """ 38 | Generate HSL dict 39 | """ 40 | hsl = super().to_hsl() 41 | data = { 42 | 'image_aspect_ratio': self.aspect_ratio, 43 | 'width': self.width.value, 44 | 'items': [item.to_hsl() for item in self.items] 45 | } 46 | hsl['data'] = data 47 | 48 | return hsl 49 | -------------------------------------------------------------------------------- /hsl_builder/elements/carousel_item.py: -------------------------------------------------------------------------------- 1 | from .actionable import Actionable 2 | from typing import List 3 | 4 | class CarouselItem(object): 5 | """ 6 | Create Carousel Items for Carousel 7 | 8 | Attributes 9 | ---------- 10 | title : str 11 | Title of specific carousel item. 12 | 13 | subtitle : str 14 | Subtitle of specific carousel item. 15 | 16 | description : str 17 | More verbose description of item that is shown below the subtitle 18 | 19 | actionables : List[Actionable] 20 | Actionables to be performed when the user taps on the item 21 | 22 | meta : str 23 | meta value for the corresponding carousal item 24 | """ 25 | 26 | 27 | def __init__(self,title: str, subtitle: str): 28 | self.title: str = title 29 | self.subtitle: str = subtitle 30 | self.description: str = '' 31 | self.thumbnail: str = '' 32 | self.actionables: List[Actionable] = [] 33 | self.meta: str = '' 34 | 35 | def to_hsl(self) -> dict: 36 | """ 37 | Generate HSL dict 38 | """ 39 | return { 40 | 'title': self.title, 41 | 'sub_title': self.subtitle, 42 | 'description': self.description, 43 | 'actionables': [actionable.to_hsl() for actionable in self.actionables], 44 | 'meta': self.meta, 45 | 'thumbnail': { 46 | 'image': self.thumbnail 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## HSL Builder Repo 2 | 3 | Python pip package for creating HSL Elements. 4 | 5 | ### Installation: 6 | 7 | You can install hsl builder using pip. 8 | ```sh 9 | pip install --pre hsl_builder 10 | ``` 11 | OR 12 | 13 | You can also add `hsl_builder==0.0.1b0` it to your project _`requirements.txt`_ 14 | ### Usage: 15 | ```python 16 | #import hsl builder 17 | from hsl_builder import Button 18 | from hsl_builder.elements import Actionable, ActionableType, URI 19 | 20 | # Create a button 21 | button = Button("Title") 22 | 23 | # Create link actionable 24 | actionable = Actionable("actionable text", ActionableType.APP_ACTION, URI.LINK) 25 | actionable.payload = { 26 | 'url': 'https://www.haptik.ai' 27 | } 28 | # Add actionable to button 29 | button.actionables.append(actionable) 30 | 31 | # generate hsl for our button object 32 | hsl = button.to_hsl() 33 | ``` 34 | 35 | ### Publishing 36 | 37 | Make sure you have specified the correct version specified in `setup.py` 38 | 39 | Remove existing build files 40 | 41 | ```sh 42 | rm -rf rm -rf dist/ build/ hsl_builder.egg-info/ 43 | ``` 44 | 45 | Build package wheel 46 | 47 | ```sh 48 | python setup.py sdist bdist_wheel 49 | ``` 50 | 51 | Publishing package 52 | 53 | Make sure that correct version is specified in setup.py 54 | 55 | you'll need to create an account at pypi beforehand 56 | 57 | publish to test.pypi.org to make sure that whl is built correctly and can be installed and used from other machines 58 | ```sh 59 | python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/* 60 | ``` 61 | 62 | publish to pypi 63 | ```sh 64 | python -m twine upload dist/* 65 | ``` -------------------------------------------------------------------------------- /tests/test_silent_action.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase, main 2 | 3 | from hsl_builder.elements import SilentAction 4 | 5 | 6 | class SilentItemTest(TestCase): 7 | 8 | def setUp(self): 9 | self.silent_action = SilentAction("Action", 1, "via_name") 10 | self.expected_hsl = { 11 | 'type': 'Action', 12 | 'data': { 13 | 'Id': 1, 14 | 'via_name': 'via_name' 15 | } 16 | } 17 | 18 | def test_default_hsl(self): 19 | """ 20 | verify the default hsl generated 21 | """ 22 | self.assertDictEqual(self.silent_action.to_hsl(), self.expected_hsl) 23 | 24 | def test_hsl_action_id(self): 25 | """ 26 | verify that action_id is updated in the hsl 27 | """ 28 | self.silent_action.action_id = 23 29 | self.expected_hsl['data']['Id'] = 23 30 | self.assertDictEqual(self.silent_action.to_hsl(), self.expected_hsl) 31 | 32 | def test_hsl_via_name(self): 33 | """ 34 | verify that via_name is updated in the hsl 35 | """ 36 | self.silent_action.via_name = 'mock string' 37 | self.expected_hsl['data']['via_name'] = 'mock string' 38 | self.assertDictEqual(self.silent_action.to_hsl(), self.expected_hsl) 39 | 40 | def test_hsl_data_payload(self): 41 | """ 42 | verify that data payload is included in the hsl 43 | """ 44 | self.silent_action.data = { 45 | 'key': 'value' 46 | } 47 | self.expected_hsl['data']['key'] = 'value' 48 | self.assertDictEqual(self.silent_action.to_hsl(), self.expected_hsl) 49 | 50 | if __name__ == '__main__': 51 | main() 52 | -------------------------------------------------------------------------------- /tests/test_button.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase,main 2 | import mock 3 | 4 | from hsl_builder import Button 5 | from hsl_builder.elements import Actionable 6 | from .mocks import MockActionable 7 | 8 | class ButtonTest(TestCase): 9 | 10 | def setUp(self): 11 | self.button = Button("title") 12 | self.expected_hsl = { 13 | 'text': 'title', 14 | 'type': 'BUTTON', 15 | 'voice_text': '', 16 | 'data': { 17 | 'items': [] 18 | } 19 | } 20 | 21 | def test_initialization(self): 22 | """ 23 | verify that button is initialized with the correct options 24 | """ 25 | self.assertEqual(self.button.text, "title") 26 | self.assertEqual(self.button.type, "BUTTON") 27 | self.assertEqual(self.button.actionables, []) 28 | 29 | def test_hsl_default(self): 30 | """ 31 | verify the default hsl generated 32 | """ 33 | self.assertDictEqual(self.button.to_hsl(),self.expected_hsl) 34 | 35 | @mock.patch.object(Actionable,'to_hsl') 36 | def test_hsl_actionable(self,mock_hsl): 37 | """ 38 | verify that button generates correct hsl for added actionables 39 | """ 40 | mock_hsl.return_value = { 41 | "key": "value" 42 | } 43 | mock_actionable = MockActionable() 44 | self.button.actionables.append(mock_actionable) 45 | self.expected_hsl['data']['items'] = [ 46 | { 47 | "key": "value" 48 | } 49 | ] 50 | self.assertDictEqual(self.button.to_hsl(), self.expected_hsl) 51 | mock_hsl.assert_called_once() 52 | 53 | if __name__ == '__main__': 54 | main() 55 | -------------------------------------------------------------------------------- /tests/test_silent.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase,main 2 | import mock 3 | 4 | from hsl_builder import Silent 5 | from hsl_builder.elements import SilentAction 6 | from .mocks import MockSilentAction 7 | 8 | 9 | class SilentTest(TestCase): 10 | 11 | def setUp(self): 12 | self.silent = Silent("title") 13 | 14 | def test_initialization(self): 15 | """ 16 | verify that silent hsl is initialized with correct options 17 | """ 18 | self.assertEqual(self.silent.text, "title") 19 | self.assertEqual(self.silent.type, "SILENT") 20 | self.assertEqual(self.silent.actions, []) 21 | 22 | def test_hsl_default(self): 23 | """ 24 | verify the default hsl generated 25 | """ 26 | self.assertDictEqual(self.silent.to_hsl(),{ 27 | 'text': 'title', 28 | 'type': 'SILENT', 29 | 'voice_text': '', 30 | 'data': { 31 | 'silent_actions': [] 32 | } 33 | }) 34 | 35 | @mock.patch.object(SilentAction,'to_hsl') 36 | def test_hsl_with_silent_action(self, mock_hsl): 37 | """ 38 | verify that silent actions are added in the hsl 39 | """ 40 | mock_hsl.return_value = { 41 | 'key': 'value' 42 | } 43 | self.silent.actions.append(MockSilentAction()) 44 | self.assertDictEqual(self.silent.to_hsl(),{ 45 | 'text': 'title', 46 | 'type': 'SILENT', 47 | 'voice_text': '', 48 | 'data': { 49 | 'silent_actions': [ 50 | { 51 | 'key':'value' 52 | } 53 | ] 54 | } 55 | }) 56 | mock_hsl.assert_called_once() 57 | 58 | if __name__ == '__main__': 59 | main() 60 | -------------------------------------------------------------------------------- /hsl_builder/elements/actionable.py: -------------------------------------------------------------------------------- 1 | from enum import unique,Enum 2 | 3 | @unique 4 | class URI(Enum): 5 | """ 6 | URI Types for showing which screen to open in case of app_action 7 | """ 8 | NONE = '' 9 | SEND_LOCATION = 'SEND_LOCATION' 10 | CAROUSEL_DETAIL = 'CAROUSEL_DETAIL' 11 | GALLERY_PICKER = 'GALLERY_PICKER' 12 | IMAGE_UPLOAD = 'IMAGE_UPLOAD' 13 | DOCUMENT_PICKER = 'DOCUMENT_PICKER' 14 | LAUNCH_CHANNEL = 'LAUNCH_CHANNEL' 15 | LINK = 'LINK' 16 | SELF_SERVE_WEB = 'SELF_SERVE_WEB' 17 | 18 | 19 | @unique 20 | class ActionableType(Enum): 21 | """ 22 | Actionable Types for specifying what action should be taken 23 | """ 24 | APP_ACTION = 'APP_ACTION' 25 | MESSAGE_BAR = 'MESSAGE_BAR' 26 | TEXT_ONLY = 'TEXT_ONLY' 27 | FORM_SHOW = 'FORM_SHOW' 28 | SHARE_RECEIPT = 'SHARE_RECEIPT' 29 | APP_FEEDBACK = 'APP_FEEDBACK' 30 | SHARE = 'SHARE' 31 | 32 | class Actionable(object): 33 | """ 34 | Create Actionables to be used in Buttons or Text messages 35 | 36 | Attributes 37 | ---------- 38 | text : str 39 | Text for the Actionable that will be displayed on the CTA (button, quick reply,etc). 40 | 41 | type : ActionableType 42 | The type of `ActionableType`. 43 | 44 | type : URI 45 | The type of `URI`. 46 | 47 | location_required : bool 48 | True if location is required for using the Actionable. 49 | 50 | is_default : bool 51 | if True, on click of the element, this actionable will get triggered. 52 | 53 | payload : dict 54 | optional payload containing metadata that might be needed by the Actionable 55 | """ 56 | 57 | def __init__(self, text: str, type: ActionableType, uri: URI): 58 | self.text: str = text 59 | self.type: ActionableType = type 60 | self.uri: URI = uri 61 | self.location_required: bool = False 62 | self.is_default: bool = False 63 | self.payload: dict = {} 64 | 65 | def to_hsl(self) -> dict: 66 | """ 67 | Generate HSL dict 68 | """ 69 | return { 70 | 'actionable_text': self.text, 71 | 'type': self.type.value, 72 | 'uri': self.uri.value, 73 | 'is_default': 1 if self.is_default else 0, 74 | 'location_required': self.location_required, 75 | 'payload': self.payload 76 | } 77 | -------------------------------------------------------------------------------- /tests/test_carousel_item.py: -------------------------------------------------------------------------------- 1 | import mock 2 | from unittest import TestCase,main 3 | 4 | from hsl_builder.elements import CarouselItem,Actionable 5 | from .mocks import MockActionable 6 | 7 | class CarouselItemTest(TestCase): 8 | 9 | def setUp(self): 10 | self.carousel_item = CarouselItem("title","subtitle") 11 | self.expected_hsl = { 12 | 'title': 'title', 13 | 'sub_title': 'subtitle', 14 | 'description': '', 15 | 'actionables': [], 16 | 'meta': '', 17 | 'thumbnail': { 18 | 'image': '' 19 | } 20 | } 21 | 22 | def test_hsl_default(self): 23 | """ 24 | verify the default hsl generated 25 | """ 26 | self.assertDictEqual(self.carousel_item.to_hsl(),self.expected_hsl) 27 | 28 | 29 | def test_hsl_description(self): 30 | """ 31 | verify descrption is updated in the hsl 32 | """ 33 | self.expected_hsl['description'] = 'mock string' 34 | self.carousel_item.description = 'mock string' 35 | self.assertDictEqual(self.carousel_item.to_hsl(),self.expected_hsl) 36 | 37 | def test_hsl_meta(self): 38 | """ 39 | verify meta is updated in the hsl 40 | """ 41 | self.expected_hsl['meta'] = 'mock string' 42 | self.carousel_item.meta = 'mock string' 43 | self.assertDictEqual(self.carousel_item.to_hsl(),self.expected_hsl) 44 | 45 | def test_hsl_thumbnail(self): 46 | """ 47 | verify thumbnail is updated in the hsl 48 | """ 49 | self.expected_hsl['thumbnail']['image'] = 'mock string' 50 | self.carousel_item.thumbnail = 'mock string' 51 | self.assertDictEqual(self.carousel_item.to_hsl(),self.expected_hsl) 52 | 53 | @mock.patch.object(Actionable,'to_hsl') 54 | def test_hsl_actionables(self, mock_hsl): 55 | """ 56 | verify actionable objects are added in the hsl 57 | """ 58 | self.carousel_item.actionables.append(MockActionable()) 59 | mock_hsl.return_value = { 60 | 'key': 'value' 61 | } 62 | self.expected_hsl['actionables'] = [ 63 | { 64 | 'key': 'value' 65 | } 66 | ] 67 | self.assertDictEqual(self.carousel_item.to_hsl(),self.expected_hsl) 68 | mock_hsl.assert_called_once() 69 | 70 | if __name__ == '__main__': 71 | main() 72 | -------------------------------------------------------------------------------- /tests/test_form.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase,main 2 | import mock 3 | 4 | from hsl_builder import Form 5 | from hsl_builder.elements import FormField 6 | from .mocks import MockFormField 7 | 8 | class FormTest(TestCase): 9 | 10 | def setUp(self): 11 | self.form = Form("title", "subtitle") 12 | 13 | def test_initialization(self): 14 | """ 15 | verify that form is initialized with the correct options 16 | """ 17 | self.assertEqual(self.form.title, "title") 18 | self.assertEqual(self.form.type, "FORM") 19 | self.assertEqual(self.form.subtitle, "subtitle") 20 | self.assertEqual(self.form.fields, []) 21 | 22 | @mock.patch.object(FormField, 'to_hsl') 23 | def test_hsl(self, mock_hsl): 24 | """ 25 | verify the default hsl generated 26 | """ 27 | mockfield = MockFormField() 28 | mock_hsl.return_value = { 29 | "text": "mock text" 30 | } 31 | self.form.fields.append(mockfield) 32 | self.assertDictEqual(self.form.to_hsl(),{ 33 | 'title': 'title', 34 | 'type': 'FORM', 35 | 'subtitle': 'subtitle', 36 | 'data': { 37 | 'fields': [ 38 | { 39 | "text": "mock text" 40 | } 41 | ] 42 | } 43 | }) 44 | mock_hsl.assert_called_once() 45 | 46 | @mock.patch.object(FormField, 'to_hsl') 47 | def test_hsl_multiple_fields(self, mock_hsl): 48 | """ 49 | verify the default hsl generated 50 | """ 51 | mockfield1 = MockFormField() 52 | mockfield2 = MockFormField() 53 | mock_hsl.return_value = { 54 | "text": "mock text" 55 | } 56 | self.form.fields.append(mockfield1) 57 | self.form.fields.append(mockfield2) 58 | self.assertDictEqual(self.form.to_hsl(),{ 59 | 'title': 'title', 60 | 'type': 'FORM', 61 | 'subtitle': 'subtitle', 62 | 'data': { 63 | 'fields': [ 64 | { 65 | "text": "mock text" 66 | }, 67 | { 68 | "text": "mock text" 69 | } 70 | ] 71 | } 72 | }) 73 | self.assertEqual(mock_hsl.call_count,2) 74 | 75 | if __name__ == '__main__': 76 | main() 77 | -------------------------------------------------------------------------------- /tests/test_text.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase,main 2 | import mock 3 | 4 | from hsl_builder import Text 5 | from hsl_builder.elements import Actionable, ActionableType, URI 6 | from .mocks import MockActionable 7 | 8 | 9 | class TextTest(TestCase): 10 | 11 | def setUp(self): 12 | self.text = Text("title") 13 | 14 | def test_initialization(self): 15 | """ 16 | verify that text is initialized with proper options 17 | """ 18 | self.assertEqual(self.text.text, "title") 19 | self.assertEqual(self.text.type, "TEXT") 20 | self.assertEqual(self.text.quick_replies, []) 21 | 22 | def test_hsl_default(self): 23 | """ 24 | verify the default hsl generated 25 | """ 26 | self.assertDictEqual(self.text.to_hsl(),{ 27 | 'text': 'title', 28 | 'type': 'TEXT', 29 | 'voice_text': '', 30 | 'data': { 31 | 'quick_replies': [] 32 | } 33 | }) 34 | 35 | @mock.patch.object(Actionable,'to_hsl') 36 | def test_hsl_qr(self,mock_hsl): 37 | """ 38 | verify that Quick_replies is updated in the hsl 39 | """ 40 | mock_hsl.return_value = { 41 | "key": "value" 42 | } 43 | mock_qr = MockActionable() 44 | self.text.quick_replies.append(mock_qr) 45 | self.assertDictEqual(self.text.to_hsl(),{ 46 | 'text': 'title', 47 | 'type': 'TEXT', 48 | 'voice_text': '', 49 | 'data': { 50 | 'quick_replies': [ 51 | { 52 | "key": "value" 53 | } 54 | ] 55 | } 56 | }) 57 | mock_hsl.assert_called_once() 58 | 59 | @mock.patch.object(Actionable,'to_hsl') 60 | def test_hsl_multiple_qr(self,mock_hsl): 61 | """ 62 | verify that Quick_replies is updated in the hsl 63 | """ 64 | mock_hsl.return_value = { 65 | "key": "value" 66 | } 67 | mock_qr1 = MockActionable() 68 | mock_qr2 = MockActionable() 69 | self.text.quick_replies.append(mock_qr1) 70 | self.text.quick_replies.append(mock_qr2) 71 | self.assertDictEqual(self.text.to_hsl(),{ 72 | 'text': 'title', 73 | 'type': 'TEXT', 74 | 'voice_text': '', 75 | 'data': { 76 | 'quick_replies': [ 77 | { 78 | "key": "value" 79 | }, 80 | { 81 | "key": "value" 82 | } 83 | ] 84 | } 85 | }) 86 | self.assertEqual(mock_hsl.call_count,2) 87 | 88 | if __name__ == '__main__': 89 | main() 90 | -------------------------------------------------------------------------------- /hsl_builder/elements/form_field.py: -------------------------------------------------------------------------------- 1 | from enum import Enum,unique 2 | from typing import List 3 | 4 | @unique 5 | class FormFieldType(Enum): 6 | TEXT = 'text' 7 | PICKER = 'picker' 8 | TIME = 'time' 9 | DATE = 'date' 10 | CONTACT_PICKER = 'contactpicker' 11 | START_DATE = 'startdate' 12 | END_DATE = 'enddate' 13 | SEARCH = 'search' 14 | SEARCH_EDITABLE = 'searcheditable' 15 | SAVED_ADDRESS = 'savedaddress' 16 | DOB = 'dob' 17 | MULTI_DAY_PICKER = 'multidaypicker' 18 | MULTI_SELECT_PICKER = 'multiselectpicker' 19 | 20 | @unique 21 | class FormKeyboardType(Enum): 22 | NORMAL = 'normal' 23 | NUMBER = 'number' 24 | EMAIL = 'email' 25 | 26 | 27 | class FormField(object): 28 | """ 29 | Create FormField objects that can be added in the Form Object 30 | 31 | Attributes 32 | ---------- 33 | key : str 34 | When the form is submitted, apps show the value for the form field against this key. 35 | This key will then be used for entity detection in bot builder 36 | 37 | type : FormFieldType 38 | The type of the formfield 39 | 40 | keyboard_type : FormKeyboardType 41 | The keyboard type used to fill the corresponding form 42 | 43 | order : int 44 | The order of the form 45 | 46 | icon : str 47 | Icon name for the field. 48 | 49 | hint : str 50 | Input placeholder for the field 51 | 52 | options : str 53 | In case of FormField type picker or multiselectpicker 54 | These will be used as the options to pick from. 55 | 56 | search_source : str 57 | API URL to get the search results from 58 | 59 | search_placeholder : str 60 | placeholder when no text is entered for search type fields 61 | 62 | autofill : str 63 | Auto fill field based on user profile or default value. 64 | 65 | auto_fill_source : str 66 | Source for the autofilling the field 67 | """ 68 | def __init__(self, key: str, form_type: FormFieldType, order: int, hint: str, icon: str): 69 | self.key: str = key 70 | self.type: FormFieldType = form_type 71 | self.keyboard_type: FormKeyboardType = FormKeyboardType.NORMAL 72 | self.order: int = order 73 | self.icon: str = icon 74 | self.hint: str = hint 75 | self.options: List[str] = [] 76 | self.search_source: str = '' 77 | self.search_placeholder: str = '' 78 | self.autofill: str = '' 79 | self.autofill_source: str = '' 80 | 81 | def to_hsl(self) -> dict: 82 | """ 83 | returns an HSL dict for the form field 84 | """ 85 | return { 86 | 'key': self.key, 87 | 'type': self.type.value, 88 | 'keyboard_type': self.keyboard_type.value, 89 | 'order': self.order, 90 | 'icon': self.icon, 91 | 'hint': self.hint, 92 | 'options': self.options, 93 | 'search_source': self.search_source, 94 | 'search_placeholder': self.search_placeholder, 95 | 'autofill': self.autofill, 96 | 'autofill_source': self.autofill_source, 97 | #TODO: add regex fields 98 | } 99 | -------------------------------------------------------------------------------- /tests/test_system.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase,main 2 | import mock 3 | 4 | from hsl_builder import System,SystemEvents 5 | 6 | class SystemCompleteTest(TestCase): 7 | 8 | def setUp(self): 9 | self.system = System("complete", SystemEvents.COMPLETE) 10 | 11 | def test_initialization(self): 12 | """ 13 | verify that System Message is initialized with the correct options 14 | """ 15 | self.assertEqual(self.system.text, "complete") 16 | self.assertEqual(self.system.event, SystemEvents.COMPLETE) 17 | self.assertEqual(self.system.type, "SYSTEM") 18 | 19 | def test_hsl_default(self): 20 | """ 21 | verify the default hsl generated 22 | """ 23 | self.assertDictEqual(self.system.to_hsl(),{ 24 | 'text': 'complete', 25 | 'type': 'SYSTEM', 26 | 'voice_text': '', 27 | 'data': { 28 | 'event_name': 'chat_complete', 29 | 'payload': {} 30 | } 31 | }) 32 | 33 | def test_hsl_payload(self): 34 | """ 35 | verify that payload is added in the generated hsl 36 | """ 37 | self.system.payload = { 38 | "key": "value", 39 | "agent":"agent_name" 40 | } 41 | self.assertDictEqual(self.system.to_hsl(),{ 42 | 'text': 'complete', 43 | 'type': 'SYSTEM', 44 | 'voice_text': '', 45 | 'data': { 46 | 'event_name': 'chat_complete', 47 | 'payload': { 48 | "key": "value", 49 | "agent":"agent_name" 50 | } 51 | } 52 | }) 53 | 54 | class SystemWaitingTest(TestCase): 55 | 56 | def setUp(self): 57 | self.system = System("waiting", SystemEvents.PINNED) 58 | 59 | def test_initialization(self): 60 | """ 61 | verify that System Message is initialized with the correct options 62 | """ 63 | self.assertEqual(self.system.text, "waiting") 64 | self.assertEqual(self.system.event, SystemEvents.PINNED) 65 | self.assertEqual(self.system.type, "SYSTEM") 66 | 67 | def test_hsl_default(self): 68 | """ 69 | verify the default hsl generated 70 | """ 71 | self.assertDictEqual(self.system.to_hsl(),{ 72 | 'text': 'waiting', 73 | 'type': 'SYSTEM', 74 | 'voice_text': '', 75 | 'data': { 76 | 'event_name': 'chat_pinned', 77 | 'payload': {} 78 | } 79 | }) 80 | 81 | def test_hsl_payload(self): 82 | """ 83 | verify that payload is added in the generated hsl 84 | """ 85 | self.system.payload = { 86 | "key": "value", 87 | "agent":"agent_name" 88 | } 89 | self.assertDictEqual(self.system.to_hsl(),{ 90 | 'text': 'waiting', 91 | 'type': 'SYSTEM', 92 | 'voice_text': '', 93 | 'data': { 94 | 'event_name': 'chat_pinned', 95 | 'payload': { 96 | "key": "value", 97 | "agent":"agent_name" 98 | } 99 | } 100 | }) 101 | 102 | if __name__ == '__main__': 103 | main() 104 | -------------------------------------------------------------------------------- /tests/test_carousel.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase,main 2 | import mock 3 | 4 | from hsl_builder import Carousel,CarouselWidth 5 | from hsl_builder.elements import CarouselItem 6 | 7 | class CarouselTest(TestCase): 8 | 9 | def setUp(self): 10 | self.carousel = Carousel("title") 11 | 12 | def test_initialization(self): 13 | """ 14 | verify the default properties on initialization 15 | """ 16 | self.assertEqual(self.carousel.text, "title") 17 | self.assertEqual(self.carousel.type, "CAROUSEL") 18 | self.assertEqual(self.carousel.items, []) 19 | self.assertEqual(self.carousel.aspect_ratio, 1) 20 | self.assertEqual(self.carousel.width, CarouselWidth.THIN) 21 | 22 | def test_hsl_default(self): 23 | """ 24 | verify the default hsl generated 25 | """ 26 | self.assertDictEqual(self.carousel.to_hsl(),{ 27 | 'text': 'title', 28 | 'type': 'CAROUSEL', 29 | 'voice_text': '', 30 | 'data': { 31 | 'image_aspect_ratio': 1, 32 | 'width': 'THIN', 33 | 'items': [] 34 | } 35 | }) 36 | 37 | @mock.patch.object(CarouselItem,'to_hsl') 38 | def test_hsl_carousel_item(self,mock_hsl): 39 | """ 40 | verify that hsl for carouselItem is added in the Carousel 41 | """ 42 | mock_hsl.return_value = { 43 | "key": "value" 44 | } 45 | mock_carousel_item = CarouselItem("title", "subtitle") 46 | self.carousel.items.append(mock_carousel_item) 47 | self.assertDictEqual(self.carousel.to_hsl(),{ 48 | 'text': 'title', 49 | 'type': 'CAROUSEL', 50 | 'voice_text': '', 51 | 'data': { 52 | 'image_aspect_ratio': 1, 53 | 'width': 'THIN', 54 | 'items': [ 55 | { 56 | "key": "value" 57 | } 58 | ] 59 | } 60 | }) 61 | mock_hsl.assert_called_once() 62 | 63 | def test_hsl_aspect_ratio(self): 64 | """ 65 | verify that aspect ratio is updated in the generated hsl 66 | """ 67 | self.carousel.aspect_ratio = 23 68 | self.assertDictEqual(self.carousel.to_hsl(),{ 69 | 'text': 'title', 70 | 'type': 'CAROUSEL', 71 | 'voice_text': '', 72 | 'data': { 73 | 'image_aspect_ratio': 23, 74 | 'width': 'THIN', 75 | 'items': [] 76 | } 77 | }) 78 | 79 | def test_hsl_width_FAT(self): 80 | """ 81 | verify that FAT width is updated in the generated hsl 82 | """ 83 | self.carousel.width = CarouselWidth.FAT 84 | self.assertDictEqual(self.carousel.to_hsl(),{ 85 | 'text': 'title', 86 | 'type': 'CAROUSEL', 87 | 'voice_text': '', 88 | 'data': { 89 | 'image_aspect_ratio': 1, 90 | 'width': 'FAT', 91 | 'items': [] 92 | } 93 | }) 94 | 95 | def test_hsl_width_BIG(self): 96 | """ 97 | verify that BIG width is updated in the generated hsl 98 | """ 99 | self.carousel.width = CarouselWidth.BIG 100 | self.assertDictEqual(self.carousel.to_hsl(),{ 101 | 'text': 'title', 102 | 'type': 'CAROUSEL', 103 | 'voice_text': '', 104 | 'data': { 105 | 'image_aspect_ratio': 1, 106 | 'width': 'BIG', 107 | 'items': [] 108 | } 109 | }) 110 | 111 | def test_hsl_width_MEDIUM(self): 112 | """ 113 | verify that MEDIUM width is updated in the generated hsl 114 | """ 115 | self.carousel.width = CarouselWidth.MEDIUM 116 | self.assertDictEqual(self.carousel.to_hsl(),{ 117 | 'text': 'title', 118 | 'type': 'CAROUSEL', 119 | 'voice_text': '', 120 | 'data': { 121 | 'image_aspect_ratio': 1, 122 | 'width': 'MEDIUM', 123 | 'items': [] 124 | } 125 | }) 126 | 127 | if __name__ == '__main__': 128 | main() 129 | -------------------------------------------------------------------------------- /tests/test_actionable.py: -------------------------------------------------------------------------------- 1 | import mock 2 | from unittest import TestCase, main 3 | from hsl_builder.elements import Actionable, URI, ActionableType 4 | 5 | class ActionableTest(TestCase): 6 | 7 | def setUp(self): 8 | self.actionable = Actionable("title", ActionableType.TEXT_ONLY, URI.NONE) 9 | self.expected_hsl = { 10 | 'actionable_text': 'title', 11 | 'type': 'TEXT_ONLY', 12 | 'uri': '', 13 | 'is_default': 0, 14 | 'location_required': False, 15 | 'payload': { 16 | 17 | } 18 | } 19 | 20 | def test_default_hsl(self): 21 | """ 22 | verify the default hsl generated 23 | """ 24 | self.assertDictEqual(self.actionable.to_hsl(),self.expected_hsl) 25 | 26 | def test_actionable_type_APP_ACTION(self): 27 | """ 28 | verify that actionable type app_action is updated in the hsl 29 | """ 30 | self.actionable.type = ActionableType.APP_ACTION 31 | self.expected_hsl['type'] = 'APP_ACTION' 32 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 33 | 34 | def test_actionable_type_MESSAGE_BAR(self): 35 | """ 36 | verify that actionable type message_bar is updated in the hsl 37 | """ 38 | self.actionable.type = ActionableType.MESSAGE_BAR 39 | self.expected_hsl['type'] = 'MESSAGE_BAR' 40 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 41 | 42 | def test_actionable_type_FORM_SHOW(self): 43 | """ 44 | verify that actionable type form_show is updated in the hsl 45 | """ 46 | self.actionable.type = ActionableType.FORM_SHOW 47 | self.expected_hsl['type'] = 'FORM_SHOW' 48 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 49 | 50 | def test_actionable_type_SHARE_RECEIPT(self): 51 | """ 52 | verify that actionable type share_receipt is updated in the hsl 53 | """ 54 | self.actionable.type = ActionableType.SHARE_RECEIPT 55 | self.expected_hsl['type'] = 'SHARE_RECEIPT' 56 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 57 | 58 | def test_actionable_type_APP_FEEDBACK(self): 59 | """ 60 | verify that actionable type app_feedback is updated in the hsl 61 | """ 62 | self.actionable.type = ActionableType.APP_FEEDBACK 63 | self.expected_hsl['type'] = 'APP_FEEDBACK' 64 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 65 | 66 | def test_actionable_type_SHARE(self): 67 | """ 68 | verify that actionable type share is updated in the hsl 69 | """ 70 | self.actionable.type = ActionableType.SHARE 71 | self.expected_hsl['type'] = 'SHARE' 72 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 73 | 74 | def test_hsl_URI_type_SEND_LOCATION(self): 75 | """ 76 | verify that URI type send_location is updated in the hsl 77 | """ 78 | self.actionable.uri = URI.SEND_LOCATION 79 | self.expected_hsl['uri'] = 'SEND_LOCATION' 80 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 81 | 82 | def test_hsl_URI_type_CAROUSEL_DETAIL(self): 83 | """ 84 | verify that URI type carousel_detail is updated in the hsl 85 | """ 86 | self.actionable.uri = URI.CAROUSEL_DETAIL 87 | self.expected_hsl['uri'] = 'CAROUSEL_DETAIL' 88 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 89 | 90 | def test_hsl_URI_type_GALLERY_PICKER(self): 91 | """ 92 | verify that URI type gallery_picker is updated in the hsl 93 | """ 94 | self.actionable.uri = URI.GALLERY_PICKER 95 | self.expected_hsl['uri'] = 'GALLERY_PICKER' 96 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 97 | 98 | def test_hsl_URI_type_IMAGE_UPLOAD(self): 99 | """ 100 | verify that URI type image_upload is updated in the hsl 101 | """ 102 | self.actionable.uri = URI.IMAGE_UPLOAD 103 | self.expected_hsl['uri'] = 'IMAGE_UPLOAD' 104 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 105 | 106 | def test_hsl_URI_type_DOCUMENT_PICKER(self): 107 | """ 108 | verify that URI type document_picker is updated in the hsl 109 | """ 110 | self.actionable.uri = URI.DOCUMENT_PICKER 111 | self.expected_hsl['uri'] = 'DOCUMENT_PICKER' 112 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 113 | 114 | def test_hsl_URI_type_LAUNCH_CHANNEL(self): 115 | """ 116 | verify that URI type launch_channel is updated in the hsl 117 | """ 118 | self.actionable.uri = URI.LAUNCH_CHANNEL 119 | self.expected_hsl['uri'] = 'LAUNCH_CHANNEL' 120 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 121 | 122 | def test_hsl_URI_type_LINK(self): 123 | """ 124 | verify that URI type link is updated in the hsl 125 | """ 126 | self.actionable.uri = URI.LINK 127 | self.expected_hsl['uri'] = 'LINK' 128 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 129 | 130 | def test_hsl_URI_type_SELF_SERVE_WEB(self): 131 | """ 132 | verify that URI type self_serve_web is updated in the hsl 133 | """ 134 | self.actionable.uri = URI.SELF_SERVE_WEB 135 | self.expected_hsl['uri'] = 'SELF_SERVE_WEB' 136 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 137 | 138 | def test_hsl_location_required(self): 139 | """ 140 | verify that location_required is updated in the hsl 141 | """ 142 | self.actionable.location_required = True 143 | self.expected_hsl['location_required'] = True 144 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 145 | 146 | def test_hsl_is_default(self): 147 | """ 148 | verify that is_default is updated in the hsl 149 | """ 150 | self.actionable.is_default = True 151 | self.expected_hsl['is_default'] = 1 152 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 153 | 154 | def test_hsl_payload(self): 155 | """ 156 | verify that payload is added in the hsl 157 | """ 158 | self.actionable.payload = { 159 | 'key': 'value' 160 | } 161 | self.expected_hsl['payload'] = { 162 | 'key': 'value' 163 | } 164 | self.assertDictEqual(self.actionable.to_hsl(), self.expected_hsl) 165 | 166 | 167 | if __name__ == '__main__': 168 | main() 169 | -------------------------------------------------------------------------------- /tests/test_form_field.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase,main 2 | import mock 3 | 4 | from hsl_builder.elements import FormField,FormFieldType,FormKeyboardType 5 | 6 | class FormFieldTest(TestCase): 7 | 8 | def setUp(self): 9 | self.field = FormField("key", FormFieldType.TEXT,1,"hint", "icon") 10 | self.default_expected_hsl = { 11 | 'key': 'key', 12 | 'type': 'text', 13 | 'keyboard_type': 'normal', 14 | 'order': 1, 15 | 'icon': 'icon', 16 | 'hint': 'hint', 17 | 'options': [], 18 | 'search_source': '', 19 | 'search_placeholder': '', 20 | 'autofill': '', 21 | 'autofill_source': '' 22 | } 23 | 24 | def test_default_hsl(self): 25 | """ 26 | verify the default hsl generated 27 | """ 28 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 29 | 30 | def test_field_type_picker(self): 31 | """ 32 | verify that Field type picker is updated in the hsl 33 | """ 34 | self.default_expected_hsl['type'] = 'picker' 35 | self.field.type = FormFieldType.PICKER 36 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 37 | 38 | def test_field_type_time(self): 39 | """ 40 | verify that Field type time is updated in the hsl 41 | """ 42 | self.default_expected_hsl['type'] = 'time' 43 | self.field.type = FormFieldType.TIME 44 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 45 | 46 | def test_field_type_data(self): 47 | """ 48 | verify that Field type date is updated in the hsl 49 | """ 50 | self.default_expected_hsl['type'] = 'date' 51 | self.field.type = FormFieldType.DATE 52 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 53 | 54 | def test_field_type_contactpicker(self): 55 | """ 56 | verify that Field type contactpicker is updated in the hsl 57 | """ 58 | self.default_expected_hsl['type'] = 'contactpicker' 59 | self.field.type = FormFieldType.CONTACT_PICKER 60 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 61 | 62 | def test_field_type_startdate(self): 63 | """ 64 | verify that Field type startdate is updated in the hsl 65 | """ 66 | self.default_expected_hsl['type'] = 'startdate' 67 | self.field.type = FormFieldType.START_DATE 68 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 69 | 70 | def test_field_type_enddate(self): 71 | """ 72 | verify that Field type enddate is updated in the hsl 73 | """ 74 | self.default_expected_hsl['type'] = 'enddate' 75 | self.field.type = FormFieldType.END_DATE 76 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 77 | 78 | def test_field_type_search(self): 79 | """ 80 | verify that Field type search is updated in the hsl 81 | """ 82 | self.default_expected_hsl['type'] = 'search' 83 | self.field.type = FormFieldType.SEARCH 84 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 85 | 86 | def test_field_type_searcheditable(self): 87 | """ 88 | verify that Field type searcheditable is updated in the hsl 89 | """ 90 | self.default_expected_hsl['type'] = 'searcheditable' 91 | self.field.type = FormFieldType.SEARCH_EDITABLE 92 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 93 | 94 | def test_field_type_savedaddress(self): 95 | """ 96 | verify that Field type savedaddress is updated in the hsl 97 | """ 98 | self.default_expected_hsl['type'] = 'savedaddress' 99 | self.field.type = FormFieldType.SAVED_ADDRESS 100 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 101 | 102 | def test_field_type_dob(self): 103 | """ 104 | verify that Field type dob is updated in the hsl 105 | """ 106 | self.default_expected_hsl['type'] = 'dob' 107 | self.field.type = FormFieldType.DOB 108 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 109 | 110 | def test_field_type_multidaypicker(self): 111 | """ 112 | verify that Field type multidaypicker is updated in the hsl 113 | """ 114 | self.default_expected_hsl['type'] = 'multidaypicker' 115 | self.field.type = FormFieldType.MULTI_DAY_PICKER 116 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 117 | 118 | def test_field_type_multiselectpicker(self): 119 | """ 120 | verify that Field type multiselectpicker is updated in the hsl 121 | """ 122 | self.default_expected_hsl['type'] = 'multiselectpicker' 123 | self.field.type = FormFieldType.MULTI_SELECT_PICKER 124 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 125 | 126 | def test_field_keyboard_type_number(self): 127 | """ 128 | verify that keyboard type number is updated in the hsl 129 | """ 130 | self.default_expected_hsl['keyboard_type'] = 'number' 131 | self.field.keyboard_type = FormKeyboardType.NUMBER 132 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 133 | 134 | def test_field_keyboard_type_email(self): 135 | """ 136 | verify that keyboard type email is updated in the hsl 137 | """ 138 | self.default_expected_hsl['keyboard_type'] = 'email' 139 | self.field.keyboard_type = FormKeyboardType.EMAIL 140 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 141 | 142 | def test_field_order_hsl(self): 143 | """ 144 | verify that order is updated in the hsl 145 | """ 146 | self.default_expected_hsl['order'] = 33 147 | self.field.order = 33 148 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 149 | 150 | def test_field_icon_hsl(self): 151 | """ 152 | verify that icon is updated in the hsl 153 | """ 154 | self.default_expected_hsl['icon'] = 'mock icon url' 155 | self.field.icon = 'mock icon url' 156 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 157 | 158 | def test_field_hint_hsl(self): 159 | """ 160 | verify that hint is updated in the hsl 161 | """ 162 | self.default_expected_hsl['hint'] = 'mock hint' 163 | self.field.hint = 'mock hint' 164 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 165 | 166 | def test_field_options_hsl(self): 167 | """ 168 | verify that options is updated in the hsl 169 | """ 170 | self.default_expected_hsl['options'] = ['option1', 'option 2'] 171 | self.field.options = ['option1', 'option 2'] 172 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 173 | 174 | def test_field_search_source_hsl(self): 175 | """ 176 | verify that search_source is updated in the hsl 177 | """ 178 | self.default_expected_hsl['search_source'] = 'mock search source' 179 | self.field.search_source = 'mock search source' 180 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 181 | 182 | def test_field_search_placeholder_hsl(self): 183 | """ 184 | verify that search_placeholder is updated in the hsl 185 | """ 186 | self.default_expected_hsl['search_placeholder'] = 'mock search placeholder' 187 | self.field.search_placeholder = 'mock search placeholder' 188 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 189 | 190 | def test_field_autofill_hsl(self): 191 | """ 192 | verify that autofill is updated in the hsl 193 | """ 194 | self.default_expected_hsl['autofill'] = 'mock autofill' 195 | self.field.autofill = 'mock autofill' 196 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 197 | 198 | def test_field_autofill_source_hsl(self): 199 | """ 200 | verify that autofill_source is updated in the hsl 201 | """ 202 | self.default_expected_hsl['autofill_source'] = 'mock autofill source' 203 | self.field.autofill_source = 'mock autofill source' 204 | self.assertDictEqual(self.field.to_hsl(),self.default_expected_hsl) 205 | 206 | --------------------------------------------------------------------------------