diff --git a/qacode/configs/settings.json b/qacode/configs/settings.json index 502b1925..ab75a18d 100644 --- a/qacode/configs/settings.json +++ b/qacode/configs/settings.json @@ -51,7 +51,8 @@ "web_controls": { "control_base": false, "control_form": false, - "control_dropdown": false + "control_dropdown": false, + "control_table": false }, "web_pages": false, "benchmarks": true diff --git a/qacode/core/loggers/logger_messages.py b/qacode/core/loggers/logger_messages.py index fc4f2d31..34625408 100644 --- a/qacode/core/loggers/logger_messages.py +++ b/qacode/core/loggers/logger_messages.py @@ -72,3 +72,5 @@ CDD_DESELECTALL_LOADED = "ctl_form | dropdown_select: deselected all" # noqa:E501 CDD_LOADED = "ctl_form | ctl.dropdown property for tag element" # noqa:E501 +# ControlTable +CT_BADTAG = "Can't use this for not tag element" # noqa:E501 diff --git a/qacode/core/webs/controls/__init__.py b/qacode/core/webs/controls/__init__.py index 561b4ab3..4f854677 100755 --- a/qacode/core/webs/controls/__init__.py +++ b/qacode/core/webs/controls/__init__.py @@ -3,7 +3,10 @@ from qacode.core.webs.controls import control_base +from qacode.core.webs.controls import control_dropdown from qacode.core.webs.controls import control_form +from qacode.core.webs.controls import control_table -__all__ = ['control_base', 'control_form'] +__all__ = [ + 'control_base', 'control_dropdown', 'control_form', 'control_table'] diff --git a/qacode/core/webs/controls/control_dropdown.py b/qacode/core/webs/controls/control_dropdown.py index 9dabf322..4f9f512b 100644 --- a/qacode/core/webs/controls/control_dropdown.py +++ b/qacode/core/webs/controls/control_dropdown.py @@ -32,8 +32,8 @@ def __check_reload__form__(self): if it's neccessary reload element properties """ super(ControlDropdown, self).__check_reload__form__() - reload_dropdown_needed = not self.element or not self.dropdown - if reload_dropdown_needed: + reload_needed = not self.element or not self.dropdown + if reload_needed: self.reload(**self.settings) def reload(self, **kwargs): diff --git a/qacode/core/webs/controls/control_form.py b/qacode/core/webs/controls/control_form.py index df56537b..7ae8b670 100644 --- a/qacode/core/webs/controls/control_form.py +++ b/qacode/core/webs/controls/control_form.py @@ -18,6 +18,8 @@ class ControlForm(ControlBase): strict_tag = None # tag=select IS_DROPDOWN = None + # tag=select + IS_TABLE = None def __init__(self, bot, **kwargs): """Instance of ControlForm. Load properties from settings dict. @@ -97,14 +99,17 @@ def __load_strict_tag__(self, strict_tag): instance ControlForm specific properties """ self.IS_DROPDOWN = False + self.IS_TABLE = False self.strict_tag = strict_tag - valid_tags = ['select'] + valid_tags = ['select', 'table'] self.bot.log.debug(MSG.CF_STRICTTAG_LOADING) if self.strict_tag.value not in valid_tags: raise ControlException( msg="This tag can be loaded as strict_rule") if self.tag == HtmlTag.TAG_SELECT.value: self.IS_DROPDOWN = True + if self.tag == HtmlTag.TAG_TABLE.value: + self.IS_TABLE = True self.bot.log.debug(MSG.CF_STRICTTAG_LOADED) return True diff --git a/qacode/core/webs/controls/control_table.py b/qacode/core/webs/controls/control_table.py new file mode 100644 index 00000000..ac7f417e --- /dev/null +++ b/qacode/core/webs/controls/control_table.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +"""Package module qacode.core.webs.control_form""" + + +from qacode.core.exceptions.control_exception import ControlException +from qacode.core.loggers import logger_messages as MSG +from qacode.core.webs.controls.control_base import ControlBase +from qacode.core.webs.controls.control_form import ControlForm + + +class ControlTable(ControlForm): + """TODO: doc class""" + + _table = None + + def __init__(self, bot, **kwargs): + """Instance of ControlForm. Load properties from settings dict. + Some elements need to search False to be search at future + """ + kwargs.update({"instance": "ControlTable"}) + strict_rules = kwargs.get("strict_rules") + if not bool(strict_rules): + strict_rules.append( + {"tag": "table", "type": "tag", "severity": "hight"}) + super(ControlTable, self).__init__(bot, **kwargs) + if not self.IS_TABLE and self.tag is not None: + raise ControlException(msg=MSG.CT_BADTAG) + self.bot.log.debug(MSG.CDD_LOADED) + + def __load_table__(self, element=None): + """Allow to load all TR > TD items from a TABLE element + + Examples: + Use case 1. TABLE > (TR > TH)+(TR > TD) + Use case 2. TABLE > (THEAD > (TR > TH))+(TBODY > (TR > TH)) + """ + if element is None: + element = self.element + self._table = ControlBase(self.bot, **{ + "selector": self.selector, + "element": element}) + # Load rows + # thead = self._table.find_child("thead") + # tbody = self._table.find_child("tbody") + # Load columns + # Load cells + # raise NotImplementedError("TODO: WIP zone") + + def __check_reload__form__(self): + """Allow to check before methods calls to ensure + if it's neccessary reload element properties + """ + super(ControlTable, self).__check_reload__form__() + reload_needed = not self.element or not self.table + if reload_needed: + self.reload(**self.settings) + if not self.IS_TABLE and self.tag is not None: + raise ControlException(msg=MSG.CT_BADTAG) + + def reload(self, **kwargs): + """Reload 'self.settings' property:dict and call to instance + logic with new configuration + """ + super(ControlTable, self).reload(**kwargs) + self.__load_table__(element=self.element) + + @property + def table(self): + """GETTER for 'table' property""" + return self._table + + @table.setter + def table(self, value): + """SETTER for 'table' property""" + if value is None or not isinstance(value, ControlBase): + raise ControlException("Can't set not 'Control' instance") + self.__load_table__(element=value) diff --git a/tests/001_functionals/suite_008_controltable.py b/tests/001_functionals/suite_008_controltable.py new file mode 100644 index 00000000..d2a792b2 --- /dev/null +++ b/tests/001_functionals/suite_008_controltable.py @@ -0,0 +1,125 @@ +# -*- coding: utf-8 -*- +"""Testsuite for package qacode.core.webs.controls""" + + +import pytest +from qacode.core.exceptions.control_exception import ControlException +from qacode.core.testing.test_info import TestInfoBotUnique +from qacode.core.webs.controls.control_base import ControlBase +from qacode.core.webs.controls.control_table import ControlTable +from qautils.files import settings +from selenium.webdriver.remote.webelement import WebElement +from selenium.webdriver.support.ui import Select + + +SETTINGS = settings(file_path="qacode/configs/") +SKIP_CONTROLS = SETTINGS['tests']['skip']['web_controls']['control_table'] +SKIP_CONTROLS_MSG = 'web_controls DISABLED by config file' + + +class TestControlDropdown(TestInfoBotUnique): + """Test Suite for ControlBase class""" + + # app from config + app = None + # page from config: app + page = None + url = None + # page from config: app + page_inputs = None + url_inputs = None + # elements from config: page + form_login = None + txt_username = None + txt_password = None + btn_submit = None + # elements from config: page_data + dd_base = None + dd_menu_data = None + dd_menu_data_lists = None + tbl_ok = None + + @classmethod + def setup_class(cls, **kwargs): + """TODO: doc method""" + super(TestControlDropdown, cls).setup_class( + config=settings(file_path="qacode/configs/"), + skip_force=SKIP_CONTROLS) + cls.add_property('app', cls.settings_app('qadmin')) + # page + cls.add_property('page', cls.settings_page('qacode_login')) + cls.add_property('url', cls.page.get('url')) + cls.add_property('form_login', cls.settings_control('form_login')) + cls.add_property('txt_username', cls.settings_control('txt_username')) + cls.add_property('txt_password', cls.settings_control('txt_password')) + cls.add_property('btn_submit', cls.settings_control('btn_submit')) + # page_inputs + cls.add_property('page_inputs', cls.settings_page('qacode_inputs')) + cls.add_property('url_inputs', cls.page_inputs.get('url')) + cls.add_property('dd_base', cls.settings_control('dd_base')) + cls.add_property('dd_menu_data', cls.settings_control('dd_menu_data')) + cls.add_property( + 'dd_menu_data_lists', cls.settings_control('dd_menu_data_lists')) + cls.add_property('tbl_ok', cls.settings_control('tbl_ok')) + + def setup_method(self, test_method): + """Configure self.attribute""" + super(TestControlDropdown, self).setup_method( + test_method, config=settings(file_path="qacode/configs/")) + + def setup_login_to_data(self): + """Do login before to exec some testcases""" + # setup_login + self.bot.navigation.get_url(self.page.get('url'), wait_for_load=10) + txt_username = self.bot.navigation.find_element( + self.txt_username.get("selector")) + txt_password = self.bot.navigation.find_element( + self.txt_password.get("selector")) + btn_submit = self.bot.navigation.find_element( + self.btn_submit.get("selector")) + self.bot.navigation.ele_write(txt_username, "admin") + self.bot.navigation.ele_write(txt_password, "admin") + self.bot.navigation.ele_click(btn_submit) + self.bot.navigation.ele_click( + self.bot.navigation.find_element_wait( + self.dd_menu_data.get("selector"))) + self.bot.navigation.ele_click( + self.bot.navigation.find_element_wait( + self.dd_menu_data_lists.get("selector"))) + # end setup_login + + @pytest.mark.skipIf(SKIP_CONTROLS, SKIP_CONTROLS_MSG) + @pytest.mark.parametrize("on_instance_search", [True, False]) + @pytest.mark.parametrize("auto_reload", [True, False]) + @pytest.mark.parametrize("strict_rules", [ + [{"tag": "table", "type": "tag", "severity": "hight"}] + ]) + def test_controltable_instance(self, on_instance_search, + strict_rules, auto_reload): + """Testcase: test_controltable_instance""" + self.setup_login_to_data() + cfg = self.tbl_ok + cfg.update({ + "instance": "ControlTable", + "on_instance_search": on_instance_search, + "auto_reload": auto_reload, + "strict_rules": strict_rules + }) + # functional testcases + ctl = ControlTable(self.bot, **cfg) + self.assert_is_instance(ctl, ControlTable) + self.assert_equals(ctl.selector, cfg.get('selector')) + self.assert_equals(ctl.instance, cfg.get('instance')) + self.assert_equals(ctl.name, cfg.get('name')) + self.assert_equals(ctl.locator, 'css selector') + self.assert_equals( + ctl.on_instance_search, cfg.get('on_instance_search')) + self.assert_equals(ctl.auto_reload, cfg.get('auto_reload')) + self.assert_equals( + len(ctl.strict_rules), len(cfg.get('strict_rules'))) + if on_instance_search: + self.assert_is_instance(ctl.element, WebElement) + if auto_reload is not None: + self.assert_none(ctl.table) + ctl.reload(**ctl.settings) + self.assert_is_instance(ctl.table, ControlBase) diff --git a/tests/001_functionals/suite_008_pagebase.py b/tests/001_functionals/suite_009_pagebase.py similarity index 100% rename from tests/001_functionals/suite_008_pagebase.py rename to tests/001_functionals/suite_009_pagebase.py diff --git a/tests/001_functionals/suite_009_reportertestlink.py b/tests/001_functionals/suite_010_reportertestlink.py similarity index 100% rename from tests/001_functionals/suite_009_reportertestlink.py rename to tests/001_functionals/suite_010_reportertestlink.py