Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: avoid initialization error in PageElements class using custom page elements #377

Merged
merged 2 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ v3.1.3

*Release date: In development*

- Fix `PageElements` class initialization when custom page element classes don't have all optional attributes

v3.1.2
------

Expand All @@ -22,6 +24,7 @@ v3.1.1
- Upgrade Sphinx version from 4.* to 7.* to fix readthedocs theme format
- Upgrade readthedocs-sphinx-search to 0.3.2 to fix security vulnerability
- Do not log warning messages when toolium system properties are used
- Allow to initialize a `PageElements` class with webview attributes

v3.1.0
------
Expand Down
15 changes: 9 additions & 6 deletions toolium/pageelements/page_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
from typing import List, Any
import inspect
from typing import Any, List

from toolium.driver_wrapper import DriverWrappersPool
from toolium.pageelements.button_page_element import Button
Expand Down Expand Up @@ -120,11 +121,13 @@ def page_elements(self) -> List[Any]:
self._page_elements = []
for order, web_element in enumerate(self.web_elements):
# Create multiple PageElement with original locator and order
page_element =\
self.page_element_class(self.locator[0], self.locator[1], parent=self.parent,
order=order, webview=self.webview,
webview_context_selection_callback=self.webview_context_selection_callback,
webview_csc_args=self.webview_csc_args)
# Optional parameters are passed only if they are defined in the PageElement constructor
signature = inspect.signature(self.page_element_class.__init__)
opt_names = ['parent', 'webview', 'webview_context_selection_callback', 'webview_csc_args']
opt_params = {name: getattr(self, name) for name in opt_names if name in signature.parameters}
if 'order' in signature.parameters:
opt_params['order'] = order
rgonalo marked this conversation as resolved.
Show resolved Hide resolved
page_element = self.page_element_class(self.locator[0], self.locator[1], **opt_params)
page_element.reset_object(self.driver_wrapper)
page_element._web_element = web_element
self._page_elements.append(page_element)
Expand Down
116 changes: 107 additions & 9 deletions toolium/test/pageelements/test_page_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,43 @@ def init_page_elements(self):
self.links = PageElements(By.XPATH, '//a')
self.inputs_with_parent = PageElements(By.XPATH, '//input', parent=(By.ID, 'parent'))
self.inputs_with_webview = PageElements(By.XPATH, '//input', webview=True)
self.inputs_with_webview_callback = \
PageElements(By.XPATH, '//input', webview_context_selection_callback=lambda a, b: (a, b),
webview_csc_args=['WEBVIEW_fake.other', "CDwindow-0123456789"], webview=True)
self.inputs_with_webview_callback = PageElements(By.XPATH, '//input',
webview_context_selection_callback=lambda a, b: (a, b),
webview_csc_args=['WEBVIEW_fake.other', "CDwindow-0123456789"],
webview=True)
self.parent_webview = PageElement(By.XPATH, '//parent', webview=True)
self.inputs_with_webview_parent = PageElements(By.XPATH, '//input', parent=self.parent_webview, webview=True)


class CustomElementAllAttributes(PageElement):
def __init__(self, by, value, parent=None, order=None, wait=False, shadowroot=None, webview=False,
webview_context_selection_callback=None, webview_csc_args=None):
super(CustomElementAllAttributes, self).__init__(by, value, parent, order, wait, shadowroot, webview,
webview_context_selection_callback, webview_csc_args)


class CustomElementSomeAttributes(PageElement):
def __init__(self, by, value, parent=None, order=None, wait=False, shadowroot=None):
super(CustomElementSomeAttributes, self).__init__(by, value, parent, order, wait, shadowroot)


class CustomElementMandatoryAttributes(PageElement):
def __init__(self, by, value):
super(CustomElementMandatoryAttributes, self).__init__(by, value)


class LoginWithPageElementsPageObject(PageObject):
def init_page_elements(self):
self.all_optional_attrs = PageElements(By.XPATH, '//input', page_element_class=CustomElementAllAttributes,
webview_context_selection_callback=lambda a, b: (a, b),
webview_csc_args=['WEBVIEW_fake.other', "CDwindow-0123456789"],
webview=True)
self.some_optional_attrs = PageElements(By.XPATH, '//input', page_element_class=CustomElementSomeAttributes,
parent=(By.ID, 'parent'))
self.only_mandatory_attrs = PageElements(By.XPATH, '//input',
page_element_class=CustomElementMandatoryAttributes)


@pytest.fixture
def driver_wrapper():
# Reset wrappers pool values
Expand Down Expand Up @@ -171,13 +201,81 @@ def test_reset_object(driver_wrapper):
assert page_element_21._web_element is not None


def test_get_page_elements_custom_element_class_all_optional(driver_wrapper):
driver_wrapper.driver.find_elements.return_value = child_elements
page_elements = LoginWithPageElementsPageObject().all_optional_attrs.page_elements

# Check that find_elements has been called just one time
driver_wrapper.driver.find_elements.assert_called_once_with(By.XPATH, '//input')
driver_wrapper.driver.find_element.assert_not_called()

# Check that the response is a list of 2 CustomElementAllFields with the expected web element
assert len(page_elements) == 2
assert isinstance(page_elements[0], CustomElementAllAttributes)
assert page_elements[0]._web_element == child_elements[0]
assert isinstance(page_elements[1], CustomElementAllAttributes)
assert page_elements[1]._web_element == child_elements[1]

# Check that the optional attributes are set correctly
assert page_elements[0].order == 0
assert page_elements[0].webview is True
assert page_elements[0].webview_context_selection_callback
assert page_elements[0].webview_csc_args == ['WEBVIEW_fake.other', "CDwindow-0123456789"]
assert page_elements[1].order == 1
assert page_elements[1].webview is True
assert page_elements[1].webview_context_selection_callback
assert page_elements[1].webview_csc_args == ['WEBVIEW_fake.other', "CDwindow-0123456789"]


def test_get_page_elements_custom_element_class_some_optional(driver_wrapper):
# Create a mock element
mock_element = mock.MagicMock(spec=WebElement)
mock_element.find_elements.return_value = child_elements

driver_wrapper.driver.find_element.return_value = mock_element
page_elements = LoginWithPageElementsPageObject().some_optional_attrs.page_elements

# Check that find_elements has been called just one time
driver_wrapper.driver.find_element.assert_called_once_with(By.ID, 'parent')
mock_element.find_elements.assert_called_once_with(By.XPATH, '//input')

# Check that the response is a list of 2 CustomElementSomeAttributes with the expected web element
assert len(page_elements) == 2
assert isinstance(page_elements[0], CustomElementSomeAttributes)
assert page_elements[0]._web_element == child_elements[0]
assert isinstance(page_elements[1], CustomElementSomeAttributes)
assert page_elements[1]._web_element == child_elements[1]

# Check that the optional attributes are set correctly
assert page_elements[0].order == 0
assert page_elements[0].parent == (By.ID, 'parent')
assert page_elements[1].order == 1
assert page_elements[0].parent == (By.ID, 'parent')


def test_get_page_elements_custom_element_class_only_mandatory(driver_wrapper):
driver_wrapper.driver.find_elements.return_value = child_elements
page_elements = LoginWithPageElementsPageObject().only_mandatory_attrs.page_elements

# Check that find_elements has been called just one time
driver_wrapper.driver.find_elements.assert_called_once_with(By.XPATH, '//input')
driver_wrapper.driver.find_element.assert_not_called()

# Check that the response is a list of 2 CustomElementMandatoryAttributes with the expected web element
assert len(page_elements) == 2
assert isinstance(page_elements[0], CustomElementMandatoryAttributes)
assert page_elements[0]._web_element == child_elements[0]
assert isinstance(page_elements[1], CustomElementMandatoryAttributes)
assert page_elements[1]._web_element == child_elements[1]


def test_get_page_elements_without_webview(driver_wrapper):
driver_wrapper.driver.find_elements.return_value = child_elements
page_elements = LoginPageObject().inputs.page_elements

# Check webview attribute is set to false by default in child elements
assert not page_elements[0].webview
assert not page_elements[1].webview
assert page_elements[0].webview is False
assert page_elements[1].webview is False


def test_get_page_elements_with_webview(driver_wrapper):
Expand All @@ -186,8 +284,8 @@ def test_get_page_elements_with_webview(driver_wrapper):

# Check webview attribute is set to true in child element when a Pagelements element
# is created with the webview attribute
assert page_elements[0].webview
assert page_elements[1].webview
assert page_elements[0].webview is True
assert page_elements[1].webview is True


def test_get_page_elements_with_context_selection_callback_provided(driver_wrapper):
Expand All @@ -196,9 +294,9 @@ def test_get_page_elements_with_context_selection_callback_provided(driver_wrapp

# Check context selection callback provided is set correctly to pageelements
assert page_elements[0].webview_context_selection_callback
assert page_elements[0].webview_csc_args
assert page_elements[0].webview_csc_args == ['WEBVIEW_fake.other', "CDwindow-0123456789"]
assert page_elements[1].webview_context_selection_callback
assert page_elements[1].webview_csc_args
assert page_elements[1].webview_csc_args == ['WEBVIEW_fake.other', "CDwindow-0123456789"]


def test_mobile_automatic_context_selection_switch_to_new_webview_context_in_pagelements_without_parent(driver_wrapper):
Expand Down
Loading