不管您如何回答这个问题,
解决方案是让它成为测试中“设置数据”部分的一部分 - 如果 Larry 公开了一个 API,
使您(或任何人)能够创建和更新用户帐户,
一定要用它来回答这个问题
请确保使用这个 API 来回答这个问题 — 如果可能的话,
您希望只有在您拥有一个用户之后才启动浏览器,您可以使用该用户的凭证进行登录。
如果每个工作流的每个测试都是从创建用户帐户开始的,那么每个测试的执行都会增加许多秒。
调用 API 并与数据库进行通信是快速、“无头”的操作,
不需要打开浏览器、导航到正确页面、点击并等待表单提交等昂贵的过程。
理想情况下,您可以在一行代码中处理这个设置阶段,这些代码将在任何浏览器启动之前执行:
// Create a user who has read-only permissions--they can configure a unicorn,// but they do not have payment information set up, nor do they have// administrative privileges. At the time the user is created, its email// address and password are randomly generated--you don't even need to// know them.Useruser=UserFactory.createCommonUser();//This method is defined elsewhere.// Log in as this user.// Logging in on this site takes you to your personal "My Account" page, so the// AccountPage object is returned by the loginAs method, allowing you to then// perform actions from the AccountPage.AccountPageaccountPage=loginAs(user.getEmail(),user.getPassword());
# Create a user who has read-only permissions--they can configure a unicorn,# but they do not have payment information set up, nor do they have# administrative privileges. At the time the user is created, its email# address and password are randomly generated--you don't even need to# know them.user=user_factory.create_common_user()#This method is defined elsewhere.# Log in as this user.# Logging in on this site takes you to your personal "My Account" page, so the# AccountPage object is returned by the loginAs method, allowing you to then# perform actions from the AccountPage.account_page=login_as(user.get_email(),user.get_password())
// Create a user who has read-only permissions--they can configure a unicorn,// but they do not have payment information set up, nor do they have// administrative privileges. At the time the user is created, its email// address and password are randomly generated--you don't even need to// know them.Useruser=UserFactory.CreateCommonUser();//This method is defined elsewhere.// Log in as this user.// Logging in on this site takes you to your personal "My Account" page, so the// AccountPage object is returned by the loginAs method, allowing you to then// perform actions from the AccountPage.AccountPageaccountPage=LoginAs(user.Email,user.Password);
# Create a user who has read-only permissions--they can configure a unicorn,# but they do not have payment information set up, nor do they have# administrative privileges. At the time the user is created, its email# address and password are randomly generated--you don't even need to# know them.user=UserFactory.create_common_user#This method is defined elsewhere.# Log in as this user.# Logging in on this site takes you to your personal "My Account" page, so the# AccountPage object is returned by the loginAs method, allowing you to then# perform actions from the AccountPage.account_page=login_as(user.email,user.password)
// Create a user who has read-only permissions--they can configure a unicorn,
// but they do not have payment information set up, nor do they have
// administrative privileges. At the time the user is created, its email
// address and password are randomly generated--you don't even need to
// know them.
varuser=userFactory.createCommonUser();//This method is defined elsewhere.
// Log in as this user.
// Logging in on this site takes you to your personal "My Account" page, so the
// AccountPage object is returned by the loginAs method, allowing you to then
// perform actions from the AccountPage.
varaccountPage=loginAs(user.email,user.password);
// Create a user who has read-only permissions--they can configure a unicorn,
// but they do not have payment information set up, nor do they have
// administrative privileges. At the time the user is created, its email
// address and password are randomly generated--you don't even need to
// know them.
valuser=UserFactory.createCommonUser()//This method is defined elsewhere.
// Log in as this user.
// Logging in on this site takes you to your personal "My Account" page, so the
// AccountPage object is returned by the loginAs method, allowing you to then
// perform actions from the AccountPage.
valaccountPage=loginAs(user.getEmail(),user.getPassword())
请注意,我们在该段落中没有讨论按钮,字段,下拉菜单,单选按钮或 Web 表单。
您的测试也不应该!
您希望像尝试解决问题的用户一样编写代码。
这是一种方法(从前面的例子继续):
// The Unicorn is a top-level Object--it has attributes, which are set here.// This only stores the values; it does not fill out any web forms or interact// with the browser in any way.Unicornsparkles=newUnicorn("Sparkles",UnicornColors.PURPLE,UnicornAccessories.SUNGLASSES,UnicornAdornments.STAR_TATTOOS);// Since we're already "on" the account page, we have to use it to get to the// actual place where you configure unicorns. Calling the "Add Unicorn" method// takes us there.AddUnicornPageaddUnicornPage=accountPage.addUnicorn();// Now that we're on the AddUnicornPage, we will pass the "sparkles" object to// its createUnicorn() method. This method will take Sparkles' attributes,// fill out the form, and click submit.UnicornConfirmationPageunicornConfirmationPage=addUnicornPage.createUnicorn(sparkles);
# The Unicorn is a top-level Object--it has attributes, which are set here.# This only stores the values; it does not fill out any web forms or interact# with the browser in any way.sparkles=Unicorn("Sparkles",UnicornColors.PURPLE,UnicornAccessories.SUNGLASSES,UnicornAdornments.STAR_TATTOOS)# Since we're already "on" the account page, we have to use it to get to the# actual place where you configure unicorns. Calling the "Add Unicorn" method# takes us there.add_unicorn_page=account_page.add_unicorn()# Now that we're on the AddUnicornPage, we will pass the "sparkles" object to# its createUnicorn() method. This method will take Sparkles' attributes,# fill out the form, and click submit.unicorn_confirmation_page=add_unicorn_page.create_unicorn(sparkles)
// The Unicorn is a top-level Object--it has attributes, which are set here. // This only stores the values; it does not fill out any web forms or interact// with the browser in any way.Unicornsparkles=newUnicorn("Sparkles",UnicornColors.Purple,UnicornAccessories.Sunglasses,UnicornAdornments.StarTattoos);// Since we are already "on" the account page, we have to use it to get to the// actual place where you configure unicorns. Calling the "Add Unicorn" method// takes us there.AddUnicornPageaddUnicornPage=accountPage.AddUnicorn();// Now that we're on the AddUnicornPage, we will pass the "sparkles" object to// its createUnicorn() method. This method will take Sparkles' attributes,// fill out the form, and click submit.UnicornConfirmationPageunicornConfirmationPage=addUnicornPage.CreateUnicorn(sparkles);
# The Unicorn is a top-level Object--it has attributes, which are set here.# This only stores the values; it does not fill out any web forms or interact# with the browser in any way.sparkles=Unicorn.new('Sparkles',UnicornColors.PURPLE,UnicornAccessories.SUNGLASSES,UnicornAdornments.STAR_TATTOOS)# Since we're already "on" the account page, we have to use it to get to the# actual place where you configure unicorns. Calling the "Add Unicorn" method# takes us there.add_unicorn_page=account_page.add_unicorn# Now that we're on the AddUnicornPage, we will pass the "sparkles" object to# its createUnicorn() method. This method will take Sparkles' attributes,# fill out the form, and click submit.unicorn_confirmation_page=add_unicorn_page.create_unicorn(sparkles)
// The Unicorn is a top-level Object--it has attributes, which are set here.
// This only stores the values; it does not fill out any web forms or interact
// with the browser in any way.
varsparkles=newUnicorn("Sparkles",UnicornColors.PURPLE,UnicornAccessories.SUNGLASSES,UnicornAdornments.STAR_TATTOOS);// Since we are already "on" the account page, we have to use it to get to the
// actual place where you configure unicorns. Calling the "Add Unicorn" method
// takes us there.
varaddUnicornPage=accountPage.addUnicorn();// Now that we're on the AddUnicornPage, we will pass the "sparkles" object to
// its createUnicorn() method. This method will take Sparkles' attributes,
// fill out the form, and click submit.
varunicornConfirmationPage=addUnicornPage.createUnicorn(sparkles);
// The Unicorn is a top-level Object--it has attributes, which are set here.
// This only stores the values; it does not fill out any web forms or interact
// with the browser in any way.
valsparkles=Unicorn("Sparkles",UnicornColors.PURPLE,UnicornAccessories.SUNGLASSES,UnicornAdornments.STAR_TATTOOS)// Since we are already "on" the account page, we have to use it to get to the
// actual place where you configure unicorns. Calling the "Add Unicorn" method
// takes us there.
valaddUnicornPage=accountPage.addUnicorn()// Now that we're on the AddUnicornPage, we will pass the "sparkles" object to
// its createUnicorn() method. This method will take Sparkles' attributes,
// fill out the form, and click submit.
unicornConfirmationPage=addUnicornPage.createUnicorn(sparkles)
既然您已经配置好了独角兽,
您需要进入第三步:确保它确实有效。
// The exists() method from UnicornConfirmationPage will take the Sparkles// object--a specification of the attributes you want to see, and compare// them with the fields on the page.Assert.assertTrue("Sparkles should have been created, with all attributes intact",unicornConfirmationPage.exists(sparkles));
# The exists() method from UnicornConfirmationPage will take the Sparkles# object--a specification of the attributes you want to see, and compare# them with the fields on the page.assertunicorn_confirmation_page.exists(sparkles),"Sparkles should have been created, with all attributes intact"
// The exists() method from UnicornConfirmationPage will take the Sparkles // object--a specification of the attributes you want to see, and compare// them with the fields on the page.Assert.True(unicornConfirmationPage.Exists(sparkles),"Sparkles should have been created, with all attributes intact");
# The exists() method from UnicornConfirmationPage will take the Sparkles# object--a specification of the attributes you want to see, and compare# them with the fields on the page.expect(unicorn_confirmation_page.exists?(sparkles)).tobe,'Sparkles should have been created, with all attributes intact'
// The exists() method from UnicornConfirmationPage will take the Sparkles
// object--a specification of the attributes you want to see, and compare
// them with the fields on the page.
assert(unicornConfirmationPage.exists(sparkles),"Sparkles should have been created, with all attributes intact");
// The exists() method from UnicornConfirmationPage will take the Sparkles
// object--a specification of the attributes you want to see, and compare
// them with the fields on the page.
assertTrue("Sparkles should have been created, with all attributes intact",unicornConfirmationPage.exists(sparkles))
packagedev.selenium.design_strategies;importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.Disabled;importorg.junit.jupiter.api.Test;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;importorg.openqa.selenium.support.ui.LoadableComponent;classEditIssueBasic{privatefinalWebDriverdriver;publicEditIssueBasic(WebDriverdriver){this.driver=driver;}publicvoidsetTitle(Stringtitle){WebElementfield=driver.findElement(By.id("issue_title"));clearAndType(field,title);}publicvoidsetBody(Stringbody){WebElementfield=driver.findElement(By.id("issue_body"));clearAndType(field,body);}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,seleniumVersion);}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);}}classIssueListextendsLoadableComponent<IssueList>{privatefinalWebDriverdriver;publicIssueList(WebDriverdriver){this.driver=driver;}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains("/issues")&&!url.contains("/issues/"),"Not on the issues list page: "+url);}}classProjectPageextendsLoadableComponent<ProjectPage>{privatefinalWebDriverdriver;privatefinalStringprojectName;publicProjectPage(WebDriverdriver,StringprojectName){this.driver=driver;this.projectName=projectName;}@Overrideprotectedvoidload(){driver.get("http://"+projectName+".googlecode.com/");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains(projectName));}}classSecuredPageextendsLoadableComponent<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.if(driver.findElements(By.id("multilogin-dropdown")).isEmpty()){Assertions.fail("Cannot locate user name link");}}}classEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;// 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,null);}publicEditIssue(WebDriverdriver,LoadableComponent<?>parent){this.driver=driver;this.parent=parent;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}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,seleniumVersion);}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);}}classActionBot{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");}}classNestedComponentsExampleTest{@Test@Disabled("Illustrative only: exercises live GitHub sign-in and issue-creation pages")voiddemonstrateNestedLoadableComponents(){WebDriverdriver=newChromeDriver();try{ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","not-a-real-password");EditIssueeditIssue=newEditIssue(driver,securedPage).get();editIssue.setHowToReproduce("How to Reproduce");editIssue.setLogOutput("Log Output");editIssue.setOperatingSystem("Operating System");editIssue.setSeleniumVersion("Selenium Version");editIssue.setBrowserVersion("Browser Version");editIssue.setDriverVersion("Driver Version");editIssue.setUsingGrid("I Am Using Grid");}finally{driver.quit();}}}
packagedev.selenium.design_strategies;importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.Disabled;importorg.junit.jupiter.api.Test;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;importorg.openqa.selenium.support.ui.LoadableComponent;classEditIssueBasic{privatefinalWebDriverdriver;publicEditIssueBasic(WebDriverdriver){this.driver=driver;}publicvoidsetTitle(Stringtitle){WebElementfield=driver.findElement(By.id("issue_title"));clearAndType(field,title);}publicvoidsetBody(Stringbody){WebElementfield=driver.findElement(By.id("issue_body"));clearAndType(field,body);}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,seleniumVersion);}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);}}classIssueListextendsLoadableComponent<IssueList>{privatefinalWebDriverdriver;publicIssueList(WebDriverdriver){this.driver=driver;}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains("/issues")&&!url.contains("/issues/"),"Not on the issues list page: "+url);}}classProjectPageextendsLoadableComponent<ProjectPage>{privatefinalWebDriverdriver;privatefinalStringprojectName;publicProjectPage(WebDriverdriver,StringprojectName){this.driver=driver;this.projectName=projectName;}@Overrideprotectedvoidload(){driver.get("http://"+projectName+".googlecode.com/");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains(projectName));}}classSecuredPageextendsLoadableComponent<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.if(driver.findElements(By.id("multilogin-dropdown")).isEmpty()){Assertions.fail("Cannot locate user name link");}}}classEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;// 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,null);}publicEditIssue(WebDriverdriver,LoadableComponent<?>parent){this.driver=driver;this.parent=parent;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}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,seleniumVersion);}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);}}classActionBot{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");}}classNestedComponentsExampleTest{@Test@Disabled("Illustrative only: exercises live GitHub sign-in and issue-creation pages")voiddemonstrateNestedLoadableComponents(){WebDriverdriver=newChromeDriver();try{ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","not-a-real-password");EditIssueeditIssue=newEditIssue(driver,securedPage).get();editIssue.setHowToReproduce("How to Reproduce");editIssue.setLogOutput("Log Output");editIssue.setOperatingSystem("Operating System");editIssue.setSeleniumVersion("Selenium Version");editIssue.setBrowserVersion("Browser Version");editIssue.setDriverVersion("Driver Version");editIssue.setUsingGrid("I Am Using Grid");}finally{driver.quit();}}}
@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}
packagedev.selenium.design_strategies;importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.Disabled;importorg.junit.jupiter.api.Test;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;importorg.openqa.selenium.support.ui.LoadableComponent;classEditIssueBasic{privatefinalWebDriverdriver;publicEditIssueBasic(WebDriverdriver){this.driver=driver;}publicvoidsetTitle(Stringtitle){WebElementfield=driver.findElement(By.id("issue_title"));clearAndType(field,title);}publicvoidsetBody(Stringbody){WebElementfield=driver.findElement(By.id("issue_body"));clearAndType(field,body);}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,seleniumVersion);}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);}}classIssueListextendsLoadableComponent<IssueList>{privatefinalWebDriverdriver;publicIssueList(WebDriverdriver){this.driver=driver;}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains("/issues")&&!url.contains("/issues/"),"Not on the issues list page: "+url);}}classProjectPageextendsLoadableComponent<ProjectPage>{privatefinalWebDriverdriver;privatefinalStringprojectName;publicProjectPage(WebDriverdriver,StringprojectName){this.driver=driver;this.projectName=projectName;}@Overrideprotectedvoidload(){driver.get("http://"+projectName+".googlecode.com/");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains(projectName));}}classSecuredPageextendsLoadableComponent<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.if(driver.findElements(By.id("multilogin-dropdown")).isEmpty()){Assertions.fail("Cannot locate user name link");}}}classEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;// 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,null);}publicEditIssue(WebDriverdriver,LoadableComponent<?>parent){this.driver=driver;this.parent=parent;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}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,seleniumVersion);}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);}}classActionBot{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");}}classNestedComponentsExampleTest{@Test@Disabled("Illustrative only: exercises live GitHub sign-in and issue-creation pages")voiddemonstrateNestedLoadableComponents(){WebDriverdriver=newChromeDriver();try{ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","not-a-real-password");EditIssueeditIssue=newEditIssue(driver,securedPage).get();editIssue.setHowToReproduce("How to Reproduce");editIssue.setLogOutput("Log Output");editIssue.setOperatingSystem("Operating System");editIssue.setSeleniumVersion("Selenium Version");editIssue.setBrowserVersion("Browser Version");editIssue.setDriverVersion("Driver Version");editIssue.setUsingGrid("I Am Using Grid");}finally{driver.quit();}}}
classEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;// 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,null);}publicEditIssue(WebDriverdriver,LoadableComponent<?>parent){this.driver=driver;this.parent=parent;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}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,seleniumVersion);}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);}}
packagedev.selenium.design_strategies;importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.Disabled;importorg.junit.jupiter.api.Test;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;importorg.openqa.selenium.support.ui.LoadableComponent;classEditIssueBasic{privatefinalWebDriverdriver;publicEditIssueBasic(WebDriverdriver){this.driver=driver;}publicvoidsetTitle(Stringtitle){WebElementfield=driver.findElement(By.id("issue_title"));clearAndType(field,title);}publicvoidsetBody(Stringbody){WebElementfield=driver.findElement(By.id("issue_body"));clearAndType(field,body);}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,seleniumVersion);}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);}}classIssueListextendsLoadableComponent<IssueList>{privatefinalWebDriverdriver;publicIssueList(WebDriverdriver){this.driver=driver;}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains("/issues")&&!url.contains("/issues/"),"Not on the issues list page: "+url);}}classProjectPageextendsLoadableComponent<ProjectPage>{privatefinalWebDriverdriver;privatefinalStringprojectName;publicProjectPage(WebDriverdriver,StringprojectName){this.driver=driver;this.projectName=projectName;}@Overrideprotectedvoidload(){driver.get("http://"+projectName+".googlecode.com/");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains(projectName));}}classSecuredPageextendsLoadableComponent<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.if(driver.findElements(By.id("multilogin-dropdown")).isEmpty()){Assertions.fail("Cannot locate user name link");}}}classEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;// 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,null);}publicEditIssue(WebDriverdriver,LoadableComponent<?>parent){this.driver=driver;this.parent=parent;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}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,seleniumVersion);}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);}}classActionBot{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");}}classNestedComponentsExampleTest{@Test@Disabled("Illustrative only: exercises live GitHub sign-in and issue-creation pages")voiddemonstrateNestedLoadableComponents(){WebDriverdriver=newChromeDriver();try{ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","not-a-real-password");EditIssueeditIssue=newEditIssue(driver,securedPage).get();editIssue.setHowToReproduce("How to Reproduce");editIssue.setLogOutput("Log Output");editIssue.setOperatingSystem("Operating System");editIssue.setSeleniumVersion("Selenium Version");editIssue.setBrowserVersion("Browser Version");editIssue.setDriverVersion("Driver Version");editIssue.setUsingGrid("I Am Using Grid");}finally{driver.quit();}}}
packagedev.selenium.design_strategies;importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.Disabled;importorg.junit.jupiter.api.Test;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;importorg.openqa.selenium.support.ui.LoadableComponent;classEditIssueBasic{privatefinalWebDriverdriver;publicEditIssueBasic(WebDriverdriver){this.driver=driver;}publicvoidsetTitle(Stringtitle){WebElementfield=driver.findElement(By.id("issue_title"));clearAndType(field,title);}publicvoidsetBody(Stringbody){WebElementfield=driver.findElement(By.id("issue_body"));clearAndType(field,body);}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,seleniumVersion);}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);}}classIssueListextendsLoadableComponent<IssueList>{privatefinalWebDriverdriver;publicIssueList(WebDriverdriver){this.driver=driver;}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains("/issues")&&!url.contains("/issues/"),"Not on the issues list page: "+url);}}classProjectPageextendsLoadableComponent<ProjectPage>{privatefinalWebDriverdriver;privatefinalStringprojectName;publicProjectPage(WebDriverdriver,StringprojectName){this.driver=driver;this.projectName=projectName;}@Overrideprotectedvoidload(){driver.get("http://"+projectName+".googlecode.com/");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains(projectName));}}classSecuredPageextendsLoadableComponent<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.if(driver.findElements(By.id("multilogin-dropdown")).isEmpty()){Assertions.fail("Cannot locate user name link");}}}classEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;// 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,null);}publicEditIssue(WebDriverdriver,LoadableComponent<?>parent){this.driver=driver;this.parent=parent;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}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,seleniumVersion);}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);}}classActionBot{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");}}classNestedComponentsExampleTest{@Test@Disabled("Illustrative only: exercises live GitHub sign-in and issue-creation pages")voiddemonstrateNestedLoadableComponents(){WebDriverdriver=newChromeDriver();try{ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","not-a-real-password");EditIssueeditIssue=newEditIssue(driver,securedPage).get();editIssue.setHowToReproduce("How to Reproduce");editIssue.setLogOutput("Log Output");editIssue.setOperatingSystem("Operating System");editIssue.setSeleniumVersion("Selenium Version");editIssue.setBrowserVersion("Browser Version");editIssue.setDriverVersion("Driver Version");editIssue.setUsingGrid("I Am Using Grid");}finally{driver.quit();}}}
classSecuredPageextendsLoadableComponent<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.if(driver.findElements(By.id("multilogin-dropdown")).isEmpty()){Assertions.fail("Cannot locate user name link");}}}
packagedev.selenium.design_strategies;importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.Disabled;importorg.junit.jupiter.api.Test;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;importorg.openqa.selenium.support.ui.LoadableComponent;classEditIssueBasic{privatefinalWebDriverdriver;publicEditIssueBasic(WebDriverdriver){this.driver=driver;}publicvoidsetTitle(Stringtitle){WebElementfield=driver.findElement(By.id("issue_title"));clearAndType(field,title);}publicvoidsetBody(Stringbody){WebElementfield=driver.findElement(By.id("issue_body"));clearAndType(field,body);}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,seleniumVersion);}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);}}classIssueListextendsLoadableComponent<IssueList>{privatefinalWebDriverdriver;publicIssueList(WebDriverdriver){this.driver=driver;}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains("/issues")&&!url.contains("/issues/"),"Not on the issues list page: "+url);}}classProjectPageextendsLoadableComponent<ProjectPage>{privatefinalWebDriverdriver;privatefinalStringprojectName;publicProjectPage(WebDriverdriver,StringprojectName){this.driver=driver;this.projectName=projectName;}@Overrideprotectedvoidload(){driver.get("http://"+projectName+".googlecode.com/");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains(projectName));}}classSecuredPageextendsLoadableComponent<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.if(driver.findElements(By.id("multilogin-dropdown")).isEmpty()){Assertions.fail("Cannot locate user name link");}}}classEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;// 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,null);}publicEditIssue(WebDriverdriver,LoadableComponent<?>parent){this.driver=driver;this.parent=parent;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}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,seleniumVersion);}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);}}classActionBot{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");}}classNestedComponentsExampleTest{@Test@Disabled("Illustrative only: exercises live GitHub sign-in and issue-creation pages")voiddemonstrateNestedLoadableComponents(){WebDriverdriver=newChromeDriver();try{ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","not-a-real-password");EditIssueeditIssue=newEditIssue(driver,securedPage).get();editIssue.setHowToReproduce("How to Reproduce");editIssue.setLogOutput("Log Output");editIssue.setOperatingSystem("Operating System");editIssue.setSeleniumVersion("Selenium Version");editIssue.setBrowserVersion("Browser Version");editIssue.setDriverVersion("Driver Version");editIssue.setUsingGrid("I Am Using Grid");}finally{driver.quit();}}}
packagedev.selenium.design_strategies;importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.Disabled;importorg.junit.jupiter.api.Test;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;importorg.openqa.selenium.support.ui.LoadableComponent;classEditIssueBasic{privatefinalWebDriverdriver;publicEditIssueBasic(WebDriverdriver){this.driver=driver;}publicvoidsetTitle(Stringtitle){WebElementfield=driver.findElement(By.id("issue_title"));clearAndType(field,title);}publicvoidsetBody(Stringbody){WebElementfield=driver.findElement(By.id("issue_body"));clearAndType(field,body);}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,seleniumVersion);}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);}}classIssueListextendsLoadableComponent<IssueList>{privatefinalWebDriverdriver;publicIssueList(WebDriverdriver){this.driver=driver;}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains("/issues")&&!url.contains("/issues/"),"Not on the issues list page: "+url);}}classProjectPageextendsLoadableComponent<ProjectPage>{privatefinalWebDriverdriver;privatefinalStringprojectName;publicProjectPage(WebDriverdriver,StringprojectName){this.driver=driver;this.projectName=projectName;}@Overrideprotectedvoidload(){driver.get("http://"+projectName+".googlecode.com/");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains(projectName));}}classSecuredPageextendsLoadableComponent<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.if(driver.findElements(By.id("multilogin-dropdown")).isEmpty()){Assertions.fail("Cannot locate user name link");}}}classEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;// 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,null);}publicEditIssue(WebDriverdriver,LoadableComponent<?>parent){this.driver=driver;this.parent=parent;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}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,seleniumVersion);}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);}}classActionBot{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");}}classNestedComponentsExampleTest{@Test@Disabled("Illustrative only: exercises live GitHub sign-in and issue-creation pages")voiddemonstrateNestedLoadableComponents(){WebDriverdriver=newChromeDriver();try{ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","not-a-real-password");EditIssueeditIssue=newEditIssue(driver,securedPage).get();editIssue.setHowToReproduce("How to Reproduce");editIssue.setLogOutput("Log Output");editIssue.setOperatingSystem("Operating System");editIssue.setSeleniumVersion("Selenium Version");editIssue.setBrowserVersion("Browser Version");editIssue.setDriverVersion("Driver Version");editIssue.setUsingGrid("I Am Using Grid");}finally{driver.quit();}}}
classNestedComponentsExampleTest{@Test@Disabled("Illustrative only: exercises live GitHub sign-in and issue-creation pages")voiddemonstrateNestedLoadableComponents(){WebDriverdriver=newChromeDriver();try{ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","not-a-real-password");EditIssueeditIssue=newEditIssue(driver,securedPage).get();editIssue.setHowToReproduce("How to Reproduce");editIssue.setLogOutput("Log Output");editIssue.setOperatingSystem("Operating System");editIssue.setSeleniumVersion("Selenium Version");editIssue.setBrowserVersion("Browser Version");editIssue.setDriverVersion("Driver Version");editIssue.setUsingGrid("I Am Using Grid");}finally{driver.quit();}}}
packagedev.selenium.design_strategies;importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.Disabled;importorg.junit.jupiter.api.Test;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;importorg.openqa.selenium.support.ui.LoadableComponent;classEditIssueBasic{privatefinalWebDriverdriver;publicEditIssueBasic(WebDriverdriver){this.driver=driver;}publicvoidsetTitle(Stringtitle){WebElementfield=driver.findElement(By.id("issue_title"));clearAndType(field,title);}publicvoidsetBody(Stringbody){WebElementfield=driver.findElement(By.id("issue_body"));clearAndType(field,body);}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,seleniumVersion);}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);}}classIssueListextendsLoadableComponent<IssueList>{privatefinalWebDriverdriver;publicIssueList(WebDriverdriver){this.driver=driver;}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains("/issues")&&!url.contains("/issues/"),"Not on the issues list page: "+url);}}classProjectPageextendsLoadableComponent<ProjectPage>{privatefinalWebDriverdriver;privatefinalStringprojectName;publicProjectPage(WebDriverdriver,StringprojectName){this.driver=driver;this.projectName=projectName;}@Overrideprotectedvoidload(){driver.get("http://"+projectName+".googlecode.com/");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains(projectName));}}classSecuredPageextendsLoadableComponent<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.if(driver.findElements(By.id("multilogin-dropdown")).isEmpty()){Assertions.fail("Cannot locate user name link");}}}classEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;// 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,null);}publicEditIssue(WebDriverdriver,LoadableComponent<?>parent){this.driver=driver;this.parent=parent;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}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,seleniumVersion);}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);}}classActionBot{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");}}classNestedComponentsExampleTest{@Test@Disabled("Illustrative only: exercises live GitHub sign-in and issue-creation pages")voiddemonstrateNestedLoadableComponents(){WebDriverdriver=newChromeDriver();try{ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","not-a-real-password");EditIssueeditIssue=newEditIssue(driver,securedPage).get();editIssue.setHowToReproduce("How to Reproduce");editIssue.setLogOutput("Log Output");editIssue.setOperatingSystem("Operating System");editIssue.setSeleniumVersion("Selenium Version");editIssue.setBrowserVersion("Browser Version");editIssue.setDriverVersion("Driver Version");editIssue.setUsingGrid("I Am Using Grid");}finally{driver.quit();}}}
classActionBot{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");}}
packagedev.selenium.design_strategies;importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.Disabled;importorg.junit.jupiter.api.Test;importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importorg.openqa.selenium.support.FindBy;importorg.openqa.selenium.support.PageFactory;importorg.openqa.selenium.support.ui.LoadableComponent;classEditIssueBasic{privatefinalWebDriverdriver;publicEditIssueBasic(WebDriverdriver){this.driver=driver;}publicvoidsetTitle(Stringtitle){WebElementfield=driver.findElement(By.id("issue_title"));clearAndType(field,title);}publicvoidsetBody(Stringbody){WebElementfield=driver.findElement(By.id("issue_body"));clearAndType(field,body);}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,seleniumVersion);}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);}}classIssueListextendsLoadableComponent<IssueList>{privatefinalWebDriverdriver;publicIssueList(WebDriverdriver){this.driver=driver;}@Overrideprotectedvoidload(){driver.get("https://github.com/SeleniumHQ/selenium/issues");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains("/issues")&&!url.contains("/issues/"),"Not on the issues list page: "+url);}}classProjectPageextendsLoadableComponent<ProjectPage>{privatefinalWebDriverdriver;privatefinalStringprojectName;publicProjectPage(WebDriverdriver,StringprojectName){this.driver=driver;this.projectName=projectName;}@Overrideprotectedvoidload(){driver.get("http://"+projectName+".googlecode.com/");}@OverrideprotectedvoidisLoaded()throwsError{Stringurl=driver.getCurrentUrl();Assertions.assertTrue(url.contains(projectName));}}classSecuredPageextendsLoadableComponent<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.if(driver.findElements(By.id("multilogin-dropdown")).isEmpty()){Assertions.fail("Cannot locate user name link");}}}classEditIssueextendsLoadableComponent<EditIssue>{privatefinalWebDriverdriver;privatefinalLoadableComponent<?>parent;// 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,null);}publicEditIssue(WebDriverdriver,LoadableComponent<?>parent){this.driver=driver;this.parent=parent;// This call sets the WebElement fields.PageFactory.initElements(driver,this);}@Overrideprotectedvoidload(){if(parent!=null){parent.get();}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();Assertions.assertTrue(url.contains("/issues/new"),"Not on the issue entry page: "+url);}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,seleniumVersion);}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);}}classActionBot{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");}}classNestedComponentsExampleTest{@Test@Disabled("Illustrative only: exercises live GitHub sign-in and issue-creation pages")voiddemonstrateNestedLoadableComponents(){WebDriverdriver=newChromeDriver();try{ProjectPageproject=newProjectPage(driver,"selenium");SecuredPagesecuredPage=newSecuredPage(driver,project,"example","not-a-real-password");EditIssueeditIssue=newEditIssue(driver,securedPage).get();editIssue.setHowToReproduce("How to Reproduce");editIssue.setLogOutput("Log Output");editIssue.setOperatingSystem("Operating System");editIssue.setSeleniumVersion("Selenium Version");editIssue.setBrowserVersion("Browser Version");editIssue.setDriverVersion("Driver Version");editIssue.setUsingGrid("I Am Using Grid");}finally{driver.quit();}}}
"""
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
/***
* Tests login feature
*/publicclassLogin{publicvoidtestLogin(){// fill login data on sign-in pagedriver.findElement(By.name("user_name")).sendKeys("userName");driver.findElement(By.name("password")).sendKeys("my supersecret password");driver.findElement(By.name("sign-in")).click();// verify h1 tag is "Hello userName" after logindriver.findElement(By.tagName("h1")).isDisplayed();assertThat(driver.findElement(By.tagName("h1")).getText(),is("Hello userName"));}}
这种方式存在两个问题。
测试方法与 AUT 的定位器(在本例中为 ID)之间没有分离;两者
交织在同一个方法中。如果 AUT 的 UI 更改了其标识符、布局,
或登录的输入和处理方式,测试本身必须随之更改。
ID 定位器会分散在多个测试中,散布在所有需要
使用此登录页面的测试里。
应用页面对象模型后,此示例可以重写为
以下登录页面的页面对象示例。
importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;/**
* Page Object encapsulates the Sign-in page.
*/publicclassSignInPage{protectedWebDriverdriver;// <input name="user_name" type="text" value="">privateByusernameBy=By.name("user_name");// <input name="password" type="password" value="">privateBypasswordBy=By.name("password");// <input name="sign_in" type="submit" value="SignIn">privateBysigninBy=By.name("sign_in");publicSignInPage(WebDriverdriver){this.driver=driver;if(!driver.getTitle().equals("Sign In Page")){thrownewIllegalStateException("This is not Sign In Page,"+" current page is: "+driver.getCurrentUrl());}}/**
* Login as valid user
*
* @param userName
* @param password
* @return HomePage object
*/publicHomePageloginValidUser(StringuserName,Stringpassword){driver.findElement(usernameBy).sendKeys(userName);driver.findElement(passwordBy).sendKeys(password);driver.findElement(signinBy).click();returnnewHomePage(driver);}}
而首页的页面对象可能如下所示。
importorg.openqa.selenium.By;importorg.openqa.selenium.WebDriver;/**
* Page Object encapsulates the Home Page
*/publicclassHomePage{protectedWebDriverdriver;// <h1>Hello userName</h1>privateBymessageBy=By.tagName("h1");publicHomePage(WebDriverdriver){this.driver=driver;if(!driver.getTitle().equals("Home Page of logged in user")){thrownewIllegalStateException("This is not Home Page of logged in user,"+" current page is: "+driver.getCurrentUrl());}}/**
* Get message (h1 tag)
*
* @return String message text
*/publicStringgetMessageText(){returndriver.findElement(messageBy).getText();}publicHomePagemanageProfile(){// Page encapsulation to manage profile functionalityreturnnewHomePage(driver);}/* More methods offering the services represented by Home Page
of Logged User. These methods in turn might return more Page Objects
for example click on Compose mail button could return ComposeMail class object */}
publicabstractclassBasePage{protectedWebDriverdriver;publicBasePage(WebDriverdriver){this.driver=driver;}}// Page ObjectpublicclassProductsPageextendsBasePage{publicProductsPage(WebDriverdriver){super(driver);// No assertions, throws an exception if the element is not loadednewWebDriverWait(driver,Duration.ofSeconds(3)).until(d->d.findElement(By.className("header_container")));}// Returning a list of products is a service of the pagepublicList<Product>getProducts(){returndriver.findElements(By.className("inventory_item")).stream().map(e->newProduct(e))// Map WebElement to a product component.toList();}// Return a specific product using a boolean-valued function (predicate)// This is the behavioral Strategy Pattern from GoFpublicProductgetProduct(Predicate<Product>condition){returngetProducts().stream().filter(condition)// Filter by product name or price.findFirst().orElseThrow(()->newRuntimeException("Product not found"));// Error thrown during actual test run}}
Product 组件对象在产品页面对象内部使用。
publicabstractclassBaseComponent{protectedWebElementroot;publicBaseComponent(WebElementroot){this.root=root;}}// Page Component ObjectpublicclassProductextendsBaseComponent{// The root element contains the entire componentpublicProduct(WebElementroot){super(root);// inventory_item}publicStringgetName(){// Locating an element begins at the root of the componentreturnroot.findElement(By.className("inventory_item_name")).getText();}publicBigDecimalgetPrice(){returnnewBigDecimal(root.findElement(By.className("inventory_item_price")).getText().replace("$","")).setScale(2,RoundingMode.UNNECESSARY);// Sanitation and formatting}publicvoidaddToCart(){root.findElement(By.id("add-to-cart-backpack")).click();}}
现在,产品测试将按如下方式使用页面对象和页面组件对象。
publicclassProductsTest{@TestpublicvoidtestProductInventory(){varproductsPage=newProductsPage(driver);// page objectvarproducts=productsPage.getProducts();assertEquals(6,products.size());// expected, actual}@TestpublicvoidtestProductPrices(){varproductsPage=newProductsPage(driver);// Pass a lambda expression (predicate) to filter the list of products// The predicate or "strategy" is the behavior passed as parametervarbackpack=productsPage.getProduct(p->p.getName().equals("Backpack"));// page component objectvarbikeLight=productsPage.getProduct(p->p.getName().equals("Bike Light"));assertEquals(newBigDecimal("29.99"),backpack.getPrice());assertEquals(newBigDecimal("9.99"),bikeLight.getPrice());}}
publicclassLoginPage{publicHomePageloginAs(Stringusername,Stringpassword){// ... clever magic happens here}publicLoginPageloginAsExpectingError(Stringusername,Stringpassword){// ... failed login here, maybe because one or both of the username and password are wrong}publicStringgetErrorMessage(){// So we can verify that the correct error is shown}}
上面的代码展示了一个要点:测试而非页面对象应负责对页面状态进行断言。例如:
publicvoidtestMessagesAreReadOrUnread(){Inboxinbox=newInbox(driver);inbox.assertMessageWithSubjectIsUnread("I like cheese");inbox.assertMessageWithSubjectIsNotUnread("I'm not fond of tofu");}
可以重写为:
publicvoidtestMessagesAreReadOrUnread(){Inboxinbox=newInbox(driver);assertTrue(inbox.isMessageWithSubjectIsUnread("I like cheese"));assertFalse(inbox.isMessageWithSubjectIsUnread("I'm not fond of tofu"));}
最后,页面对象不必表示整个页面,可以由页面对象组件组成。
这些组件可以表示在站点或页面中频繁出现的部分,例如站点导航。
核心原则是,在你的测试套件中只有一个地方了解特定页面(或页面的一部分)的 HTML 结构。
总结
公共方法表示页面或组件提供的服务
尽量不要暴露页面或组件的内部细节
通常不要进行断言
方法返回其他页面对象、页面组件对象,或可选地返回自身(用于流畅语法)
不必始终表示整个页面
同一操作的不同结果建模为不同的方法
示例
publicclassLoginPage{privatefinalWebDriverdriver;publicLoginPage(WebDriverdriver){this.driver=driver;// Check that we're on the right page.if(!"Login".equals(driver.getTitle())){// Alternatively, we could navigate to the login page, perhaps logging out firstthrownewIllegalStateException("This is not the login page");}}// The login page contains several HTML elements that will be represented as WebElements.// The locators for these elements should only be defined once.ByusernameLocator=By.id("username");BypasswordLocator=By.id("passwd");ByloginButtonLocator=By.id("login");// The login page allows the user to type their username into the username fieldpublicLoginPagetypeUsername(Stringusername){// This is the only place that "knows" how to enter a usernamedriver.findElement(usernameLocator).sendKeys(username);// Return the current page object as this action doesn't navigate to a page represented by another PageObjectreturnthis;}// The login page allows the user to type their password into the password fieldpublicLoginPagetypePassword(Stringpassword){// This is the only place that "knows" how to enter a passworddriver.findElement(passwordLocator).sendKeys(password);// Return the current page object as this action doesn't navigate to a page represented by another PageObjectreturnthis;}// The login page allows the user to submit the login formpublicHomePagesubmitLogin(){// This is the only place that submits the login form and expects the destination to be the home page.// A separate method should be created for the instance of clicking login whilst expecting a login failure. driver.findElement(loginButtonLocator).submit();// Return a new page object representing the destination. Should the login page ever// go somewhere else (for example, a legal disclaimer) then changing the method signature// for this method will mean that all tests that rely on this behaviour won't compile.returnnewHomePage(driver);}// The login page allows the user to submit the login form knowing that an invalid username and / or password were enteredpublicLoginPagesubmitLoginExpectingFailure(){// This is the only place that submits the login form and expects the destination to be the login page due to login failure.driver.findElement(loginButtonLocator).submit();// Return a new page object representing the destination. Should the user ever be navigated to the home page after submitting a login with credentials // expected to fail login, the script will fail when it attempts to instantiate the LoginPage PageObject.returnnewLoginPage(driver);}// Conceptually, the login page offers the user the service of being able to "log into"// the application using a user name and password. publicHomePageloginAs(Stringusername,Stringpassword){// The PageObject methods that enter username, password & submit login have already defined and should not be repeated here.typeUsername(username);typePassword(password);returnsubmitLogin();}}
/**
* Takes a username and password, fills out the fields, and clicks "login".
* @return An instance of the AccountPage
*/publicAccountPageloginAsUser(Stringusername,Stringpassword){WebElementloginField=driver.findElement(By.id("loginField"));loginField.clear();loginField.sendKeys(username);// Fill out the password field. The locator we're using is "By.id", and we should// have it defined elsewhere in the class.WebElementpasswordField=driver.findElement(By.id("password"));passwordField.clear();passwordField.sendKeys(password);// Click the login button, which happens to have the id "submit".driver.findElement(By.id("submit")).click();// Create and return a new instance of the AccountPage (via the built-in Selenium// PageFactory).returnPageFactory.newInstance(AccountPage.class);}
publicvoidloginTest(){loginAsUser("cbrown","cl0wn3");// Now that we're logged in, do some other stuff--since we used a DSL to support// our testers, it's as easy as choosing from available methods.do.something();do.somethingElse();Assert.assertTrue("Something should have been done!",something.wasDone());// Note that we still haven't referred to a button or web control anywhere in this// script...}
If you choose pytest as your test runner, this can be
easily done by yielding your driver in a global fixture. This way each test gets its own
driver instance, and you can ensure that drivers always quit after a test is finished
(pass or fail).
publicabstractclassBasePage{protectedWebDriverdriver;publicBasePage(WebDriverdriver){this.driver=driver;}}publicclassGoogleSearchPageextendsBasePage{publicGoogleSearchPage(WebDriverdriver){super(driver);// Generally do not assert within pages or components.// Effectively throws an exception if the lambda condition is not met.newWebDriverWait(driver,Duration.ofSeconds(3)).until(d->d.findElement(By.id("logo")));}publicGoogleSearchPagesetSearchString(Stringsstr){driver.findElement(By.id("gbqfq")).sendKeys(sstr);returnthis;}publicvoidclickSearchButton(){driver.findElement(By.id("gbqfb")).click();}}
验证码 (CAPTCHA), 是 全自动区分计算机和人类的图灵测试(Completely Automated Public Turing test to tell Computers and Humans Apart) 的简称,
是被明确地设计用于阻止自动化的, 所以不要尝试! 规避验证码的检查, 主要有两个策略: