# Citronella
[](https://badge.fury.io/py/citronella)
[](https://pepy.tech/project/citronella)
webdriver extension with a page object wrapper.



## Example Tests
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.
```python
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]
```
### Selenium
```python
import pytest
from Pages.home.home_page import HomePage
class TestNavigationMenu:
def test_help_page(self, web):
web.driver.get('https://pypi.org/')
web.page_object(HomePage)
web.page.help_button.click()
assert 'Help' in web.driver.title
def test_sponsors_page(self, web):
web.page.sponsors_button.click()
assert 'Sponsors' in web.driver.title
def test_login_page(self, web):
web.page.login_button.click()
assert 'Log' in web.driver.title
def test_register_page(self, web):
web.page.register_button.click()
assert 'Create' in web.driver.title
```
### Appium
```python
import pytest
from Pages.api_demos_page import ApiDemosPage
class TestNavigationMenu:
def test_accessibility_page(self, web):
web.page_object(ApiDemosPage)
web.page.accessibility_button.click()
assert web.page.accessibility_node_provider_button.get_element().is_visible()
def test_animation_page(self, web):
web.back
web.page.animation_button.click()
assert web.page.cloning_button.get_element().is_visible()
def test_app_page(self, web):
web.back
web.page.app_button.click()
assert web.page.activity_button.get_element().is_visible()
def test_os_page(self, web):
web.back
web.page.os_button.click()
assert web.page.morse_code_button.get_element().is_visible()
```
___
## Install Package
```bash
pip install citronella
```
___
## Documentation
There are only three modules imported in this package:
* The first module is for conftest.py.
### Selenium
```python
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
```python
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 and third modules are for the page object model.
[Check out this link for more information on the Page Object Design.](https://github.com/heyclore/citronella/tree/main/python/example#readme)
### Selenium
```python
from selenium.webdriver.common.by import By
from citronella import Ui, PlaceholderPage
from Pages.component.HeaderMenu import HeaderMenu
class HomePage(HeaderMenu):
def some_button(self):
return Ui(By.XPATH, '//a[@name="foo"]')
def search_input(self):
return Ui(By.ID, 'search')
def search_button(self):
from Pages.SearchPage import SearchPage
return Ui(By.NAME, 'search-button', SearchPage)
def link_to_somewhere_currently_dont_have_page_object(self):
return Ui(By.NAME, 'search-button', PlaceholderPage)
```
### Appium
```python
from appium.webdriver.common.appiumby import AppiumBy
from citronella import Ui, PlaceholderPage
from Pages.component.HeaderMenu import HeaderMenu
class HomePage(HeaderMenu):
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):
from Pages.SearchPage import SearchPage
return Ui(AppiumBy.ID, 'search-button', SearchPage)
def link_to_somewhere_currently_dont_have_page_object(self):
return Ui(AppiumBy.ACCESSIBILITY_ID, 'search-button', PlaceholderPage)
```
___
## 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 | None | None | return selenium `webdriver` object |
| locate | by, value | None | similar as`driver.get_element` args |
| page_object | Page Object | get_start `bool` | Page Object must contain `ACTIVITY` variable with URL(selenium)/State(appium) if using Kwargs** |
| page | None | None | |
| back | None | None | |
| webdriver_wait | number(sec) | None | |
| ready_state | number(sec) | None | execute javascript `document.readyState` manually, default timeout is `0` |
| get_window_size | None | None | |
| sleep | number(sec) | None | |
### citronella.ui / citronella.WebUi
###### Args:
- by
- value
- page_object (optional)
###### Method Lists:
| Method Name | Args* | Kwargs** | Note |
| ------------- |:------:|:------------------:|:----:|
| send_keys | text | clear `bool`, return_key `bool` | default value is `False` by default |
| click | None | switch_page `bool` | see [test_auth.py](example/selenium/Test/pytest_html_image/test_auth.py) example |
| get_element | None | None | |
| get_elements | None | None | |
| ec_element_to_be_clickable | None | None | wrapper of `EC` / `excpected_condition` |
| ec_presence_of_element_located | None | None | wrapper of `EC` / `excpected_condition` |
| ec_presence_of_all_elements_located | None | None | wrapper of `EC` / `excpected_condition` |
| ec_visibility_of_element_located | None | None | wrapper of `EC` / `excpected_condition` |
| ec_visibility_of_all_elements_located | None | None | wrapper of `EC` / `excpected_condition` |
| ec_visibility_of_any_elements_located | None | None | wrapper of `EC` / `excpected_condition` |
| ec_invisibility_of_element_located | None | None | wrapper of `EC` / `excpected_condition` |
| ec_element_located_to_be_selected | None | None | wrapper of `EC` / `excpected_condition` |
## Testing powered by
<a target="_blank" href="https://www.browserstack.com/"><img width="200" src="https://www.browserstack.com/images/layout/browserstack-logo-600x315.png"></a><br>
[BrowserStack Open-Source Program](https://www.browserstack.com/open-source)