Package: citronella
Citronellawebdriver extension with a page object wrapper.Example TestsSeleniumimportpytestfromPages.contents_pageimportContentsPageclassTestNavigationMenu:deftest_help_page(self,web):web.driver.get('https://pypi.org/')web.page=ContentsPageweb.page.home_page.help_button.click()assert'Help'inweb.driver.titledeftest_sponsors_page(self,web):web.page.help_page.sponsors_button.click()assert'Sponsors'inweb.driver.titledeftest_login_page(self,web):web.page.sponsors_page.login_button.click()assert'Log'inweb.driver.titledeftest_register_page(self,web):web.page.login_page.register_button.click()assert'Create'inweb.driver.titleAppiumimportpytestfromPages.contents_pageimportContentsPageclassTestInput:deftest_input(self,web):web.page=ContentsPageweb.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.textforxinelements]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.fromseleniumimportwebdriverfromselenium.webdriver.common.byimportByfromcitronellaimportWebPagedriver=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"]')ifelements.ec_visibility_of_all_elements_located():results=elements.get_elements()text_lists=[x.textforxinresults]Install PackagepipinstallcitronellaDocumentationThere are only two modules import in this package:The first module is for conftest.py.SeleniumimportpytestfromseleniumimportwebdriverfromcitronellaimportWebPage@pytest.fixture(autouse=True,scope='class')defweb(request):driver=webdriver.Chrome()yieldWebPage(driver)driver.quit()Appiumimportpytestimportosfromappiumimportwebdriverfromappium.options.androidimportUiAutomator2OptionsfromcitronellaimportWebPage@pytest.fixture(autouse='true',scope='class')defweb(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)yieldWebPage(driver)driver.quit()The second module are for the page object model.Seleniumfromselenium.webdriver.common.byimportByfromcitronellaimportuifromPages.componentsimportHeaderclassHomePage(Header):defsome_button(self):returnui(By.XPATH,'//a[@name="foo"]')defsearch_input(self):returnui(By.ID,'search')defsearch_button(self):returnui(By.NAME,'search-button')Appiumfromappium.webdriver.common.appiumbyimportAppiumByfromcitronellaimportuifromPages.componentsimportHeaderclassHomePage(Header):defsome_button(self):returnui(AppiumBy.XPATH,'//a[@name="foo"]')defsearch_input(self):returnui(AppiumBy.ACCESSIBILITY_ID,'search')defsearch_button(self):returnui(AppiumBy.ID,'search-button')Page Object Design / StrategyThere's a two ways to create a page object forWebPage:Straightforward approach: This method requires importing the page object for each test.fromseleniumimportwebdriverfromselenium.webdriver.common.byimportByfromcitronellaimportWebPage,uiclassHomePage:defauth_buton(self):returnui(By.XPATH,'//a[@name="foo"]')classLoginPage:defemail_input(self):returnui(By.ID,'email')defpassword_input(self):returnui(By.ID,'password')deflogin_buton(self):returnui(By.ID,'login')driver=webdriver.Chrome()web=WebPage(driver)web.driver.get('https://foobarbaz.com/')web.page=HomePageweb.page.auth_button.click()web.page=LoginPageweb.page.email_input.send_keys('foo')web.page.password_input.send_keys('bar')web.page.login_button.click()Lazy loading approach: This method is slightly more complex but offers the benefit of lazy loading.
seeContentsPage exampleor thisPage object examplefromseleniumimportwebdriverfromselenium.webdriver.common.byimportByfromcitronellaimportWebPage,uiclassContentsPage:defhome_page(self):returnHomePagedeflogin_page(self):returnLoginPageclassHomePage:defauth_buton(self):returnui(By.XPATH,'//a[@name="foo"]')classLoginPage:defemail_input(self):returnui(By.ID,'email')defpassword_input(self):returnui(By.ID,'password')deflogin_buton(self):returnui(By.ID,'login')driver=webdriver.Chrome()web=WebPage(driver)web.driver.get('https://foobarbaz.com/')web.page=ContentsPageweb.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()Usagecitronella.WebPageArgs:driver / webdriverKwargs (optional):webdriver_waitnumber(seconds), default value is10loggerbool, default value isTrueMethod Lists:Method NameArgs*Kwargs**Notedriver--return seleniumwebdriverobjectlocateby, value-similar asdriver.get_elementas input & returncitronella.WebUiobjectpagepage object-setterpage--getterwebdriver_waitnumber(sec)-ready_statenumber(sec)-execute javascriptdocument.readyStatemanually, default timeout is30sleepnumber(sec)-citronella.ui / citronella.WebUiArgs:byvalueMethod Lists:Method NameArgs*Kwargs**Notesend_keystextclearbool, return_keyboolclick--get_element--get_elements--ec_element_to_be_clickable--wrapper ofEC/excpected_conditionec_presence_of_element_located--wrapper ofEC/excpected_conditionec_presence_of_all_elements_located--wrapper ofEC/excpected_conditionec_visibility_of_element_located--wrapper ofEC/excpected_conditionec_visibility_of_all_elements_located--wrapper ofEC/excpected_conditionec_visibility_of_any_elements_located--wrapper ofEC/excpected_conditionec_invisibility_of_element_located--wrapper ofEC/excpected_conditionec_element_located_to_be_selected--wrapper ofEC/excpected_conditionTesting powered byBrowserStack Open-Source Program