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

consider moving to protocols for the majority of helper-entities like Command #518

Open
yashaka opened this issue Mar 5, 2024 · 0 comments

Comments

@yashaka
Copy link
Owner

yashaka commented Mar 5, 2024

This might allow to move from something like this:

# command.py

class js:

    class __ClickWithOffset(Command[Element]):
        def __init__(self):
            self._description = 'click'

        @overload
        def __call__(self, element: Element) -> None: ...

        @overload
        def __call__(self, *, xoffset=0, yoffset=0) -> Command[Element]: ...

        def __call__(self, element: Element | None = None, *, xoffset=0, yoffset=0):
            def func(element: Element):
                element.execute_script(
                    '''
                    const offsetX = arguments[0]
                    const offsetY = arguments[1]
                    const rect = element.getBoundingClientRect()

                    function mouseEvent() {
                      if (typeof (Event) === 'function') {
                        return new MouseEvent('click', {
                          view: window,
                          bubbles: true,
                          cancelable: true,
                          clientX: rect.left + rect.width / 2 + offsetX,
                          clientY: rect.top + rect.height / 2 + offsetY
                        })
                      }
                      else {
                        const event = document.createEvent('MouseEvent')
                        event.initEvent('click', true, true)
                        event.type = 'click'
                        event.view = window
                        event.clientX = rect.left + rect.width / 2 + offsetX
                        event.clientY = rect.top + rect.height / 2 + offsetY
                        return event
                      }
                    }
                    element.dispatchEvent(mouseEvent())
                    ''',
                    xoffset,
                    yoffset,
                )

            if element is not None:
                # somebody passed command as `.perform(command.js.click)`
                # not as `.perform(command.js.click())`
                func(element)
                return None

            return Command(
                (
                    self.__str__()
                    if (not xoffset and not yoffset)
                    else f'click(xoffset={xoffset},yoffset={yoffset})'
                ),
                func,
            )

    click = __ClickWithOffset()

to something like this:

# command.py

class js:
    @staticmethod
    @overload
    def click(element: Element | None) -> None: ...

    @staticmethod
    @overload
    def click(*, xoffset=0, yoffset=0) -> Command[Element]: ...

    @staticmethod
    def click(element: Element | None = None, *, xoffset=0, yoffset=0):
        def func(element: Element):
            element.execute_script(
                '''
                const offsetX = arguments[0]
                const offsetY = arguments[1]
                const rect = element.getBoundingClientRect()

                function mouseEvent() {
                  if (typeof (Event) === 'function') {
                    return new MouseEvent('click', {
                      view: window,
                      bubbles: true,
                      cancelable: true,
                      clientX: rect.left + rect.width / 2 + offsetX,
                      clientY: rect.top + rect.height / 2 + offsetY
                    })
                  }
                  else {
                    const event = document.createEvent('MouseEvent')
                    event.initEvent('click', true, true)
                    event.type = 'click'
                    event.view = window
                    event.clientX = rect.left + rect.width / 2 + offsetX
                    event.clientY = rect.top + rect.height / 2 + offsetY
                    return event
                  }
                }
                element.dispatchEvent(mouseEvent())
                ''',
                xoffset,
                yoffset,
            )

        if isinstance(element, Element):
            # somebody passed command as `.perform(command.js.click)`
            # not as `.perform(command.js.click())`
            func(element)

        return Command(
            (
                'click'
                if (not xoffset and not yoffset)
                else f'click(xoffset={xoffset},yoffset={yoffset})'
            ),
            func,
        )

that can be kind of more KISS way to implement a command that can be called in 3 different syntax:

element.perform(command.js.click(xoffset=10, yoffset=0))
element.perform(command.js.click())
element.perform(command.js.click)

Right now, the "functional" way can hardly make autocompletion work after element.perform(command.js.click).HERE

There are also other examples where we have some problems with autocompletion because of too "strict" typing based on normal classes...

yashaka added a commit that referenced this issue Mar 6, 2024
... as it has not been fully working in context of autocompletion for now (waiting for #518 to progress on this)
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

1 participant