如何检查 p:selectBooleanCheckbox 并等待它在 Graphene/Selenium 中检查?
How to check a p:selectBooleanCheckbox and wait for it to be checked in Graphene/Selenium?
类似于 我想知道如何在 Arquillian 和 Selenium/Graphene 的功能测试中检查 p:selectBooleanCheckbox
并等待它被检查。
我已经想通了
- 在普通 HTML 中,检查状态不是由
checked
属性的值决定的,而是由它的存在和 XHTML 中的存在决定的(属性需要始终存在)按值 checked
(不是 true
或 false
,但为什么要使新标准直观...),请参阅 https://www.w3schools.com/tags/att_input_checked.asp 了解详细信息。
- Selenium 文档在某些情况下可能会产生误导(我会说甚至是错误的)因为它不区分
""
和 null
例如在某些情况下,例如 ExpectedConditions.attributeToBe(WebElement, String, String)
并且没有提及它 - 然后改进它的请求关闭并提示 Javadoc is accepted to be wrong because everything is well documented in the W3C web driver spec.
WebElement.click
(其中 WebElement
实例指的是 p:selectBooleanCheckbox
的 ID 在最小环境中有效,但在复杂环境中无效。
在 JSF 中声明的 @FindBy(id="mainForm:mainCheckbox")
元素上用 WebElement.click
单击复选框后,当我用 Firefox 进行视觉调查时,复选框被选中:
<h:form id="mainForm">
<p:selectBooleanCheckbox id="mainCheckbox"
value="#{managedBeanView.property0}"/>
</h:form>
我试过了:
- 调查生成的
div
的 checked
属性,它总是存在(或者可能不存在,参见上面的 Selenium 文档的问题)
- 等待嵌套 HTML
_input
的 checked
属性,它显然不是 checked
属性(或者可能不是,见上文)。
现在有一个非常棒的 arquillian-primefaces project,它提供了 one-liner。如果你不能使用这个:
/**
* 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
*
* 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 找到了正确的元素,这可能会在所有其他类似情况下提供帮助。
类似于 p:selectBooleanCheckbox
并等待它被检查。
我已经想通了
- 在普通 HTML 中,检查状态不是由
checked
属性的值决定的,而是由它的存在和 XHTML 中的存在决定的(属性需要始终存在)按值checked
(不是true
或false
,但为什么要使新标准直观...),请参阅 https://www.w3schools.com/tags/att_input_checked.asp 了解详细信息。 - Selenium 文档在某些情况下可能会产生误导(我会说甚至是错误的)因为它不区分
""
和null
例如在某些情况下,例如ExpectedConditions.attributeToBe(WebElement, String, String)
并且没有提及它 - 然后改进它的请求关闭并提示 Javadoc is accepted to be wrong because everything is well documented in the W3C web driver spec. WebElement.click
(其中WebElement
实例指的是p:selectBooleanCheckbox
的 ID 在最小环境中有效,但在复杂环境中无效。
在 JSF 中声明的 @FindBy(id="mainForm:mainCheckbox")
元素上用 WebElement.click
单击复选框后,当我用 Firefox 进行视觉调查时,复选框被选中:
<h:form id="mainForm">
<p:selectBooleanCheckbox id="mainCheckbox"
value="#{managedBeanView.property0}"/>
</h:form>
我试过了:
- 调查生成的
div
的checked
属性,它总是存在(或者可能不存在,参见上面的 Selenium 文档的问题) - 等待嵌套 HTML
_input
的checked
属性,它显然不是checked
属性(或者可能不是,见上文)。
现在有一个非常棒的 arquillian-primefaces project,它提供了 one-liner。如果你不能使用这个:
/**
* 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
*
* 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 找到了正确的元素,这可能会在所有其他类似情况下提供帮助。