2

类似于为什么我可以单击 type=radio 为 ah:selectOneRadio 的输入,但不能单击 ap:selectOneRadio 和 Graphene/Selenium 之一?我想知道如何p:selectBooleanCheckbox使用 Arquillian 和 Selenium/Graphene 在功能测试中检查 a 并等待检查。

我已经想通了

  • 在纯 HTML 中,检查状态不是由checked属性的值决定的,而是由它的存在决定的,而在 XHTML(属性需要始终存在的地方)中,由值决定checked(不是trueor false,但为什么要制定一个直观的新标准。 ..),有关详细信息,请参阅https://www.w3schools.com/tags/att_input_checked.asp
  • Selenium 文档在某些情况下可能会产生误导(我什至会说是错误的),因为它没有区分""null例如在某些情况下,喜欢ExpectedConditions.attributeToBe(WebElement, String, String)并且没有提及它 - 然后改进它的请求被关闭提示Javadoc 被认为是错误的,因为所有内容都在 W3C Web 驱动程序规范中有详细记录
  • WebElement.clickWebElement实例指的p:selectBooleanCheckbox是最小环境中的作品的ID,但不是复杂环境中的作品。

在 JSF 中声明WebElement.click的元素上单击复选框后,当我使用 Firefox 进行视觉调查时,复选框被选中:@FindBy(id="mainForm:mainCheckbox")

<h:form id="mainForm">
    <p:selectBooleanCheckbox id="mainCheckbox"
                             value="#{managedBeanView.property0}"/>
</h:form>

我试过了:

  • 调查始终存在checked的生成的属性div(或者可能不存在,请参阅上面的 Selenium 文档的问题)
  • 等待checked嵌套 HTML 的属性,_input该属性checked显然不是属性(或者可能不是,见上文)。
4

1 回答 1

1

现在有一个非常棒的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 找出了正确的元素,这可能会在所有其他类似情况下有所帮助。

于 2018-04-02T20:34:23.600 回答