Metadata-Version: 2.1
Name: zelenium
Version: 1.0.2
Summary: New Selenium framework for Python with base pages and elements
Home-page: https://github.com/zeburek/zelenium
Author: Parviz Khavari
Author-email: me@parviz.pw
License: GNU General Public License v3 (GPLv3)
Description: # zelenium
        New Selenium framework for Python with base pages and elements
        
        # Installation
        
        ```bash
        pip install zelenium
        ```
        
        # Usage
        
        Zelenium offers several features that could be combined with classical
        selenium usage:
        
        * Driver singleton configuration;
        * BasePage with BaseElements;
        * Suffix and formatting mechanisms for BaseElements;
        * It also should be useful for Appium testing.
        
        ## zelenium configuration
        
        To setup configuration for zelenium you could just use `Config`:
        
        ```python
        from selenium import webdriver
        from zelenium import Config
        
        config = Config.get_instance()
        config.driver = webdriver.Chrome()
        ```
        
        Because Config is singleton - you could not use it with two different
        webdrivers at one moment. But if you need it, you could use private class:
        
        ```python
        from zelenium import Config
        from zelenium.base.config import _Config
        
        config1 = Config.get_instance()
        config2 = _Config()
        
        assert not (config1 is config2)  # No assertion
        ```
        
        ## BasePage and BaseElement
        
        What offers you BasePage:
        
        * No need to pass webdriver instance - it would be passed from
        configuration automatically
        * Some predefined methods, which are useful in testing
        * Suffix mechanism
        
        ### Define new Page
        
        Let's imagine that we have already setup webdriver for Config,
        and starting to create new page:
        
        ```python
        from selenium.webdriver.common.by import By
        from zelenium import BasePage
        
        class LoginPage(BasePage):
            title = (By.CSS_SELECTOR, "[data-test='title']")
            username = (By.CSS_SELECTOR, "[data-test='username']")
            password = (By.CSS_SELECTOR, "[data-test='password']")
            submit = (By.CSS_SELECTOR, "[data-test='submit']")
        
        def main():
            login_page = LoginPage()
            print(login_page.title().text)
        
        main()
        ```
        
        If we execute it after opening something in browser - it will find
        element and print text inside of it.
        
        How it works?
        
        Well, BasePage also has a `metaclass` that will go all over page class
        fields and if field is tuple with two strings - it would replace it with
        `BaseElement`.
        
        `BaseElement` itself has magic `__call__` method,  which executes when
        you 'call' class instance:
        ```python
        from zelenium.base import BaseElement
        elem = BaseElement("by", "selector")
        web_element = elem()  # Here you calls class instance and it will return
                              # WebElement for you. Just classic WebElement
        ```
        
        ### Inherit pages
        
        For example, you have several pages, which have same structure, but some
        different logic, for example:
        
        ```python
        from selenium.webdriver.common.by import By
        from zelenium import BasePage
        
        class LoginPage(BasePage):
            title = (By.CSS_SELECTOR, "[data-test='title']")
            username = (By.CSS_SELECTOR, "[data-test='username']")
            password = (By.CSS_SELECTOR, "[data-test='password']")
            submit = (By.CSS_SELECTOR, "[data-test='submit']")
        
            def login(self, username, password):
                self.username().send_keys(username)
                self.password().send_keys(password)
                self.submit().click()
        
        
        class RegisterPage(LoginPage):
            full_name = (By.CSS_SELECTOR, "[data-test='full_name']")
        
            def register(self, full_name, username, password):
                self.full_name().send_key(full_name)
                self.username().send_keys(username)
                self.password().send_keys(password)
                self.submit().click()
        ```
        
        Using this - you have no need to redefine elements on different pages -
        you could just inherit them, if they have same locators (or quite the same).
        
        ### Format elements
        
        Sometimes you need to define a lot of elements with similar locators.
        Zelenium offers two way to solve this. First is BaseElement formatting:
        
        ```python
        from selenium.webdriver.common.by import By
        from zelenium import BasePage
        
        class DevicesPage(BasePage):
            _cell = (By.CSS_SELECTOR, "[data-test='devicesPageCell_{}']")
            user = _cell.format("user")
            imei = _cell.format("imei")
            iccid = _cell.format("iccid")
            model = _cell.format("model")
        ```
        
        `.format()` method formats locator as a string and returns new instance
        of BaseElement. It also handles during class loading, so you do not need
        to do anything.
        
        Second mechanism is suffix:
        
        ```python
        from selenium.webdriver.common.by import By
        from zelenium import BasePage
        
        class DevicesPage(BasePage):
            __suffix = "devicesPageCell_"
            user = (By.CSS_SELECTOR, "[data-test='{s}_user']")
            imei = (By.CSS_SELECTOR, "[data-test='{s}_imei']")
            iccid = (By.CSS_SELECTOR, "[data-test='{s}_iccid']")
            model = (By.CSS_SELECTOR, "[data-test='{s}_model']")
        ```
        
        Main differences of this two mechanisms are:
        
        * Suffix adds to locator automatically;
        * Suffix could be inherited;
        * Format could be used anywhere outside classes - you could format
        element in some functions according to changes on page.
        
        Example of suffix inheritance:
        
        ```python
        from selenium.webdriver.common.by import By
        from zelenium import BasePage
        
        
        class LoginPage(BasePage):
            __suffix = "loginPageForm_"
        
            title = (By.CSS_SELECTOR, "[data-test='{s}title']")
            username = (By.CSS_SELECTOR, "[data-test='{s}username']")
            password = (By.CSS_SELECTOR, "[data-test='{s}password']")
            submit = (By.CSS_SELECTOR, "[data-test='{s}submit']")
        
        
        class RegisterPage(LoginPage):
            __suffix = "registerPageForm_"
        
            email = (By.CSS_SELECTOR, "[data-test='{s}email']")
            confirm = (By.CSS_SELECTOR, "[data-test='{s}confirm']")
        
        
        class RenamedRegisterPage(RegisterPage):
            __suffix = "renamedRegisterPageForm_"
        
        
        def main():
            log = LoginPage()
            reg = RegisterPage()
            ren = RenamedRegisterPage()
        
            print(log.title)
            print(log.username)
            print(log.password)
            print(log.submit)
            print(reg.title)
            print(reg.username)
            print(reg.password)
            print(reg.submit)
            print(reg.email)
            print(reg.confirm)
            print(ren.title)
            print(ren.username)
            print(ren.password)
            print(ren.submit)
            print(ren.email)
            print(ren.confirm)
        
        
        if __name__ == '__main__':
            main()
        ```
        
        This code will output:
        
        ```text
        Element [data-test='loginPageForm_title'] (css selector)
        Element [data-test='loginPageForm_username'] (css selector)
        Element [data-test='loginPageForm_password'] (css selector)
        Element [data-test='loginPageForm_submit'] (css selector)
        Element [data-test='registerPageForm_title'] (css selector)
        Element [data-test='registerPageForm_username'] (css selector)
        Element [data-test='registerPageForm_password'] (css selector)
        Element [data-test='registerPageForm_submit'] (css selector)
        Element [data-test='registerPageForm_email'] (css selector)
        Element [data-test='registerPageForm_confirm'] (css selector)
        Element [data-test='renamedRegisterPageForm_title'] (css selector)
        Element [data-test='renamedRegisterPageForm_username'] (css selector)
        Element [data-test='renamedRegisterPageForm_password'] (css selector)
        Element [data-test='renamedRegisterPageForm_submit'] (css selector)
        Element [data-test='renamedRegisterPageForm_email'] (css selector)
        Element [data-test='renamedRegisterPageForm_confirm'] (css selector)
        ```
        
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Development Status :: 3 - Alpha
Classifier: Natural Language :: English
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
Classifier: Topic :: Software Development :: Testing
Description-Content-Type: text/markdown
