现在有一个非常棒的arquillian-primefaces 项目,它提供了一个单线。如果你不能使用这个:
/**
* Checks a {@code p:selectBooleanCheckbox} and waits for it to be checked.
* The method works for XHTML elements only and does not check whether the
* passed {@code checkbox} is declared in XHTML.
*
* The handling of Primefaces in functional testing with Selenium/Graphene
* is extremely difficult because the behaviour of elements is not
* documented in a usable way (either extremely complex for Primefaces
* developers or not at all), so that the following behaviour has been
* extracted:<ul>
* <li>The checked state of HTML input element which is a checkbox is
* determined by the presence of the {@code checked} attribute and not its
* value. In XHTML where the attribute has to be always present its the
* value {@code checked} of the attribute .See
* {@link https://www.w3schools.com/tags/att_input_checked.asp} for details.
* </li>
* <li>The {@code checked} attribute on {@code checkbox} is always
* {@code null} and
* {@code ExpectedConditions.attributeToBe(checkbox, "checked", "")} is
* always {@code true} (Selenium doesn't document whether it distinguishes
* between {@code ""} and {@code null} and refused all suggestions on
* improving the documentation (see e.g.
* https://github.com/SeleniumHQ/selenium/issues/5649)).</li>
* <li>{@link WebElement#click() } works in a minimal environment (the
* checked state appears visually) whereas it doesn't work in most real
* world conditions.</li>
* </ul>
*
* Asked
* https://stackoverflow.com/questions/46765542/how-to-access-primefaces-components-through-graphene-in-the-most-portable-way
* for a general solution.
*
* @param browser the web driver to use
* @param checkbox the web element representing the {@code p:selectBooleanCheckbox}
* @param checked whether to check or uncheck the checkbox
*/
public void checkCheckbox(WebDriver browser,
WebElement checkbox,
boolean checked) {
assert checkbox.getAttribute("id") != null
&& !checkbox.getAttribute("id").isEmpty();
String checkboxInputId = String.format("%s_input",
checkbox.getAttribute("id"));
final WebElement checkboxInputElement = checkbox.findElements(By.xpath(String.format("id('%s')/div[2]/span",
checkbox.getAttribute("id"))))
.stream().collect(MoreCollectors.onlyElement());
if(checked && !isCheckboxChecked(browser, checkboxInputId)
|| !checked && isCheckboxChecked(browser, checkboxInputId)) {
LOGGER.trace("checkCheckbox: need to click");
LOGGER.trace(String.format("checkboxInputElement.selected: %s",
isCheckboxChecked(browser, checkboxInputId)));
checkboxInputElement.click();
LOGGER.trace(String.format("checkboxInputElement.selected: %s",
isCheckboxChecked(browser, checkboxInputId)));
//- cannot invoke `checkboxInputElement.click` because the element
//is not visible
//- cannot invoke `checkboxInputElement.isSelected` or
//`checkbox.isSelected` (causes
//org.openqa.selenium.ElementNotSelectableException)
}
new WebDriverWait(browser, 5).until(
(WebDriver t) -> {
boolean retValue0 = isCheckboxChecked(browser,
checkboxInputId) == checked;
return retValue0;
});
//waiting for the checked attribute is no guarantee that the check
//will be visible on the screenshot
}
private boolean isCheckboxChecked(WebDriver browser,
String checkboxInputId) {
boolean retValue = (Boolean) ((JavascriptExecutor)browser).executeScript(String.format("return document.getElementById('%s').checked;",
checkboxInputId));
return retValue;
}
我使用 Selenium IDE 找出了正确的元素,这可能会在所有其他类似情况下有所帮助。