
org.omnifaces.utils.arquillian.ArquillianPrimeFaces Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of arquillian-primefaces Show documentation
Show all versions of arquillian-primefaces Show documentation
To make Arquillian - Graphene - Selenium - JUnit life easier on PrimeFaces components
The newest version!
/*
* Copyright 2018 OmniFaces
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.omnifaces.utils.arquillian;
import static org.jboss.arquillian.graphene.Graphene.guardAjax;
import static org.jboss.arquillian.graphene.Graphene.guardHttp;
import static org.jboss.arquillian.graphene.Graphene.waitForHttp;
import static org.jboss.arquillian.graphene.Graphene.waitGui;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.openqa.selenium.support.ui.ExpectedConditions.attributeContains;
import static org.openqa.selenium.support.ui.ExpectedConditions.elementToBeClickable;
import static org.openqa.selenium.support.ui.ExpectedConditions.or;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOf;
import java.io.Serializable;
import java.time.Duration;
import org.jboss.arquillian.drone.api.annotation.Default;
import org.jboss.arquillian.graphene.context.GrapheneContext;
import org.jboss.arquillian.graphene.proxy.GrapheneProxyInstance;
import org.jboss.arquillian.graphene.spi.configuration.GrapheneConfiguration;
import org.junit.Before;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
/**
*
* @author Bauke Scholtz
*/
public final class ArquillianPrimeFaces {
private ArquillianPrimeFaces() {
throw new AssertionError("This is a utility class.");
}
// Configuration ----------------------------------------------------------------------------------------------------------------------
/**
* Allows more flexible programmatic configuration as to wait timeouts.
* Graphene#guardXxx() namely doesn't support specifying custom timeouts and defaults to 2~3 seconds which may be too low sometimes.
* Best place to run this is a {@link Before} annotated method.
* @param browser The browser.
* @param timeout The timeout.
*/
public static void configureTimeouts(WebDriver browser, Duration timeout) {
while (browser instanceof GrapheneProxyInstance) {
browser = ((GrapheneProxyInstance) browser).unwrap();
}
GrapheneContext.setContextFor(new GrapheneConfiguration() {
@Override
public long getWaitAjaxInterval() {
return timeout.getSeconds();
}
@Override
public long getWaitGuardInterval() {
return timeout.getSeconds();
}
@Override
public long getWaitGuiInterval() {
return timeout.getSeconds();
}
@Override
public long getWaitModelInterval() {
return timeout.getSeconds();
}
}, browser, Default.class);
}
// General ----------------------------------------------------------------------------------------------------------------------------
/**
* Assert that given element is displayed.
* @param element The element to be checked.
*/
public static void assertPresent(WebElement element) {
try {
assertTrue(element.isDisplayed());
}
catch (NoSuchElementException e) {
fail(e.toString());
}
}
/**
* Assert that given element is not displayed.
* @param element The element to be checked.
*/
public static void assertAbsent(WebElement element) {
try {
assertFalse(element.isDisplayed());
}
catch (NoSuchElementException e) {
// Expected.
}
}
// Forms ------------------------------------------------------------------------------------------------------------------------------
/**
* Returns the parent form element associated with given form-based element.
* @param element The form-based element, e.g. form/input/select/textarea/button, anything which is inside a form.
* @return The parent form element.
*/
public static WebElement getForm(WebElement element) {
if (element.getTagName().equals("form")) {
return element;
}
else {
return getForm(getNamingContainer(element));
}
}
private static WebElement getNamingContainer(WebElement element) {
String clientId = element.getAttribute("id");
WebElement document = element.findElement(By.xpath("/*"));
return document.findElement(By.id(clientId.substring(0, clientId.lastIndexOf(':')))); // TODO: get separator character from JS.
}
/**
* Returns the view state hidden input element associated with given form-based element.
* @param element The form-based element, e.g. form/input/select/textarea/button, anything which is inside a form.
* @return The view state hidden input element associated with given form-based element.
*/
public static String getViewState(WebElement element) {
return getForm(element).findElement(By.name("javax.faces.ViewState")).getAttribute("value");
}
/**
* Assert that the given form-based element is in a stateless view.
* @param element The form-based element, e.g. form/input/select/textarea/button, anything which is inside a form.
*/
public static void assertStateless(WebElement element) {
assertEquals("stateless", getViewState(element));
}
/**
* Assert that the given form-based element is in a stateful view.
* @param element The form-based element, e.g. form/input/select/textarea/button, anything which is inside a form.
*/
public static void assertStateful(WebElement element) {
assertNotEquals("stateless", getViewState(element));
}
// Inputs -----------------------------------------------------------------------------------------------------------------------------
/**
* Returns whether given form-based element is valid.
* @param element The form-based element, e.g. form/input/select/textarea/button, anything which is inside a form.
* @return Whether given form-based element is valid.
*/
public static boolean isValid(WebElement element) {
if (element.getAttribute("class").contains("ui-state-error")) {
return false;
}
else if (element.getAttribute("class").contains("ui-state-default")) { //
return true;
}
else {
return isValid(element.findElement(By.cssSelector(".ui-state-default"))); // with special wrapping markup (e.g. inputNumber, spinner, etc)
}
}
/**
* Assert that the given form-based element is valid.
* @param element The form-based element, e.g. form/input/select/textarea/button, anything which is inside a form.
*/
public static void assertValid(WebElement element) {
assertTrue("Must be valid: " + element, isValid(element));
}
/**
* Assert that the given form-based element is invalid.
* @param element The form-based element, e.g. form/input/select/textarea/button, anything which is inside a form.
*/
public static void assertInvalid(WebElement element) {
assertFalse("Must be invalid: " + element, isValid(element));
}
/**
* Set the selected value of a p:selectOneMenu.
* @param selectOneMenu The element representing the p:selectOneMenu.
* @param value The selected value. This must match the f:selectItem value (not label!).
* @return The f:selectItem label associated with the selected value, may be useful for comparison/logging.
*/
public static String setSelectOneMenuValue(WebElement selectOneMenu, Serializable value) {
String clientId = selectOneMenu.getAttribute("id");
WebElement document = selectOneMenu.findElement(By.xpath("/*"));
WebElement input = document.findElement(By.id(clientId + "_input"));
String itemValue = value.toString();
String itemLabel = executeScript("return $(document.getElementById('" + input.getAttribute("id") + "')).find('option[value=\"" + itemValue + "\"]').text()"); // getText() doesn't work as option is hidden. It's needed because ui-selectonemenu-item doesn't have a data-value.
document.findElement(By.id(clientId + "_label")).click(); // Open panel.
WebElement panel = document.findElement(By.id(clientId + "_panel"));
WebElement selectItem = panel.findElement(By.cssSelector(".ui-selectonemenu-item[data-label='" + itemLabel + "']"));
if (input.getAttribute("onchange") != null) {
guardAjax(selectItem).click();
}
else {
selectItem.click();
}
return itemLabel;
}
/**
* Set the selected value of a p:selectOneRadio.
* @param selectOneRadio The element representing the p:selectOneRadio.
* @param value The selected value. This must match the f:selectItem value (not label!).
* @return The f:selectItem label associated with the selected value, may be useful for comparison/logging.
*/
public static String setSelectOneRadioValue(WebElement selectOneRadio, Serializable value) {
String itemValue = value.toString();
WebElement input = selectOneRadio.findElement(By.cssSelector("input[value='" + itemValue + "']"));
String itemLabel = selectOneRadio.findElement(By.cssSelector("label[for='" + input.getAttribute("id") + "']")).getText();
WebElement findElement = input.findElement(By.xpath("ancestor::div[contains(@class,'ui-radiobutton')]"));
WebElement selectItem = findElement.findElement(By.cssSelector(".ui-radiobutton-box"));
if (!selectItem.getAttribute("class").contains("ui-state-active")) {
if (input.getAttribute("onchange") != null) {
guardAjax(selectItem).click();
}
else {
selectItem.click();
}
}
return itemLabel;
}
/**
* Set the selected value of a p:selectOneButton.
* @param selectOneButton The element representing the p:selectOneButton.
* @param value The selected value. This must match the f:selectItem value (not label!).
* @return The f:selectItem label associated with the selected value, may be useful for comparison/logging.
*/
public static String setSelectOneButtonValue(WebElement selectOneButton, Serializable value) {
String itemValue = value.toString();
WebElement input = selectOneButton.findElement(By.cssSelector("input[value='" + itemValue + "']"));
WebElement selectItem = input.findElement(By.xpath("ancestor::div[contains(@class,'ui-state-default')]"));
String itemLabel = selectItem.findElement(By.cssSelector(".ui-button-text")).getText();
if (!selectItem.getAttribute("class").contains("ui-state-active")) {
selectItem.click();
}
return itemLabel;
}
/**
* Set the value of a p:inputText.
* @param inputText The element representing the p:inputText.
* @param value The input value.
*/
public static void setInputTextValue(WebElement inputText, Serializable value) {
inputText.clear();
inputText.sendKeys(value.toString());
}
/**
* Set the value of a p:inputMask.
* @param inputMask The element representing the p:inputMask.
* @param value The input value.
*/
public static void setInputMaskValue(WebElement inputMask, Serializable value) {
String clientId = inputMask.getAttribute("id");
executeScript("document.getElementById('" + clientId + "').value='" + value + "'"); // Selenium 3.7.0 bugs here with timing errors on WebElement#sendKeys(), hence JavaScript. TODO: check if it works in a newer Selenium version.
}
/**
* Set the value of a p:inputNumber.
* @param inputNumber The element representing the p:inputNumber.
* @param value The input value.
*/
public static void setInputNumberValue(WebElement inputNumber, Number value) {
String clientId = inputNumber.getAttribute("id");
WebElement input = inputNumber.findElement(By.id(clientId + "_input"));
setInputTextValue(input, String.valueOf(value));
}
/**
* Set the value of a p:spinner.
* @param spinner The element representing the p:spinner.
* @param value The input value.
*/
public static void setSpinnerValue(WebElement spinner, Number value) {
setInputNumberValue(spinner, value);
}
/**
* Set the value of a p:inputXxx having a p:slider.
* @param slider The element representing the p:inputXxx having a p:slider.
* @param value The input value.
*/
public static void setSliderValue(WebElement slider, Number value) {
setInputTextValue(slider, value);
}
/**
* Set the query of a p:autoComplete and wait for either the panel to show up or the input to be marked invalid.
* When the panel is shown up, then you can select the item value via {@link #setAutoCompleteValue(WebElement, Serializable)}.
* Alternatively, you can also use {@link #setAutoCompleteValue(WebElement, String, Serializable)} which does both in a single call.
* @param autoComplete The element representing the p:autoComplete.
* @param query The query to run auto complete for.
*/
public static void setAutoCompleteQuery(WebElement autoComplete, String query) {
setAutoCompleteQuery(autoComplete, query, true);
}
/**
* Set the query of a p:autoComplete and optionally wait for either the panel to show up or the input to be marked invalid.
* When the panel is shown up, then you can select the item value via {@link #setAutoCompleteValue(WebElement, Serializable)}.
* @param autoComplete The element representing the p:autoComplete.
* @param resultsExpected Whether immediate results are expected, i.e. the panel shows up, or the input is marked invalid.
* @param query The query to run auto complete for.
*/
public static void setAutoCompleteQuery(WebElement autoComplete, String query, boolean resultsExpected) {
String clientId = autoComplete.getAttribute("id");
WebElement input = autoComplete.findElement(By.id(clientId + "_input"));
setInputTextValue(input, query);
if (resultsExpected) {
WebElement document = autoComplete.findElement(By.xpath("/*"));
WebElement panel = document.findElement(By.id(clientId + "_panel"));
waitGui().until(or(visibilityOf(panel), attributeContains(input, "class", "ui-state-error")));
}
}
/**
* Set the selected value of a p:autoComplete.
* This should match one of the available items as returned by {@link #setAutoCompleteQuery(WebElement, String)}.
* Alternatively, you can also use {@link #setAutoCompleteValue(WebElement, String, Serializable)} which does both in a single call.
* @param autoComplete The element representing the p:autoComplete.
* @param value The selected value. This must match the item value (not label!).
* @return The label associated with the selected value, may be useful for comparison/logging.
*/
public static String setAutoCompleteValue(WebElement autoComplete, Serializable value) {
String clientId = autoComplete.getAttribute("id");
WebElement document = autoComplete.findElement(By.xpath("/*"));
WebElement panel = document.findElement(By.id(clientId + "_panel"));
waitGui().until(visibilityOf(panel));
WebElement selectItem = panel.findElement(By.cssSelector("[data-item-value='" + value + "']"));
String itemLabel = selectItem.getAttribute("data-item-label");
selectItem.click();
return itemLabel;
}
/**
* Set the query and then the selected value of a p:autoComplete.
* @param autoComplete The element representing the p:autoComplete.
* @param query The query to run auto complete for.
* @param value The selected value. This must match the item value (not label!).
* @return The label associated with the selected value, may be useful for comparison/logging.
*/
public static String setAutoCompleteValue(WebElement autoComplete, String query, Serializable value) {
setAutoCompleteQuery(autoComplete, query);
return setAutoCompleteValue(autoComplete, value);
}
/**
* Set the checked state of a p:selectBooleanCheckbox.
* @param selectBooleanCheckbox The element representing the p:selectBooleanCheckbox.
* @param checked The checked state.
*/
public static void setSelectBooleanCheckboxChecked(WebElement selectBooleanCheckbox, boolean checked) {
WebElement box = selectBooleanCheckbox.findElement(By.cssSelector(".ui-chkbox-box"));
if (box.getAttribute("class").contains("ui-state-active")) {
if (!checked) {
box.click();
}
}
else if (checked) {
box.click();
}
}
// Commands ---------------------------------------------------------------------------------------------------------------------------
/**
* Click a p:commandLink.
* @param commandLink The element representing the p:commandLink.
*/
public static void clickCommandLink(WebElement commandLink) {
clickCommandElement(commandLink, false);
}
/**
* Click a p:commandLink which is expected to perform a HTTP redirect.
* @param commandLink The element representing the p:commandLink.
*/
public static void clickCommandLinkWithRedirect(WebElement commandLink) {
clickCommandElement(commandLink, true);
}
/**
* Click a p:commandButton.
* @param commandButton The element representing the p:commandButton.
*/
public static void clickCommandButton(WebElement commandButton) {
clickCommandElement(commandButton, false);
}
/**
* Click a p:commandButton which is expected to perform a HTTP redirect.
* @param commandButton The element representing the p:commandButton.
*/
public static void clickCommandButtonWithRedirect(WebElement commandButton) {
clickCommandElement(commandButton, true);
}
private static void clickCommandElement(WebElement command, boolean redirectExpected) {
waitGui().until(elementToBeClickable(command));
if (redirectExpected) {
waitForHttp(command).click();
}
else if (command.getAttribute("onclick") != null && command.getAttribute("onclick").contains("PrimeFaces.ab")) {
guardAjax(command).click();
}
else {
guardHttp(command).click();
}
}
// Links ------------------------------------------------------------------------------------------------------------------------------
/**
* Click a p:link.
* @param link The element representing the p:link.
*/
public static void clickLink(WebElement link) {
waitGui().until(elementToBeClickable(link));
if ("_blank".equals(link.getAttribute("target"))) {
link.click();
}
else {
guardHttp(link).click();
}
}
/**
* Click a p:button.
* @param button The element representing the p:button.
*/
public static void clickButton(WebElement button) {
waitGui().until(elementToBeClickable(button));
String onclick = button.getAttribute("onclick");
if (!onclick.startsWith("window.open") || onclick.endsWith("'_blank')")) {
button.click();
}
else {
guardHttp(button).click();
}
}
// Helpers ----------------------------------------------------------------------------------------------------------------------------
@SuppressWarnings("unchecked")
private static T executeScript(String script) {
JavascriptExecutor browser = (JavascriptExecutor) GrapheneContext.getContextFor(Default.class).getWebDriver();
return (T) browser.executeScript(script);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy