使用 Selenium 获取子项的 XPath - Java
Get sub-item's XPath using Selenium - Java
我在第三步尝试单击菜单中的子项时遇到问题..
我登录了
进入项目
只删除创建的卡片
我认为问题在于获得正确的 xpath
第
页
打包页面对象;
导入 org.openqa.selenium.By;
导入 org.openqa.selenium.Keys;
导入 org.openqa.selenium.WebDriver;
导入 org.openqa.selenium.WebElement;
导入 org.openqa.selenium.interactions.Actions;
public class 页 {
受保护的最终 WebDriver webDriver;
public Page( final WebDriver driver ) {
this.webDriver =driver;
}
protected WebElement element(By by ) {
return webDriver.findElement( by );
}
public void pressEnter(){
Actions builder = new Actions(webDriver);
builder.sendKeys(Keys.RETURN).perform();
}
}
页面对象:卡片页面
package Helpers;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
public class public class CardPage extends PageObject.Page{
By close = By.xpath("//*[@id='ngdialog5']/div[2]/div/div[2]");
By menuCard = By.xpath("html/body/div[1]/div/div/div/div/ui-view/project/div[1]/board/div/div/div/backlog-list/div[2]/div/ul/li/ul/div[1]/card/li/div/div[1]/a[3]");
By container1stCard = By.xpath("html/body/div[1]/div/div/div/div/ui-view/project/div[1]/board/div/div/div/backlog-list/div[2]/div/ul/li/ul/div/card/li/div");
By delete3 = By.xpath("//*[contains(text(), 'delete')]");
By accceptWarning = By.xpath("html/body/div[4]/div/div[10]/button[1]");
By openCard = By.xpath("//*[@id=\"scrollable\"]/div/backlog-list/div[2]/div/ul/li/ul/div/card/li/div");
private Services services;
public CardPage(WebDriver driver) {
super(driver);
}
//SERVICES CARDS
private void closeCard() {
element(close).click();
}
public void delete1stCard(){
WebElement Wcontainer1stCard = element(container1stCard);//Menu
Actions builder = new Actions(super.webDriver);
Actions hoverOverContainer = builder.moveToElement(Wcontainer1stCard);
hoverOverContainer.perform();
Services.waitMilisegundos(1000);
element(menuCard).click();
Services.waitMilisegundos(500);
WebElement deleteBtn = element(delete3);
deleteBtn.click();//Menu Item
Services.waitMilisegundos(1000);
}
public void openCard(){
element(openCard).click();
}
}
页面对象服务
package Helpers;
import PageObject.*;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions;
import java.io.File;
import java.io.IOException;
import java.util.Date;
public class Services {
WebDriver webDriver;
private LandingPage landingPage;
private MainPage mainPage;
private LoginPage loginPage;
private ProjectPage projectPage;
private CardPage cardPage;
String url;
////
public Services(TmpEnvironment environment) {
webDriver = new StartDriver( environment.url ).getWebDriver();
}
public Services() {
webDriver = new StartDriver(TmpEnvironment.STAGING).getWebDriver();
}
///LOGIN SERVICES
public Services login(String email, String passw){
getLandingPage().goToLoginPage();
getLoginPage().writeUserName(email)
.writePassword(passw)
.clickOnLogin();
return this;
}
public Services enterToProject() {
getMainPage().enterToProject();
return this;
}
//PAGES GETTERS
public WebDriver getWebDriver() {
return webDriver;
}
public MainPage getMainPage() {
if (mainPage == null)
mainPage = new MainPage(webDriver);
return mainPage;
}
public LoginPage getLoginPage() {
if (loginPage == null)
loginPage = new LoginPage(webDriver);
return loginPage;
}
public ProjectPage getProjectPage(){
if (projectPage == null)
projectPage = new ProjectPage(webDriver);
return projectPage;
}
public LandingPage getLandingPage() {
if (landingPage == null)
landingPage = new LandingPage(webDriver);
return landingPage;
}
public CardPage getCardPage() {
if (cardPage == null)
cardPage = new CardPage(webDriver);
return cardPage;
}
//CARDS SERVICES
public Services delete1stCard() {
getCardPage().delete1stCard();
return this;
}
public static void waitMilisegundos(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void pressEnter(){
Actions builder = new Actions(webDriver);
builder.sendKeys(Keys.RETURN).perform();
}
public void pressEsc(){
Actions builder = new Actions(webDriver);
builder.sendKeys(Keys.ESCAPE).perform();
}
//
public Services goToLoginPage() {
getLandingPage().goToLoginPage();
return this;
}
public enum TmpEnvironment {
DEVELOPMENT( "http://tmp-landing-dev.theamalgama.com/index" ),
STAGING( "https://tmpapp.theamalgama.com" ),
PRODUCTION( "https://tmpapp.com" );
public final String url;
TmpEnvironment( final String url ) {
this.url = url;
}
public String getUrl(){
return url;
}
}
}
测试CLASS
package z_Test;
import Helpers.Services;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import static Helpers.Services.waitMilisegundos;
public class CardTest {
static String email, password;
Services services;
public CardTest(){
services = new Services();
}
@BeforeClass
public static void setData(){
email = "test01@testing.com";
password = "password";
}
@After
public void CloseDriver(){
services.getWebDriver().close();
}
/////////////////////////////////////////////////////////////
@Test
public void cardTest(){
services.login(email,password);
services.enterToProject()
.delete1stCard();
waitMilisegundos();
}
}
接下来是尝试删除卡时的错误消息。
[org.openqa.selenium.ElementNotVisibleException: element not visible
(Session info: chrome=58.0.3029.110) (Driver info:
chromedriver=2.30.477691
(6ee44a7247c639c0703f291d320bdf05c1531b57),platform=Linux
4.4.0-79-generic x86_64) (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 96 milliseconds
Build info: version: 'unknown', revision: 'unknown', time: 'unknown'
System info: host: 'julieta', ip: '127.0.1.1', os.name: 'Linux',
os.arch: 'amd64', os.version: '4.4.0-79-generic', java.version:
'1.8.0_131' Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities [{applicationCacheEnabled=false, rotatable=false,
mobileEmulationEnabled=false, networkConnectionEnabled=false,
chrome={chromedriverVersion=2.30.477691
(6ee44a7247c639c0703f291d320bdf05c1531b57),
userDataDir=/tmp/.org.chromium.Chromium.rQuYOu},
takesHeapSnapshot=true, pageLoadStrategy=normal,
databaseEnabled=false, handlesAlerts=true, hasTouchScreen=false,
version=58.0.3029.110, platform=LINUX, browserConnectionEnabled=false,
nativeEvents=true, acceptSslCerts=true, locationContextEnabled=true,
webStorageEnabled=true, browserName=chrome, takesScreenshot=true,
javascriptEnabled=true, cssSelectorsEnabled=true,
unexpectedAlertBehaviour=}] Session ID:
a33c710a9bae046f731a66bb56b344b8 at
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at
org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:215)
at
org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:167)
at
org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:671)
at
org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:272)
at
org.openqa.selenium.remote.RemoteWebElement.click(RemoteWebElement.java:82)
at PageObject.CardPage.delete1stCard(CardPage.java:92) at
Helpers.Services.delete1stCard(Services.java:201) at
z_Test.CardTest.cardTest(CardTest.java:69) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290) at
org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at
org.junit.runners.ParentRunner.access[=16=]0(ParentRunner.java:58) at
org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268) at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at
org.junit.runner.JUnitCore.run(JUnitCore.java:137) at
com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at
com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at
com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at
com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
]
我也试过使用不同的 xpath,所以我 运行 我得到了另一种例外:org.openqa.selenium.NoSuchElementException: Unable to locate element:
我认为你有很多问题需要改进。
您正在使用绝对 XPath,这始终是一种不好的做法。它们极其脆弱。您应该花一些时间阅读一些关于手工制作 XPath 的教程。它们会更短、更易于阅读,但也不会那么脆弱。
与其使用方法 delete1stCard()
,不如创建一个采用索引的方法 deleteCard(int index)
,以便您可以删除任何想要的卡片。您可能需要另一种方法 deleteCard(String cardName)
接收卡名并将其删除。我认为这可能比按索引删除更有用,但我不知道您的测试用例是什么样的。 (或者更好的是,实现一个卡片组件 class,正如我在下面建议的那样,它解决了这个问题。)
你的 class 称为 Services
似乎是一个包罗万象的桶。创建适当的页面对象模型并添加处理登录页面登录的登录页面、处理该页面的项目页面,等等。我不知道 Services
在您将所有内容重新组织到适当的页面对象后应该包含什么...我认为您可能不需要它。
我还建议您创建组件页面对象,例如卡片,一些工具栏。 "page object" 不必是整个页面。它可以是任何可重用的组件。您可以将 Services
class 中的一些可用功能移动到 TimerMenu
、ProjectBar
等组件中,以表示顶部的不同工具栏页面及其功能。
您将有一个代表卡片页面的 CardsPage
页面对象,例如https://tmpapp.theamalgama.com/#/projects/681/cards,但您还会有一个 CardComponent
表示页面上的实际卡片,这些内容包含在 <card>
标记中。 CardComponent
将包含单张卡片的功能...名称、该卡片的播放按钮、该卡片的完成图标、该卡片的 delete/edit/etc 选项,等等。
现在是真正的答案。我写了一个CardComponent
class,按照我建议你写的。您传入卡的名称,它会得到一个句柄。从那里,您可以调用 card.delete()
或 card.whatever()
,该操作将在您指定的卡上完成。它使处理单个卡片、项目等变得更加容易。卡片功能的更新很容易...更改进入 CardComponent
页面对象等
public class CardComponent
{
private WebDriver driver;
private WebElement card;
private By deleteCardLocator = By.xpath(".//p[@class='option-list-option'][.='Delete']");
private By acceptDeleteButtonLocator = By.xpath("//button[.='Accept']");
public CardComponent(WebDriver webDriver, String cardName)
{
driver = webDriver;
card = new WebDriverWait(webDriver, 10)
.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//card[contains(., '" + cardName + "')]")));
}
public void delete()
{
openMenu();
card.findElement(deleteCardLocator).click();
driver.findElement(acceptDeleteButtonLocator).click();
}
private void openMenu()
{
new Actions(driver).moveToElement(card).perform();
card.findElement(By.id("dots")).click();
}
}
要使用此代码,请导航至卡片页面并调用
CardComponent card = new CardComponent(driver, "card to delete");
card.delete();
我创建了一些新卡片并测试了这段代码并且它有效。
我在第三步尝试单击菜单中的子项时遇到问题..
我登录了
进入项目
只删除创建的卡片 我认为问题在于获得正确的 xpath 第
页打包页面对象;
导入 org.openqa.selenium.By; 导入 org.openqa.selenium.Keys; 导入 org.openqa.selenium.WebDriver; 导入 org.openqa.selenium.WebElement; 导入 org.openqa.selenium.interactions.Actions;
public class 页 { 受保护的最终 WebDriver webDriver;public Page( final WebDriver driver ) { this.webDriver =driver; } protected WebElement element(By by ) { return webDriver.findElement( by ); } public void pressEnter(){ Actions builder = new Actions(webDriver); builder.sendKeys(Keys.RETURN).perform(); }
}
页面对象:卡片页面
package Helpers;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
public class public class CardPage extends PageObject.Page{
By close = By.xpath("//*[@id='ngdialog5']/div[2]/div/div[2]");
By menuCard = By.xpath("html/body/div[1]/div/div/div/div/ui-view/project/div[1]/board/div/div/div/backlog-list/div[2]/div/ul/li/ul/div[1]/card/li/div/div[1]/a[3]");
By container1stCard = By.xpath("html/body/div[1]/div/div/div/div/ui-view/project/div[1]/board/div/div/div/backlog-list/div[2]/div/ul/li/ul/div/card/li/div");
By delete3 = By.xpath("//*[contains(text(), 'delete')]");
By accceptWarning = By.xpath("html/body/div[4]/div/div[10]/button[1]");
By openCard = By.xpath("//*[@id=\"scrollable\"]/div/backlog-list/div[2]/div/ul/li/ul/div/card/li/div");
private Services services;
public CardPage(WebDriver driver) {
super(driver);
}
//SERVICES CARDS
private void closeCard() {
element(close).click();
}
public void delete1stCard(){
WebElement Wcontainer1stCard = element(container1stCard);//Menu
Actions builder = new Actions(super.webDriver);
Actions hoverOverContainer = builder.moveToElement(Wcontainer1stCard);
hoverOverContainer.perform();
Services.waitMilisegundos(1000);
element(menuCard).click();
Services.waitMilisegundos(500);
WebElement deleteBtn = element(delete3);
deleteBtn.click();//Menu Item
Services.waitMilisegundos(1000);
}
public void openCard(){
element(openCard).click();
}
}
页面对象服务
package Helpers;
import PageObject.*;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions;
import java.io.File;
import java.io.IOException;
import java.util.Date;
public class Services {
WebDriver webDriver;
private LandingPage landingPage;
private MainPage mainPage;
private LoginPage loginPage;
private ProjectPage projectPage;
private CardPage cardPage;
String url;
////
public Services(TmpEnvironment environment) {
webDriver = new StartDriver( environment.url ).getWebDriver();
}
public Services() {
webDriver = new StartDriver(TmpEnvironment.STAGING).getWebDriver();
}
///LOGIN SERVICES
public Services login(String email, String passw){
getLandingPage().goToLoginPage();
getLoginPage().writeUserName(email)
.writePassword(passw)
.clickOnLogin();
return this;
}
public Services enterToProject() {
getMainPage().enterToProject();
return this;
}
//PAGES GETTERS
public WebDriver getWebDriver() {
return webDriver;
}
public MainPage getMainPage() {
if (mainPage == null)
mainPage = new MainPage(webDriver);
return mainPage;
}
public LoginPage getLoginPage() {
if (loginPage == null)
loginPage = new LoginPage(webDriver);
return loginPage;
}
public ProjectPage getProjectPage(){
if (projectPage == null)
projectPage = new ProjectPage(webDriver);
return projectPage;
}
public LandingPage getLandingPage() {
if (landingPage == null)
landingPage = new LandingPage(webDriver);
return landingPage;
}
public CardPage getCardPage() {
if (cardPage == null)
cardPage = new CardPage(webDriver);
return cardPage;
}
//CARDS SERVICES
public Services delete1stCard() {
getCardPage().delete1stCard();
return this;
}
public static void waitMilisegundos(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void pressEnter(){
Actions builder = new Actions(webDriver);
builder.sendKeys(Keys.RETURN).perform();
}
public void pressEsc(){
Actions builder = new Actions(webDriver);
builder.sendKeys(Keys.ESCAPE).perform();
}
//
public Services goToLoginPage() {
getLandingPage().goToLoginPage();
return this;
}
public enum TmpEnvironment {
DEVELOPMENT( "http://tmp-landing-dev.theamalgama.com/index" ),
STAGING( "https://tmpapp.theamalgama.com" ),
PRODUCTION( "https://tmpapp.com" );
public final String url;
TmpEnvironment( final String url ) {
this.url = url;
}
public String getUrl(){
return url;
}
}
}
测试CLASS
package z_Test;
import Helpers.Services;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import static Helpers.Services.waitMilisegundos;
public class CardTest {
static String email, password;
Services services;
public CardTest(){
services = new Services();
}
@BeforeClass
public static void setData(){
email = "test01@testing.com";
password = "password";
}
@After
public void CloseDriver(){
services.getWebDriver().close();
}
/////////////////////////////////////////////////////////////
@Test
public void cardTest(){
services.login(email,password);
services.enterToProject()
.delete1stCard();
waitMilisegundos();
}
}
接下来是尝试删除卡时的错误消息。
[org.openqa.selenium.ElementNotVisibleException: element not visible
(Session info: chrome=58.0.3029.110) (Driver info: chromedriver=2.30.477691 (6ee44a7247c639c0703f291d320bdf05c1531b57),platform=Linux 4.4.0-79-generic x86_64) (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 96 milliseconds Build info: version: 'unknown', revision: 'unknown', time: 'unknown' System info: host: 'julieta', ip: '127.0.1.1', os.name: 'Linux', os.arch: 'amd64', os.version: '4.4.0-79-generic', java.version: '1.8.0_131' Driver info: org.openqa.selenium.chrome.ChromeDriver Capabilities [{applicationCacheEnabled=false, rotatable=false, mobileEmulationEnabled=false, networkConnectionEnabled=false, chrome={chromedriverVersion=2.30.477691 (6ee44a7247c639c0703f291d320bdf05c1531b57), userDataDir=/tmp/.org.chromium.Chromium.rQuYOu}, takesHeapSnapshot=true, pageLoadStrategy=normal, databaseEnabled=false, handlesAlerts=true, hasTouchScreen=false, version=58.0.3029.110, platform=LINUX, browserConnectionEnabled=false, nativeEvents=true, acceptSslCerts=true, locationContextEnabled=true, webStorageEnabled=true, browserName=chrome, takesScreenshot=true, javascriptEnabled=true, cssSelectorsEnabled=true, unexpectedAlertBehaviour=}] Session ID: a33c710a9bae046f731a66bb56b344b8 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:215) at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:167) at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:671) at org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:272) at org.openqa.selenium.remote.RemoteWebElement.click(RemoteWebElement.java:82) at PageObject.CardPage.delete1stCard(CardPage.java:92) at Helpers.Services.delete1stCard(Services.java:201) at z_Test.CardTest.cardTest(CardTest.java:69) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner.run(ParentRunner.java:290) at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access[=16=]0(ParentRunner.java:58) at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)]
我也试过使用不同的 xpath,所以我 运行 我得到了另一种例外:org.openqa.selenium.NoSuchElementException: Unable to locate element:
我认为你有很多问题需要改进。
您正在使用绝对 XPath,这始终是一种不好的做法。它们极其脆弱。您应该花一些时间阅读一些关于手工制作 XPath 的教程。它们会更短、更易于阅读,但也不会那么脆弱。
与其使用方法
delete1stCard()
,不如创建一个采用索引的方法deleteCard(int index)
,以便您可以删除任何想要的卡片。您可能需要另一种方法deleteCard(String cardName)
接收卡名并将其删除。我认为这可能比按索引删除更有用,但我不知道您的测试用例是什么样的。 (或者更好的是,实现一个卡片组件 class,正如我在下面建议的那样,它解决了这个问题。)你的 class 称为
Services
似乎是一个包罗万象的桶。创建适当的页面对象模型并添加处理登录页面登录的登录页面、处理该页面的项目页面,等等。我不知道Services
在您将所有内容重新组织到适当的页面对象后应该包含什么...我认为您可能不需要它。我还建议您创建组件页面对象,例如卡片,一些工具栏。 "page object" 不必是整个页面。它可以是任何可重用的组件。您可以将
Services
class 中的一些可用功能移动到TimerMenu
、ProjectBar
等组件中,以表示顶部的不同工具栏页面及其功能。您将有一个代表卡片页面的
CardsPage
页面对象,例如https://tmpapp.theamalgama.com/#/projects/681/cards,但您还会有一个CardComponent
表示页面上的实际卡片,这些内容包含在<card>
标记中。CardComponent
将包含单张卡片的功能...名称、该卡片的播放按钮、该卡片的完成图标、该卡片的 delete/edit/etc 选项,等等。
现在是真正的答案。我写了一个CardComponent
class,按照我建议你写的。您传入卡的名称,它会得到一个句柄。从那里,您可以调用 card.delete()
或 card.whatever()
,该操作将在您指定的卡上完成。它使处理单个卡片、项目等变得更加容易。卡片功能的更新很容易...更改进入 CardComponent
页面对象等
public class CardComponent
{
private WebDriver driver;
private WebElement card;
private By deleteCardLocator = By.xpath(".//p[@class='option-list-option'][.='Delete']");
private By acceptDeleteButtonLocator = By.xpath("//button[.='Accept']");
public CardComponent(WebDriver webDriver, String cardName)
{
driver = webDriver;
card = new WebDriverWait(webDriver, 10)
.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//card[contains(., '" + cardName + "')]")));
}
public void delete()
{
openMenu();
card.findElement(deleteCardLocator).click();
driver.findElement(acceptDeleteButtonLocator).click();
}
private void openMenu()
{
new Actions(driver).moveToElement(card).perform();
card.findElement(By.id("dots")).click();
}
}
要使用此代码,请导航至卡片页面并调用
CardComponent card = new CardComponent(driver, "card to delete");
card.delete();
我创建了一些新卡片并测试了这段代码并且它有效。