英文:
Selenium Webdriver: How to click on a hidden element of a specific row from a tablelist (Java)?
问题
我在Java和Selenium方面还很新,希望尽可能清晰明了。
测试场景:
添加一个类别(例如:TestCategoryName),验证类别的创建,删除类别,验证类别的删除。
工作原理: 一旦类别被创建,所创建的类别将出现在表格末尾的附加行中。该表格显然包含了所有已创建的类别,但该表格的每一行都包含三个元素:
- 所创建类别的名称。
- 在所创建类别的名称下方,有两个隐藏元素:“编辑”和“删除”选项。这两个选项只在用户将鼠标移动到包含一个特定类别的行上时才可见,例如“类别名称”。
附注: 我无法点击类别名称,否则我会进入另一个页面。
我的困难: 我只需要删除一个类别,即最后创建的一个(例如,表格的最后一行)。然而,即使“删除”选项(="Löschen")是“可见”的,也无法点击它。
似乎我只能找到表格中所有的“Löschen”选项(“删除”选项),但不能点击那个特定的“Löschen”选项,即针对特定类别“TestCategoryName”的选项。
先前描述的表格本身的代码如下:
<tbody id="the-list" data-wp-lists="list:tag">
<tr id="tag-1">...</tr>
<tr id="tag-1">...</tr>
<tr id="tag-1">...</tr>
...
<tr id="tag-1">
<th scope="row" class="check-column">...</th>
<td data-colname="Name" class="name column-name has-row-actions column-primary">
<strong>
<a href="#/projects/active?category=172" class="row-title">TestCategoryName</a>
</strong>
<div class="row-actions">
<span class="edit">
<a href="#">Bearbeiten</a> |
<a href="#">Löschen</a>
</span>
</div>
</td>
</tr>
...
</tbody>
- 类别在表格中没有真正的ID,它们通过其类别名称可识别。
- “编辑”(“Bearbeiten”)和“删除”(“Löschen”)选项并不直接“链接”到类别名称。
在调试过程中,无论我写了什么代码(我尝试过使用size(),equals,循环和其他在互联网上提供的解决方案...),我的测试在尝试“点击”“删除”选项时总是抛出异常:
下面是一个方法的草稿(当然不起作用),它想要点击特定类别的“删除”选项:
/**
* Deletes the created category.
*
* @param categoryName
*/
public void deleteNewCategory(String categoryName) {
System.out.println("--- Delete Created Category ---");
WebElement element1 = driver.findElement(By.xpath(String.format(CATEGORY_LIST_NAME, categoryName)));
WebElement element2 = driver.findElement(By.xpath(CATEGORY_DELETE_OPTION));
Actions builder = new Actions(driver);
builder.moveToElement(element1).moveToElement(element2).pause(1000).click().build().perform();
driver.switchTo().alert().accept();
}
这是Xpaths(“删除”选项的Xpath可能不够具体,可能需要一个特定的//tr):
private static final String CATEGORIES_LIST_CONTAINER = "//tbody[contains(@id, 'the-list')]";
private static final String CATEGORY_LIST_FIELD = CATEGORIES_LIST_CONTAINER + "//tr";
private static final String CATEGORY_LIST_NAME = CATEGORIES_LIST_CONTAINER + "//a[contains(text(), '%s')]";
private static final String CATEGORY_DELETE_OPTION = "//a[text()='Löschen']";
这是我的调试中的invokeMethod方法:
/**
* @see org.junit.platform.commons.support.ReflectionSupport#invokeMethod(Method, Object, Object...)
*/
public static Object invokeMethod(Method method, Object target, Object... args) {
Preconditions.notNull(method, "Method must not be null");
Preconditions.condition((target != null || isStatic(method)),
() -> String.format("Cannot invoke non-static method [%s] on a null target.", method.toGenericString()));
try {
return makeAccessible(method).invoke(target, args);
}
catch (Throwable t) {
throw ExceptionUtils.throwAsUncheckedException(getUnderlyingCause(t));
}
}
英文:
I am quite new in java and selenium and I hope to be as clear as possible.
Test Scenario:
Add a category (ex: TestCategoryName), validate creation of category, delete category, validate deletion of category.
How it works: once the category has been created, the created category will appear in an additional row at the end of a table. This table obviously contains all the created categories but each row of that table contains three elements:
- the name of the created category
- below the name of the created category, there are two hidden elements: "edit" and "delete" options. These two options are only visible when the user moves the mouse to a specific row containing one category e.g. the "category name".
PS: I can't click on the category name or else I would access another page.
My difficulty: I need to delete only one category, which is the last one created (e.g. the last row of the table). However, even though the "delete" option (="Löschen") can be "seen", it will not be clicked.
It seems I can only find all the "Löschen" options ("delete" options) of the table but I can't click on that one specific "Löschen" for that specific category "TestCategoryName".
The code itself of the previously described table looks like the following:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
<tbody id="the-list" data-wp-lists="list:tag">
<tr id="tag-1">_</tr
<tr id="tag-1">_</tr
<tr id="tag-1">_</tr
<tr id="tag-1">_</tr
<tr id="tag-1">_</tr
<tr id="tag-1">_</tr
<tr id="tag-1">_</tr
<tr id="tag-1">
<th scope="row" class="check-column">_</th>
<td data-colname="Name" class="name column-name has-row-actions column-primary">
<strong>
<a href="#/projects/active?category=172" class="row-title">TestCategoryName</a>
</strong>
<div class="row-actions">
<span class="edit">
<a href="#">Bearbeiten</a>
" |
<a href="#">Löschen</a>
</span>
</div>
</td>
<!-- end snippet -->
- the categories are listed in the table with no real ID, they are recognisable through their category name.
- the options "edit" ("Bearbeiten") and "delete" ("Löschen") are not directly "linked" to the category name.
While debugging, no matter what I code (I tried using size(), equals, loops and other solutions offered in the internet...), my test always throws an exception once it trys to "click" on the "delete" option:
here is one of the drafts of the method (not working of course) that wants to click the "delete" option of a specific category:
/**
* Deletes the created category.
*
* @param categoryName
*/
public void deleteNewCategory(String categoryName) {
System.out.println("--- Delete Created Category ---");
// int rowCount = driver.findElements(By.xpath(CATEGORY_LIST_FIELD)).size();
// int rowNumber = driver.findElements(By.xpath(String.format(CATEGORY_LIST_NAME, categoryName))).size();
WebElement element1 = driver.findElement(By.xpath(String.format(CATEGORY_LIST_NAME, categoryName)));
WebElement element2 = driver.findElement(By.xpath(CATEGORY_DELETE_OPTION));
Actions builder = new Actions(driver);
builder.moveToElement(element1).moveToElement(element2).pause(1000).click().build().perform();
driver.switchTo().alert().accept();
}
here are the Xpaths (the Xpath for the "delete" option might not be specific enough, maybe a specific //tr is needed):
private static final String CATEGORIES_LIST_CONTAINER = "//tbody[contains(@id, 'the-list')]";
private static final String CATEGORY_LIST_FIELD = CATEGORIES_LIST_CONTAINER + "//tr";
private static final String CATEGORY_LIST_NAME = CATEGORIES_LIST_CONTAINER + "//a[contains(text(), '%s')]";
private static final String CATEGORY_DELETE_OPTION = "//a[@innertext='Löschen']";
here is the invokeMethod from my debugging:
/**
* @see org.junit.platform.commons.support.ReflectionSupport#invokeMethod(Method, Object, Object...)
*/
public static Object invokeMethod(Method method, Object target, Object... args) {
Preconditions.notNull(method, "Method must not be null");
Preconditions.condition((target != null || isStatic(method)),
() -> String.format("Cannot invoke non-static method [%s] on a null target.", method.toGenericString()));
try {
return makeAccessible(method).invoke(target, args);
}
catch (Throwable t) {
throw ExceptionUtils.throwAsUncheckedException(getUnderlyingCause(t));
}
答案1
得分: 0
尝试以下XPath表达式:
//a[text()='TestCategoryName']/parent::*/following-sibling::div/span[@class='edit']//a[text()='Löschen']
英文:
try below xpath-
//a[text()='TestCategoryName']/parent::*/following-sibling::div/span[@class='edit']//a[text()='Löschen']
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论