Skip to main content

Webdriver Extension with Page Object Wrapper

Project description

Citronella

PyPI version Downloads

webdriver extension with a page object wrapper.

alt terminal alt pytest-html alt github-action

Example Tests

Selenium

import pytest
from Pages.contents_page import ContentsPage


class TestNavigationMenu:

    def test_help_page(self, web):
        web.driver.get('https://pypi.org/')
        web.page = ContentsPage

        web.page.home_page.help_button.click()
        assert 'Help' in web.driver.title

    def test_sponsors_page(self, web):
        web.page.help_page.sponsors_button.click()
        assert 'Sponsors' in web.driver.title

    def test_login_page(self, web):
        web.page.sponsors_page.login_button.click()
        assert 'Log' in web.driver.title

    def test_register_page(self, web):
        web.page.login_page.register_button.click()
        assert 'Create' in web.driver.title

Appium

import pytest
from Pages.contents_page import ContentsPage


class TestInput:

    def test_input(self, web):
        web.page = ContentsPage
        web.page.home_page.gallery_button.click()
        web.page.gallery_page.text_input.send_keys('citronella')
        web.page.gallery_page.add_button.click()
        elements = web.page.gallery_page.text_lists.get_elements()
        assert 'citronella' in [x.text for x in elements]

Even though this module is mainly designed for the page object model, it can also be used without it for quick prototyping or mockups, etc.

from selenium import webdriver
from selenium.webdriver.common.by import By
from citronella import WebPage


driver = webdriver.Chrome()

web = WebPage(driver, webdriver_wait=20, logger=False)
web.driver.get('https://pypi.org/')

web.locate(By.ID, 'search').get_element().send_keys('citronella')
web.locate(By.XPATH, '//button[@type="submit"]/i').get_element().click()

elements = web.locate(By.XPATH, '//span[@class="package-snippet__name"]')
if elements.ec_visibility_of_all_elements_located():
    results = elements.get_elements()
    text_lists = [x.text for x in results]

Install Package

pip install citronella

Documentation

There are only two modules import in this package:

  • The first module is for conftest.py.

Selenium

import pytest
from selenium import webdriver
from citronella import WebPage


@pytest.fixture(autouse=True, scope='class')
def web(request):
    driver = webdriver.Chrome()
    yield WebPage(driver)
    driver.quit()

Appium

import pytest
import os
from appium import webdriver
from appium.options.android import UiAutomator2Options
from citronella import WebPage


@pytest.fixture(autouse='true', scope='class')
def web(request):
    options = UiAutomator2Options()
    options.platformName = 'Android'
    options.app = os.getcwd() + '/APK/ApiDemos-debug.apk.zip'
    driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', options=options)
    yield WebPage(driver)
    driver.quit()
  • The second module are for the page object model.

Selenium

from selenium.webdriver.common.by import By
from citronella import ui
from Pages.components import Header


class HomePage(Header):

    def some_button(self):
        return ui(By.XPATH, '//a[@name="foo"]')

    def search_input(self):
        return ui(By.ID, 'search')

    def search_button(self):
        return ui(By.NAME, 'search-button')

Appium

from appium.webdriver.common.appiumby import AppiumBy
from citronella import ui
from Pages.components import Header


class HomePage(Header):

    def some_button(self):
        return ui(AppiumBy.XPATH, '//a[@name="foo"]')

    def search_input(self):
        return ui(AppiumBy.ACCESSIBILITY_ID, 'search')

    def search_button(self):
        return ui(AppiumBy.ID, 'search-button')

Page Object Design / Strategy

There's a two ways to create a page object for WebPage:

  1. Straightforward approach: This method requires importing the page object for each test.
from selenium import webdriver
from selenium.webdriver.common.by import By
from citronella import WebPage, ui


class HomePage:
    def auth_buton(self):
        return ui(By.XPATH, '//a[@name="foo"]')

class LoginPage:
    def email_input(self):
        return ui(By.ID, 'email')

    def password_input(self):
        return ui(By.ID, 'password')

    def login_buton(self):
        return ui(By.ID, 'login')

driver = webdriver.Chrome()
web = WebPage(driver)
web.driver.get('https://foobarbaz.com/')
web.page = HomePage
web.page.auth_button.click()
web.page = LoginPage
web.page.email_input.send_keys('foo')
web.page.password_input.send_keys('bar')
web.page.login_button.click()
  1. Lazy loading approach: This method is slightly more complex but offers the benefit of lazy loading. see ContentsPage example or this Page object example
from selenium import webdriver
from selenium.webdriver.common.by import By
from citronella import WebPage, ui


class ContentsPage:
    def home_page(self):
        return HomePage

    def login_page(self):
        return LoginPage

class HomePage:
    def auth_buton(self):
        return ui(By.XPATH, '//a[@name="foo"]')

class LoginPage:
    def email_input(self):
        return ui(By.ID, 'email')

    def password_input(self):
        return ui(By.ID, 'password')

    def login_buton(self):
        return ui(By.ID, 'login')

driver = webdriver.Chrome()
web = WebPage(driver)
web.driver.get('https://foobarbaz.com/')
web.page = ContentsPage
web.page.home_page.auth_button.click()
web.page.login_page.email_input.send_keys('foo')
web.page.login_page.password_input.send_keys('bar')
web.page.login_page.login_button.click()

Usage

citronella.WebPage

Args:
  • driver / webdriver
Kwargs (optional):
  • webdriver_wait number(seconds), default value is 10
  • logger bool, default value is True
Method Lists:
Method Name Args* Kwargs** Note
driver - - return selenium webdriver object
locate by, value - similar asdriver.get_element as input & return citronella.WebUi object
page page object - setter
page - - getter
webdriver_wait number(sec) -
ready_state number(sec) - execute javascript document.readyState manually, default timeout is 30
sleep number(sec) -

citronella.ui / citronella.WebUi

Args:
  • by
  • value
Method Lists:
Method Name Args* Kwargs** Note
send_keys text clear bool, return_key bool
click - -
get_element - -
get_elements - -
ec_element_to_be_clickable - - wrapper of EC / excpected_condition
ec_presence_of_element_located - - wrapper of EC / excpected_condition
ec_presence_of_all_elements_located - - wrapper of EC / excpected_condition
ec_visibility_of_element_located - - wrapper of EC / excpected_condition
ec_visibility_of_all_elements_located - - wrapper of EC / excpected_condition
ec_visibility_of_any_elements_located - - wrapper of EC / excpected_condition
ec_invisibility_of_element_located - - wrapper of EC / excpected_condition
ec_element_located_to_be_selected - - wrapper of EC / excpected_condition

Testing powered by


BrowserStack Open-Source Program

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

citronella-1.0.1.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

citronella-1.0.1-py3-none-any.whl (12.9 kB view details)

Uploaded Python 3

File details

Details for the file citronella-1.0.1.tar.gz.

File metadata

  • Download URL: citronella-1.0.1.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.3

File hashes

Hashes for citronella-1.0.1.tar.gz
Algorithm Hash digest
SHA256 6a0abdd1db01a2c683802d2f2857a7f22a219b92870e5fa26280da854301e209
MD5 1a992e7b1a961cd31f533bc71f86f041
BLAKE2b-256 b2403808891e6374218157dbb28232177be085c4648dc333a5cf43d22d89f92d

See more details on using hashes here.

File details

Details for the file citronella-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: citronella-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 12.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.3

File hashes

Hashes for citronella-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 04ec3fe4355875fb24ac0cd0b4751c50aaad6d3e7f2169b595bee06ede99820a
MD5 2c1f4db0ce26319cb6cf3cfe259313a1
BLAKE2b-256 138e6d546822917c5cd349482a15301ac4b5d059cfa620c6783c8bb9e5a7fafc

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page