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

execut_script() TypeError:Object of type Element is not json serializable #26

Open
lileeves opened this issue Jun 21, 2021 · 1 comment

Comments

@lileeves
Copy link

申明一个元素
class xxPage(Page):
xxbtn = Element(xpath="~~~~~")
在测试类中:
class TestXX:
def test_xxpage(browser):
page = xxPage(broeser)
page.execut_script("arguments[0].click()", page.xxbtn)
在selenium 中都可以通过 driver.execut_script("arguments[0].click()", xxbtn) 执行,但是poium 报错TypeError:Object of type Element is not json serializable,是什么问题呢?

@YunJing-P
Copy link

YunJing-P commented Aug 23, 2021

原因(应该是这样)

page.execute_script("arguments[0].click()", page.xxbtn)

Element类是描述符类,走的是__get__方法,返回self(应该是当前实例),并不是elem(元素),所以报错了
看page_objects.py 130行

class Element(object):
    """
    Returns an element object
    """

    def __init__(self, timeout=5, describe="undefined", index=0, **kwargs):
        self.timeout = timeout
        self.index = index
        self.desc = describe
        if not kwargs:
            raise ValueError("Please specify a locator")
        if len(kwargs) > 1:
            raise ValueError("Please specify only one locator")
        self.kwargs = kwargs
        self.k, self.v = next(iter(kwargs.items()))

        if self.k not in LOCATOR_LIST.keys():
            raise FindElementTypesError("Element positioning of type '{}' is not supported.".format(self.k))

    def __get__(self, instance, owner):
        if instance is None:
            return None

        Browser.driver = instance.driver
        return self

    def __set__(self, instance, value):
        self.__get__(instance, instance.__class__)
        self.send_keys(value)

    ...

    def __get_element(self, by, value):
        """
        Judge element positioning way, and returns the element.
        """

        # selenium
        if by == "id_":
            self.__find_element((By.ID, value))
            elem = Browser.driver.find_elements_by_id(value)[self.index]
        elif by == "name":
            self.__find_element((By.NAME, value))
            elem = Browser.driver.find_elements_by_name(value)[self.index]
        elif by == "class_name":
            self.__find_element((By.CLASS_NAME, value))
            elem = Browser.driver.find_elements_by_class_name(value)[self.index]
        elif by == "tag":
            self.__find_element((By.TAG_NAME, value))
            elem = Browser.driver.find_elements_by_tag_name(value)[self.index]
        elif by == "link_text":
            self.__find_element((By.LINK_TEXT, value))
            elem = Browser.driver.find_elements_by_link_text(value)[self.index]
        elif by == "partial_link_text":
            self.__find_element((By.PARTIAL_LINK_TEXT, value))
            elem = Browser.driver.find_elements_by_partial_link_text(value)[self.index]
        elif by == "xpath":
            self.__find_element((By.XPATH, value))
            elem = Browser.driver.find_elements_by_xpath(value)[self.index]
        elif by == "css":
            self.__find_element((By.CSS_SELECTOR, value))
            elem = Browser.driver.find_elements_by_css_selector(value)[self.index]

        # appium
        elif by == "ios_uiautomation":
            self.__find_element((MobileBy.IOS_UIAUTOMATION, value))
            elem = Browser.driver.find_elements_by_ios_uiautomation(value)[self.index]
        elif by == "ios_predicate":
            self.__find_element((MobileBy.IOS_PREDICATE, value))
            elem = Browser.driver.find_elements_by_ios_predicate(value)[self.index]
        elif by == "ios_class_chain":
            self.__find_element((MobileBy.IOS_CLASS_CHAIN, value))
            elem = Browser.driver.find_elements_by_ios_class_chain(value)[self.index]
        elif by == "android_uiautomator":
            self.__find_element((MobileBy.ANDROID_UIAUTOMATOR, value))
            elem = Browser.driver.find_elements_by_android_uiautomator(value)[self.index]
        elif by == "android_viewtag":
            self.__find_element((MobileBy.ANDROID_VIEWTAG, value))
            elem = Browser.driver.find_elements_by_android_viewtag(value)[self.index]
        elif by == "android_data_matcher":
            self.__find_element((MobileBy.ANDROID_DATA_MATCHER, value))
            elem = Browser.driver.find_elements_by_android_data_matcher(value)[self.index]
        elif by == "accessibility_id":
            self.__find_element((MobileBy.ACCESSIBILITY_ID, value))
            elem = Browser.driver.find_elements_by_accessibility_id(value)[self.index]
        elif by == "android_view_matcher":
            self.__find_element((MobileBy.ANDROID_VIEW_MATCHER, value))
            elem = Browser.driver.find_elements_by_android_view_matcher(value)[self.index]
        elif by == "windows_uiautomation":
            self.__find_element((MobileBy.WINDOWS_UI_AUTOMATION, value))
            elem = Browser.driver.find_elements_by_windows_uiautomation(value)[self.index]
        elif by == "image":
            self.__find_element((MobileBy.IMAGE, value))
            elem = Browser.driver.find_elements_by_image(value)[self.index]
        elif by == "custom":
            self.__find_element((MobileBy.CUSTOM, value))
            elem = Browser.driver.find_elements_by_custom(value)[self.index]
        else:
            raise FindElementTypesError(
                "Please enter the correct targeting elements")
        if Browser.show is True:
            try:
                style_red = 'arguments[0].style.border="2px solid #FF0000"'
                style_blue = 'arguments[0].style.border="2px solid #00FF00"'
                style_null = 'arguments[0].style.border=""'

                for _ in range(2):
                    Browser.driver.execute_script(style_red, elem)
                    sleep(0.1)
                    Browser.driver.execute_script(style_blue, elem)
                    sleep(0.1)
                Browser.driver.execute_script(style_blue, elem)
                sleep(0.5)
                Browser.driver.execute_script(style_null, elem)
            except WebDriverException:
                pass

        return elem
...

其实__elements()返回的才是page.execute_script("arguments[0].click()", elems)应该接受的参数

但虫师大佬把这个方法私有化了,不能在外部调用了(如果有误我道歉)

我的处理方法是

"""
InheritElement.py
"""
from poium.config import Browser
from poium.common import logging
from poium import Element

class InheritElement(Element):
    def click_js(self):
        Browser.driver.execute_script("arguments[0].click();", self._Element__get_element(self.k, self.v))
        logging.info("🖱 click element by click_js: {}".format(self.desc))

我的处理方法是再封装一层类,强制调用私有方法(但这种做法不是很符合规范)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants