@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=I-defect%2Cneeds-triaging&projects=&template=bug-report.yml&title=%5B%F0%9F%90%9B+Bug%5D%3A+");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();assertTrue("Not on the issue entry page: "+url,url.endsWith("/new"));}
packagecom.example.webdriver;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;import staticjunit.framework.Assert.assertTrue;publicclassEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;// By default the PageFactory will locate elements with the same name or id// as the field. Since the issue_title element has an id attribute of "issue_title"// we don't need any additional annotations.privateWebElementissue_title;// But we'd prefer a different name in our code than "issue_body", so we use the// FindBy annotation to tell the PageFactory how to locate the element.@FindBy(id="issue_body")privateWebElementbody;publicEditIssue(WebDriverdriver){this.driver=driver;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=I-defect%2Cneeds-triaging&projects=&template=bug-report.yml&title=%5B%F0%9F%90%9B+Bug%5D%3A+");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();assertTrue("Not on the issue entry page: "+url,url.endsWith("/new"));}publicvoidsetHowToReproduce(StringhowToReproduce){WebElementfield=driver.findElement(By.id("issue_form_repro-command"));clearAndType(field,howToReproduce);}publicvoidsetLogOutput(StringlogOutput){WebElementfield=driver.findElement(By.id("issue_form_logs"));clearAndType(field,logOutput);}publicvoidsetOperatingSystem(StringoperatingSystem){WebElementfield=driver.findElement(By.id("issue_form_operating-system"));clearAndType(field,operatingSystem);}publicvoidsetSeleniumVersion(StringseleniumVersion){WebElementfield=driver.findElement(By.id("issue_form_selenium-version"));clearAndType(field,logOutput);}publicvoidsetBrowserVersion(StringbrowserVersion){WebElementfield=driver.findElement(By.id("issue_form_browser-versions"));clearAndType(field,browserVersion);}publicvoidsetDriverVersion(StringdriverVersion){WebElementfield=driver.findElement(By.id("issue_form_browser-driver-versions"));clearAndType(field,driverVersion);}publicvoidsetUsingGrid(StringusingGrid){WebElementfield=driver.findElement(By.id("issue_form_selenium-grid-version"));clearAndType(field,usingGrid);}publicIssueListsubmit(){driver.findElement(By.cssSelector("button[type='submit']")).click();returnnewIssueList(driver);}privatevoidclearAndType(WebElementfield,Stringtext){field.clear();field.sendKeys(text);}}
packagecom.example.webdriver;importorg.openqa.selenium.By;importorg.openqa.selenium.NoSuchElementException;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;import staticorg.junit.Assert.fail;publicclassSecuredPageextendsLoadableComponent<SecuredPage>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;privatefinalStringusername;privatefinalStringpassword;publicSecuredPage(WebDriverdriver,LoadableComponent<?>parent,Stringusername,Stringpassword){this.driver=driver;this.parent=parent;this.username=username;this.password=password;}@Overrideprotectedvoidload(){parent.get();StringoriginalUrl=driver.getCurrentUrl();// Sign indriver.get("https://www.google.com/accounts/ServiceLogin?service=code");driver.findElement(By.name("Email")).sendKeys(username);WebElementpasswordField=driver.findElement(By.name("Passwd"));passwordField.sendKeys(password);passwordField.submit();// Now return to the original URLdriver.get(originalUrl);}@OverrideprotectedvoidisLoaded()throwsError{// If you're signed in, you have the option of picking a different login.// Let's check for the presence of that.try{WebElementdiv=driver.findElement(By.id("multilogin-dropdown"));}catch(NoSuchElementExceptione){fail("Cannot locate user name link");}}}
publicclassActionBot{privatefinalWebDriverdriver;publicActionBot(WebDriverdriver){this.driver=driver;}publicvoidclick(Bylocator){driver.findElement(locator).click();}publicvoidsubmit(Bylocator){driver.findElement(locator).submit();}/**
* Type something into an input field. WebDriver doesn't normally clear these
* before typing, so this method does that first. It also sends a return key
* to move the focus out of the element.
*/publicvoidtype(Bylocator,Stringtext){WebElementelement=driver.findElement(locator);element.clear();element.sendKeys(text+"\n");}}
"""
An example of `python + pytest + selenium`
which implemented "**Action Bot**, **Loadable Component** and **Page Object**".
"""importpytestfromseleniumimportwebdriverfromselenium.commonimport(ElementNotInteractableException,NoSuchElementException,StaleElementReferenceException,)fromselenium.webdriverimportActionChainsfromselenium.webdriver.common.byimportByfromselenium.webdriver.remote.webelementimportWebElementfromselenium.webdriver.supportimportexpected_conditionsasECfromselenium.webdriver.support.uiimportWebDriverWait@pytest.fixture(scope="function")defchrome_driver():withwebdriver.Chrome()asdriver:driver.set_window_size(1024,768)driver.implicitly_wait(0.5)yielddriverclassActionBot:def__init__(self,driver)->None:self.driver=driverself.wait=WebDriverWait(driver,timeout=10,poll_frequency=2,ignored_exceptions=[NoSuchElementException,StaleElementReferenceException,ElementNotInteractableException,],)defelement(self,locator:tuple)->WebElement:self.wait.until(lambdadriver:driver.find_element(*locator))returnself.driver.find_element(*locator)defelements(self,locator:tuple)->list[WebElement]:returnself.driver.find_elements(*locator)defhover(self,locator:tuple)->None:element=self.element(locator)ActionChains(self.driver).move_to_element(element).perform()defclick(self,locator:tuple)->None:element=self.element(locator)element.click()deftype(self,locator:tuple,value:str)->None:element=self.element(locator)element.clear()element.send_keys(value)deftext(self,locator:tuple)->str:element=self.element(locator)returnelement.textclassLoadableComponent:defload(self):raiseNotImplementedError("Subclasses must implement this method")defis_loaded(self):raiseNotImplementedError("Subclasses must implement this method")defget(self):ifnotself.is_loaded():self.load()ifnotself.is_loaded():raiseException("Page not loaded properly.")returnselfclassTodoPage(LoadableComponent):url="https://todomvc.com/examples/react/dist/"new_todo_by=(By.CSS_SELECTOR,"input.new-todo")count_todo_left_by=(By.CSS_SELECTOR,"span.todo-count")todo_items_by=(By.CSS_SELECTOR,"ul.todo-list>li")view_all_by=(By.LINK_TEXT,"All")view_active_by=(By.LINK_TEXT,"Active")view_completed_by=(By.LINK_TEXT,"Completed")toggle_all_by=(By.CSS_SELECTOR,"input.toggle-all")clear_completed_by=(By.CSS_SELECTOR,"button.clear-completed")@staticmethoddefbuild_todo_by(s:str)->tuple:p=f"//li[.//label[contains(text(), '{s}')]]"returnBy.XPATH,p@staticmethoddefbuild_todo_item_label_by(s:str)->tuple:p=f"//label[contains(text(), '{s}')]"returnBy.XPATH,p@staticmethoddefbuild_todo_item_toggle_by(s:str)->tuple:by,using=TodoPage.build_todo_item_label_by(s)p=f"{using}/../input[@class='toggle']"returnby,p@staticmethoddefbuild_todo_item_delete_by(s:str)->tuple:by,using=TodoPage.build_todo_item_label_by(s)p=f"{using}/../button[@class='destroy']"returnby,pdefbuild_count_todo_left(self,count:int)->str:ifcount==1:return"1 item left!"else:returnf"{count} items left!"def__init__(self,driver):self.driver=driverself.bot=ActionBot(driver)defload(self):self.driver.get(self.url)defis_loaded(self):try:WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(self.new_todo_by))returnTrueexcept:returnFalse# business domain belowdefcount_todo_items_left(self)->str:returnself.bot.text(self.count_todo_left_by)deftodo_count(self)->int:returnlen(self.bot.elements(self.todo_items_by))defnew_todo(self,s:str):self.bot.type(self.new_todo_by,s+"\n")deftoggle_todo(self,s:str):self.bot.click(self.build_todo_item_toggle_by(s))defhover_todo(self,s:str)->None:self.bot.hover(self.build_todo_by(s))defdelete_todo(self,s:str):self.hover_todo(s)self.bot.click(self.build_todo_item_delete_by(s))defclear_completed_todo(self):self.bot.click(self.clear_completed_by)deftoggle_all_todo(self):self.bot.click(self.toggle_all_by)defview_all_todo(self):self.bot.click(self.view_all_by)defview_active_todo(self):self.bot.click(self.view_active_by)defview_completed_todo(self):self.bot.click(self.view_completed_by)@pytest.fixturedefpage(chrome_driver)->TodoPage:driver=chrome_driverreturnTodoPage(driver).get()classTestTodoPage:deftest_new_todo(self,page:TodoPage):assertpage.todo_count()==0page.new_todo("aaa")assertpage.count_todo_items_left()==page.build_count_todo_left(1)deftest_todo_toggle(self,page:TodoPage):s="aaa"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(1)page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(0)page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(1)deftest_todo_delete(self,page:TodoPage):s1="aaa"s2="bbb"page.new_todo(s1)page.new_todo(s2)assertpage.count_todo_items_left()==page.build_count_todo_left(2)page.delete_todo(s1)assertpage.count_todo_items_left()==page.build_count_todo_left(1)page.delete_todo(s2)assertpage.todo_count()==0deftest_new_100_todo(self,page:TodoPage):foriinrange(100):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(100)deftest_toggle_all_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10page.toggle_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(0)assertpage.todo_count()==10page.toggle_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10deftest_clear_completed_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10foriinrange(5):s=f"ToDo{i}"page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(5)assertpage.todo_count()==10page.clear_completed_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(5)assertpage.todo_count()==5deftest_view_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)foriinrange(4):s=f"ToDo{i}"page.toggle_todo(s)page.view_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==10page.view_active_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==6page.view_completed_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==4
"""
An example of `python + pytest + selenium`
which implemented "**Action Bot**, **Loadable Component** and **Page Object**".
"""importpytestfromseleniumimportwebdriverfromselenium.commonimport(ElementNotInteractableException,NoSuchElementException,StaleElementReferenceException,)fromselenium.webdriverimportActionChainsfromselenium.webdriver.common.byimportByfromselenium.webdriver.remote.webelementimportWebElementfromselenium.webdriver.supportimportexpected_conditionsasECfromselenium.webdriver.support.uiimportWebDriverWait@pytest.fixture(scope="function")defchrome_driver():withwebdriver.Chrome()asdriver:driver.set_window_size(1024,768)driver.implicitly_wait(0.5)yielddriverclassActionBot:def__init__(self,driver)->None:self.driver=driverself.wait=WebDriverWait(driver,timeout=10,poll_frequency=2,ignored_exceptions=[NoSuchElementException,StaleElementReferenceException,ElementNotInteractableException,],)defelement(self,locator:tuple)->WebElement:self.wait.until(lambdadriver:driver.find_element(*locator))returnself.driver.find_element(*locator)defelements(self,locator:tuple)->list[WebElement]:returnself.driver.find_elements(*locator)defhover(self,locator:tuple)->None:element=self.element(locator)ActionChains(self.driver).move_to_element(element).perform()defclick(self,locator:tuple)->None:element=self.element(locator)element.click()deftype(self,locator:tuple,value:str)->None:element=self.element(locator)element.clear()element.send_keys(value)deftext(self,locator:tuple)->str:element=self.element(locator)returnelement.textclassLoadableComponent:defload(self):raiseNotImplementedError("Subclasses must implement this method")defis_loaded(self):raiseNotImplementedError("Subclasses must implement this method")defget(self):ifnotself.is_loaded():self.load()ifnotself.is_loaded():raiseException("Page not loaded properly.")returnselfclassTodoPage(LoadableComponent):url="https://todomvc.com/examples/react/dist/"new_todo_by=(By.CSS_SELECTOR,"input.new-todo")count_todo_left_by=(By.CSS_SELECTOR,"span.todo-count")todo_items_by=(By.CSS_SELECTOR,"ul.todo-list>li")view_all_by=(By.LINK_TEXT,"All")view_active_by=(By.LINK_TEXT,"Active")view_completed_by=(By.LINK_TEXT,"Completed")toggle_all_by=(By.CSS_SELECTOR,"input.toggle-all")clear_completed_by=(By.CSS_SELECTOR,"button.clear-completed")@staticmethoddefbuild_todo_by(s:str)->tuple:p=f"//li[.//label[contains(text(), '{s}')]]"returnBy.XPATH,p@staticmethoddefbuild_todo_item_label_by(s:str)->tuple:p=f"//label[contains(text(), '{s}')]"returnBy.XPATH,p@staticmethoddefbuild_todo_item_toggle_by(s:str)->tuple:by,using=TodoPage.build_todo_item_label_by(s)p=f"{using}/../input[@class='toggle']"returnby,p@staticmethoddefbuild_todo_item_delete_by(s:str)->tuple:by,using=TodoPage.build_todo_item_label_by(s)p=f"{using}/../button[@class='destroy']"returnby,pdefbuild_count_todo_left(self,count:int)->str:ifcount==1:return"1 item left!"else:returnf"{count} items left!"def__init__(self,driver):self.driver=driverself.bot=ActionBot(driver)defload(self):self.driver.get(self.url)defis_loaded(self):try:WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(self.new_todo_by))returnTrueexcept:returnFalse# business domain belowdefcount_todo_items_left(self)->str:returnself.bot.text(self.count_todo_left_by)deftodo_count(self)->int:returnlen(self.bot.elements(self.todo_items_by))defnew_todo(self,s:str):self.bot.type(self.new_todo_by,s+"\n")deftoggle_todo(self,s:str):self.bot.click(self.build_todo_item_toggle_by(s))defhover_todo(self,s:str)->None:self.bot.hover(self.build_todo_by(s))defdelete_todo(self,s:str):self.hover_todo(s)self.bot.click(self.build_todo_item_delete_by(s))defclear_completed_todo(self):self.bot.click(self.clear_completed_by)deftoggle_all_todo(self):self.bot.click(self.toggle_all_by)defview_all_todo(self):self.bot.click(self.view_all_by)defview_active_todo(self):self.bot.click(self.view_active_by)defview_completed_todo(self):self.bot.click(self.view_completed_by)@pytest.fixturedefpage(chrome_driver)->TodoPage:driver=chrome_driverreturnTodoPage(driver).get()classTestTodoPage:deftest_new_todo(self,page:TodoPage):assertpage.todo_count()==0page.new_todo("aaa")assertpage.count_todo_items_left()==page.build_count_todo_left(1)deftest_todo_toggle(self,page:TodoPage):s="aaa"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(1)page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(0)page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(1)deftest_todo_delete(self,page:TodoPage):s1="aaa"s2="bbb"page.new_todo(s1)page.new_todo(s2)assertpage.count_todo_items_left()==page.build_count_todo_left(2)page.delete_todo(s1)assertpage.count_todo_items_left()==page.build_count_todo_left(1)page.delete_todo(s2)assertpage.todo_count()==0deftest_new_100_todo(self,page:TodoPage):foriinrange(100):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(100)deftest_toggle_all_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10page.toggle_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(0)assertpage.todo_count()==10page.toggle_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10deftest_clear_completed_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10foriinrange(5):s=f"ToDo{i}"page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(5)assertpage.todo_count()==10page.clear_completed_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(5)assertpage.todo_count()==5deftest_view_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)foriinrange(4):s=f"ToDo{i}"page.toggle_todo(s)page.view_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==10page.view_active_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==6page.view_completed_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==4
classLoadableComponent:defload(self):raiseNotImplementedError("Subclasses must implement this method")defis_loaded(self):raiseNotImplementedError("Subclasses must implement this method")defget(self):ifnotself.is_loaded():self.load()ifnotself.is_loaded():raiseException("Page not loaded properly.")returnself
"""
An example of `python + pytest + selenium`
which implemented "**Action Bot**, **Loadable Component** and **Page Object**".
"""importpytestfromseleniumimportwebdriverfromselenium.commonimport(ElementNotInteractableException,NoSuchElementException,StaleElementReferenceException,)fromselenium.webdriverimportActionChainsfromselenium.webdriver.common.byimportByfromselenium.webdriver.remote.webelementimportWebElementfromselenium.webdriver.supportimportexpected_conditionsasECfromselenium.webdriver.support.uiimportWebDriverWait@pytest.fixture(scope="function")defchrome_driver():withwebdriver.Chrome()asdriver:driver.set_window_size(1024,768)driver.implicitly_wait(0.5)yielddriverclassActionBot:def__init__(self,driver)->None:self.driver=driverself.wait=WebDriverWait(driver,timeout=10,poll_frequency=2,ignored_exceptions=[NoSuchElementException,StaleElementReferenceException,ElementNotInteractableException,],)defelement(self,locator:tuple)->WebElement:self.wait.until(lambdadriver:driver.find_element(*locator))returnself.driver.find_element(*locator)defelements(self,locator:tuple)->list[WebElement]:returnself.driver.find_elements(*locator)defhover(self,locator:tuple)->None:element=self.element(locator)ActionChains(self.driver).move_to_element(element).perform()defclick(self,locator:tuple)->None:element=self.element(locator)element.click()deftype(self,locator:tuple,value:str)->None:element=self.element(locator)element.clear()element.send_keys(value)deftext(self,locator:tuple)->str:element=self.element(locator)returnelement.textclassLoadableComponent:defload(self):raiseNotImplementedError("Subclasses must implement this method")defis_loaded(self):raiseNotImplementedError("Subclasses must implement this method")defget(self):ifnotself.is_loaded():self.load()ifnotself.is_loaded():raiseException("Page not loaded properly.")returnselfclassTodoPage(LoadableComponent):url="https://todomvc.com/examples/react/dist/"new_todo_by=(By.CSS_SELECTOR,"input.new-todo")count_todo_left_by=(By.CSS_SELECTOR,"span.todo-count")todo_items_by=(By.CSS_SELECTOR,"ul.todo-list>li")view_all_by=(By.LINK_TEXT,"All")view_active_by=(By.LINK_TEXT,"Active")view_completed_by=(By.LINK_TEXT,"Completed")toggle_all_by=(By.CSS_SELECTOR,"input.toggle-all")clear_completed_by=(By.CSS_SELECTOR,"button.clear-completed")@staticmethoddefbuild_todo_by(s:str)->tuple:p=f"//li[.//label[contains(text(), '{s}')]]"returnBy.XPATH,p@staticmethoddefbuild_todo_item_label_by(s:str)->tuple:p=f"//label[contains(text(), '{s}')]"returnBy.XPATH,p@staticmethoddefbuild_todo_item_toggle_by(s:str)->tuple:by,using=TodoPage.build_todo_item_label_by(s)p=f"{using}/../input[@class='toggle']"returnby,p@staticmethoddefbuild_todo_item_delete_by(s:str)->tuple:by,using=TodoPage.build_todo_item_label_by(s)p=f"{using}/../button[@class='destroy']"returnby,pdefbuild_count_todo_left(self,count:int)->str:ifcount==1:return"1 item left!"else:returnf"{count} items left!"def__init__(self,driver):self.driver=driverself.bot=ActionBot(driver)defload(self):self.driver.get(self.url)defis_loaded(self):try:WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(self.new_todo_by))returnTrueexcept:returnFalse# business domain belowdefcount_todo_items_left(self)->str:returnself.bot.text(self.count_todo_left_by)deftodo_count(self)->int:returnlen(self.bot.elements(self.todo_items_by))defnew_todo(self,s:str):self.bot.type(self.new_todo_by,s+"\n")deftoggle_todo(self,s:str):self.bot.click(self.build_todo_item_toggle_by(s))defhover_todo(self,s:str)->None:self.bot.hover(self.build_todo_by(s))defdelete_todo(self,s:str):self.hover_todo(s)self.bot.click(self.build_todo_item_delete_by(s))defclear_completed_todo(self):self.bot.click(self.clear_completed_by)deftoggle_all_todo(self):self.bot.click(self.toggle_all_by)defview_all_todo(self):self.bot.click(self.view_all_by)defview_active_todo(self):self.bot.click(self.view_active_by)defview_completed_todo(self):self.bot.click(self.view_completed_by)@pytest.fixturedefpage(chrome_driver)->TodoPage:driver=chrome_driverreturnTodoPage(driver).get()classTestTodoPage:deftest_new_todo(self,page:TodoPage):assertpage.todo_count()==0page.new_todo("aaa")assertpage.count_todo_items_left()==page.build_count_todo_left(1)deftest_todo_toggle(self,page:TodoPage):s="aaa"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(1)page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(0)page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(1)deftest_todo_delete(self,page:TodoPage):s1="aaa"s2="bbb"page.new_todo(s1)page.new_todo(s2)assertpage.count_todo_items_left()==page.build_count_todo_left(2)page.delete_todo(s1)assertpage.count_todo_items_left()==page.build_count_todo_left(1)page.delete_todo(s2)assertpage.todo_count()==0deftest_new_100_todo(self,page:TodoPage):foriinrange(100):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(100)deftest_toggle_all_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10page.toggle_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(0)assertpage.todo_count()==10page.toggle_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10deftest_clear_completed_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10foriinrange(5):s=f"ToDo{i}"page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(5)assertpage.todo_count()==10page.clear_completed_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(5)assertpage.todo_count()==5deftest_view_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)foriinrange(4):s=f"ToDo{i}"page.toggle_todo(s)page.view_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==10page.view_active_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==6page.view_completed_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==4
"""
An example of `python + pytest + selenium`
which implemented "**Action Bot**, **Loadable Component** and **Page Object**".
"""importpytestfromseleniumimportwebdriverfromselenium.commonimport(ElementNotInteractableException,NoSuchElementException,StaleElementReferenceException,)fromselenium.webdriverimportActionChainsfromselenium.webdriver.common.byimportByfromselenium.webdriver.remote.webelementimportWebElementfromselenium.webdriver.supportimportexpected_conditionsasECfromselenium.webdriver.support.uiimportWebDriverWait@pytest.fixture(scope="function")defchrome_driver():withwebdriver.Chrome()asdriver:driver.set_window_size(1024,768)driver.implicitly_wait(0.5)yielddriverclassActionBot:def__init__(self,driver)->None:self.driver=driverself.wait=WebDriverWait(driver,timeout=10,poll_frequency=2,ignored_exceptions=[NoSuchElementException,StaleElementReferenceException,ElementNotInteractableException,],)defelement(self,locator:tuple)->WebElement:self.wait.until(lambdadriver:driver.find_element(*locator))returnself.driver.find_element(*locator)defelements(self,locator:tuple)->list[WebElement]:returnself.driver.find_elements(*locator)defhover(self,locator:tuple)->None:element=self.element(locator)ActionChains(self.driver).move_to_element(element).perform()defclick(self,locator:tuple)->None:element=self.element(locator)element.click()deftype(self,locator:tuple,value:str)->None:element=self.element(locator)element.clear()element.send_keys(value)deftext(self,locator:tuple)->str:element=self.element(locator)returnelement.textclassLoadableComponent:defload(self):raiseNotImplementedError("Subclasses must implement this method")defis_loaded(self):raiseNotImplementedError("Subclasses must implement this method")defget(self):ifnotself.is_loaded():self.load()ifnotself.is_loaded():raiseException("Page not loaded properly.")returnselfclassTodoPage(LoadableComponent):url="https://todomvc.com/examples/react/dist/"new_todo_by=(By.CSS_SELECTOR,"input.new-todo")count_todo_left_by=(By.CSS_SELECTOR,"span.todo-count")todo_items_by=(By.CSS_SELECTOR,"ul.todo-list>li")view_all_by=(By.LINK_TEXT,"All")view_active_by=(By.LINK_TEXT,"Active")view_completed_by=(By.LINK_TEXT,"Completed")toggle_all_by=(By.CSS_SELECTOR,"input.toggle-all")clear_completed_by=(By.CSS_SELECTOR,"button.clear-completed")@staticmethoddefbuild_todo_by(s:str)->tuple:p=f"//li[.//label[contains(text(), '{s}')]]"returnBy.XPATH,p@staticmethoddefbuild_todo_item_label_by(s:str)->tuple:p=f"//label[contains(text(), '{s}')]"returnBy.XPATH,p@staticmethoddefbuild_todo_item_toggle_by(s:str)->tuple:by,using=TodoPage.build_todo_item_label_by(s)p=f"{using}/../input[@class='toggle']"returnby,p@staticmethoddefbuild_todo_item_delete_by(s:str)->tuple:by,using=TodoPage.build_todo_item_label_by(s)p=f"{using}/../button[@class='destroy']"returnby,pdefbuild_count_todo_left(self,count:int)->str:ifcount==1:return"1 item left!"else:returnf"{count} items left!"def__init__(self,driver):self.driver=driverself.bot=ActionBot(driver)defload(self):self.driver.get(self.url)defis_loaded(self):try:WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(self.new_todo_by))returnTrueexcept:returnFalse# business domain belowdefcount_todo_items_left(self)->str:returnself.bot.text(self.count_todo_left_by)deftodo_count(self)->int:returnlen(self.bot.elements(self.todo_items_by))defnew_todo(self,s:str):self.bot.type(self.new_todo_by,s+"\n")deftoggle_todo(self,s:str):self.bot.click(self.build_todo_item_toggle_by(s))defhover_todo(self,s:str)->None:self.bot.hover(self.build_todo_by(s))defdelete_todo(self,s:str):self.hover_todo(s)self.bot.click(self.build_todo_item_delete_by(s))defclear_completed_todo(self):self.bot.click(self.clear_completed_by)deftoggle_all_todo(self):self.bot.click(self.toggle_all_by)defview_all_todo(self):self.bot.click(self.view_all_by)defview_active_todo(self):self.bot.click(self.view_active_by)defview_completed_todo(self):self.bot.click(self.view_completed_by)@pytest.fixturedefpage(chrome_driver)->TodoPage:driver=chrome_driverreturnTodoPage(driver).get()classTestTodoPage:deftest_new_todo(self,page:TodoPage):assertpage.todo_count()==0page.new_todo("aaa")assertpage.count_todo_items_left()==page.build_count_todo_left(1)deftest_todo_toggle(self,page:TodoPage):s="aaa"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(1)page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(0)page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(1)deftest_todo_delete(self,page:TodoPage):s1="aaa"s2="bbb"page.new_todo(s1)page.new_todo(s2)assertpage.count_todo_items_left()==page.build_count_todo_left(2)page.delete_todo(s1)assertpage.count_todo_items_left()==page.build_count_todo_left(1)page.delete_todo(s2)assertpage.todo_count()==0deftest_new_100_todo(self,page:TodoPage):foriinrange(100):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(100)deftest_toggle_all_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10page.toggle_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(0)assertpage.todo_count()==10page.toggle_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10deftest_clear_completed_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10foriinrange(5):s=f"ToDo{i}"page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(5)assertpage.todo_count()==10page.clear_completed_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(5)assertpage.todo_count()==5deftest_view_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)foriinrange(4):s=f"ToDo{i}"page.toggle_todo(s)page.view_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==10page.view_active_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==6page.view_completed_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==4
"""
An example of `python + pytest + selenium`
which implemented "**Action Bot**, **Loadable Component** and **Page Object**".
"""importpytestfromseleniumimportwebdriverfromselenium.commonimport(ElementNotInteractableException,NoSuchElementException,StaleElementReferenceException,)fromselenium.webdriverimportActionChainsfromselenium.webdriver.common.byimportByfromselenium.webdriver.remote.webelementimportWebElementfromselenium.webdriver.supportimportexpected_conditionsasECfromselenium.webdriver.support.uiimportWebDriverWait@pytest.fixture(scope="function")defchrome_driver():withwebdriver.Chrome()asdriver:driver.set_window_size(1024,768)driver.implicitly_wait(0.5)yielddriverclassActionBot:def__init__(self,driver)->None:self.driver=driverself.wait=WebDriverWait(driver,timeout=10,poll_frequency=2,ignored_exceptions=[NoSuchElementException,StaleElementReferenceException,ElementNotInteractableException,],)defelement(self,locator:tuple)->WebElement:self.wait.until(lambdadriver:driver.find_element(*locator))returnself.driver.find_element(*locator)defelements(self,locator:tuple)->list[WebElement]:returnself.driver.find_elements(*locator)defhover(self,locator:tuple)->None:element=self.element(locator)ActionChains(self.driver).move_to_element(element).perform()defclick(self,locator:tuple)->None:element=self.element(locator)element.click()deftype(self,locator:tuple,value:str)->None:element=self.element(locator)element.clear()element.send_keys(value)deftext(self,locator:tuple)->str:element=self.element(locator)returnelement.textclassLoadableComponent:defload(self):raiseNotImplementedError("Subclasses must implement this method")defis_loaded(self):raiseNotImplementedError("Subclasses must implement this method")defget(self):ifnotself.is_loaded():self.load()ifnotself.is_loaded():raiseException("Page not loaded properly.")returnselfclassTodoPage(LoadableComponent):url="https://todomvc.com/examples/react/dist/"new_todo_by=(By.CSS_SELECTOR,"input.new-todo")count_todo_left_by=(By.CSS_SELECTOR,"span.todo-count")todo_items_by=(By.CSS_SELECTOR,"ul.todo-list>li")view_all_by=(By.LINK_TEXT,"All")view_active_by=(By.LINK_TEXT,"Active")view_completed_by=(By.LINK_TEXT,"Completed")toggle_all_by=(By.CSS_SELECTOR,"input.toggle-all")clear_completed_by=(By.CSS_SELECTOR,"button.clear-completed")@staticmethoddefbuild_todo_by(s:str)->tuple:p=f"//li[.//label[contains(text(), '{s}')]]"returnBy.XPATH,p@staticmethoddefbuild_todo_item_label_by(s:str)->tuple:p=f"//label[contains(text(), '{s}')]"returnBy.XPATH,p@staticmethoddefbuild_todo_item_toggle_by(s:str)->tuple:by,using=TodoPage.build_todo_item_label_by(s)p=f"{using}/../input[@class='toggle']"returnby,p@staticmethoddefbuild_todo_item_delete_by(s:str)->tuple:by,using=TodoPage.build_todo_item_label_by(s)p=f"{using}/../button[@class='destroy']"returnby,pdefbuild_count_todo_left(self,count:int)->str:ifcount==1:return"1 item left!"else:returnf"{count} items left!"def__init__(self,driver):self.driver=driverself.bot=ActionBot(driver)defload(self):self.driver.get(self.url)defis_loaded(self):try:WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(self.new_todo_by))returnTrueexcept:returnFalse# business domain belowdefcount_todo_items_left(self)->str:returnself.bot.text(self.count_todo_left_by)deftodo_count(self)->int:returnlen(self.bot.elements(self.todo_items_by))defnew_todo(self,s:str):self.bot.type(self.new_todo_by,s+"\n")deftoggle_todo(self,s:str):self.bot.click(self.build_todo_item_toggle_by(s))defhover_todo(self,s:str)->None:self.bot.hover(self.build_todo_by(s))defdelete_todo(self,s:str):self.hover_todo(s)self.bot.click(self.build_todo_item_delete_by(s))defclear_completed_todo(self):self.bot.click(self.clear_completed_by)deftoggle_all_todo(self):self.bot.click(self.toggle_all_by)defview_all_todo(self):self.bot.click(self.view_all_by)defview_active_todo(self):self.bot.click(self.view_active_by)defview_completed_todo(self):self.bot.click(self.view_completed_by)@pytest.fixturedefpage(chrome_driver)->TodoPage:driver=chrome_driverreturnTodoPage(driver).get()classTestTodoPage:deftest_new_todo(self,page:TodoPage):assertpage.todo_count()==0page.new_todo("aaa")assertpage.count_todo_items_left()==page.build_count_todo_left(1)deftest_todo_toggle(self,page:TodoPage):s="aaa"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(1)page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(0)page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(1)deftest_todo_delete(self,page:TodoPage):s1="aaa"s2="bbb"page.new_todo(s1)page.new_todo(s2)assertpage.count_todo_items_left()==page.build_count_todo_left(2)page.delete_todo(s1)assertpage.count_todo_items_left()==page.build_count_todo_left(1)page.delete_todo(s2)assertpage.todo_count()==0deftest_new_100_todo(self,page:TodoPage):foriinrange(100):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(100)deftest_toggle_all_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10page.toggle_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(0)assertpage.todo_count()==10page.toggle_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10deftest_clear_completed_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(10)assertpage.todo_count()==10foriinrange(5):s=f"ToDo{i}"page.toggle_todo(s)assertpage.count_todo_items_left()==page.build_count_todo_left(5)assertpage.todo_count()==10page.clear_completed_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(5)assertpage.todo_count()==5deftest_view_todo(self,page:TodoPage):foriinrange(10):s=f"ToDo{i}"page.new_todo(s)foriinrange(4):s=f"ToDo{i}"page.toggle_todo(s)page.view_all_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==10page.view_active_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==6page.view_completed_todo()assertpage.count_todo_items_left()==page.build_count_todo_left(6)assertpage.todo_count()==4