Skip to content
This repository has been archived by the owner on Nov 23, 2021. It is now read-only.

288 bobcatwait reworked #291

Merged
merged 11 commits into from
Oct 3, 2018
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@

/**
* Class contains custom ExpectedConditions for explicit waiting (provided by BobcatWait)
*
* @deprecated to be removed in 2.0; use methods from {@link org.openqa.selenium.support.ui.ExpectedConditions} or {@link com.cognifide.qa.bb.webelement.WebElementConditions}
*/
@Deprecated
public final class CommonExpectedConditions {

private static final Logger LOG = LoggerFactory.getLogger(CommonExpectedConditions.class);
Expand All @@ -56,9 +59,9 @@ public static ExpectedCondition<Boolean> elementNotPresent(final By bySelector)
/**
* Check if element has attribute with provided value
*
* @param attributeName name of the attribute
* @param attributeName name of the attribute
* @param attributeValue value of the attribute
* @param element WebElement to check
* @param element WebElement to check
* @return true if element has attribute with provided value
*/
public static ExpectedCondition<Boolean> elementHasAttributeWithValue(final WebElement element,
Expand All @@ -71,7 +74,7 @@ public static ExpectedCondition<Boolean> elementHasAttributeWithValue(final WebE
* Check if element located by specified By locator exists in DOM in an
* element's context
*
* @param scope scope in which element will be searched for
* @param scope scope in which element will be searched for
* @param locator {@link By} locator of the searched element
* @return false if element does not exist or WebDriver is null
*/
Expand Down Expand Up @@ -102,7 +105,7 @@ public static ExpectedCondition<Boolean> elementNotPresentOrVisible(final By byS
/**
* Check if provided element height is greater than expected height
*
* @param element - WebElement to check
* @param element - WebElement to check
* @param expectedHeight - expected height of an element
* @return true if element height is greater than expected
*/
Expand All @@ -115,7 +118,7 @@ public static ExpectedCondition<Boolean> heightOfElementGreaterThan(final WebEle
* List of WebElements found in provided scope using provided locator is
* constant
*
* @param element WebElement to set scope for elements finder
* @param element WebElement to set scope for elements finder
* @param byElement By selector
* @return true if list of WebElements is the same after one second
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@

import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;

/**
* Class contains custom ExpectedConditions for testing current URL
*
* @deprecated use methods from {@link ExpectedConditions}
*/
@Deprecated
public final class UrlExpectedConditions {

private UrlExpectedConditions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@

/**
* This is an utility class that extends Selenium's wait functionality. If you need wait/until replacement,
* inject instance of this class into your PageObject. If you only need "sleep" function, call it directly
* from BobcatWait statically, because "sleep" is static.
* inject instance of this class into your PageObject.
* <p>
* This class serves as a factory for BobcatWebDriverWait instances.
*
* @deprecated moved under {@link com.cognifide.qa.bb.wait.BobcatWait}
*/
@Deprecated
public class BobcatWait {

private static final Logger LOG = LoggerFactory.getLogger(BobcatWait.class);
Expand All @@ -52,18 +54,9 @@ public class BobcatWait {
private WebDriverProvider webDriverProvider;

/**
* This is a wrapper method for Thread's sleep method.
* <p>
* It catches and logs InterruptedException thrown from original sleep method,
* so the user doesn't need to bother with writing a try-catch block.
* <p>
* Use this method only if you can't use "withTimeout" (which is more flexible).
* <p>
* If you don't use "withTimeout", call "sleep" directly from BobcatWait,
* without creating an instance.
*
* @param durationInSec Thread will sleep for durationInSec seconds.
* @deprecated it's 2018, don't use sleeps in your tests :)
*/
@Deprecated
public static void sleep(double durationInSec) {
try {
TimeUnit.MILLISECONDS.sleep((long) (durationInSec * 1000));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
/**
* This class performs actual wait. It should always be used with BobcatWait class which acts as a factory for
* BobcatWebDriverWait.
*
* @deprecated will be removed in 2.0
*/
@Deprecated
public class BobcatWebDriverWait {

private static final int IMPLICITLY_WAIT_TIME = 1;
Expand Down Expand Up @@ -88,7 +91,8 @@ public <T> T until(ExpectedCondition<T> condition) {
*/
public <T> T until(ExpectedCondition<T> condition, long delay) {
webDriver.manage().timeouts().implicitlyWait(IMPLICITLY_WAIT_TIME, TimeUnit.SECONDS);
final T result = new WebDriverWait(webDriver, timeOutInSeconds, delay * 1000L).until(condition::apply);
final T result =
new WebDriverWait(webDriver, timeOutInSeconds, delay * 1000L).until(condition::apply);
webDriver.manage().timeouts().implicitlyWait(defaultTimeout, TimeUnit.SECONDS);
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* 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.
Expand All @@ -25,6 +25,7 @@
import org.openqa.selenium.WebDriver;

import com.cognifide.qa.bb.guice.ThreadScoped;
import com.cognifide.qa.bb.wait.BobcatWait;
import com.google.inject.Inject;

/**
Expand All @@ -38,7 +39,7 @@ public final class BrowserTabsHelper {
private WebDriver webDriver;

@Inject
private WebElementUtils webElementUtils;
private BobcatWait bobcatWait;

/**
* Checks if expected tabs count is opened with timeout defined in
Expand All @@ -48,7 +49,7 @@ public final class BrowserTabsHelper {
* @return value indicating if expected tabs count is opened.
*/
public boolean isExpectedTabsCountOpened(int tabsCount) {
return webElementUtils.isConditionMet(driver -> getOpenedTabsCount() == tabsCount);
return bobcatWait.isConditionMet(driver -> getOpenedTabsCount() == tabsCount);
}

/**
Expand Down Expand Up @@ -77,8 +78,8 @@ public void switchToPreviousTab() {
}

/**
* Switches to the browser tab with specified index offset from active tab. If resulting index
* exceeds the index of first or last tab counting continues from another end.
* Switches to the browser tab with specified index offset from active tab. If resulting index
* exceeds the index of first or last tab counting continues from another end.
*
* @param tabOffset tab index offset from active tab.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@
*/
package com.cognifide.qa.bb.utils;

import static org.openqa.selenium.support.ui.ExpectedConditions.not;
import static org.openqa.selenium.support.ui.ExpectedConditions.textToBePresentInElement;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOf;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfAllElements;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;
import static org.openqa.selenium.support.ui.ExpectedConditions.*;

import java.util.ArrayDeque;
import java.util.Deque;
Expand All @@ -41,13 +37,17 @@
import com.cognifide.qa.bb.constants.Timeouts;
import com.cognifide.qa.bb.guice.ThreadScoped;
import com.cognifide.qa.bb.provider.selenium.BobcatWait;
import com.cognifide.qa.bb.webelement.WebElementConditions;
import com.google.inject.Inject;

/**
* This class contains utility methods for checking with waits if WebElements are meeting different
* conditions.
*
* @deprecated use {@link WebElementConditions} together with {@link com.cognifide.qa.bb.wait.BobcatWait}
*/
@ThreadScoped
@Deprecated
public final class WebElementUtils {

private static final Logger LOG = LoggerFactory.getLogger(WebElementUtils.class);
Expand Down
120 changes: 120 additions & 0 deletions bb-core/src/main/java/com/cognifide/qa/bb/wait/BobcatWait.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*-
* #%L
* Bobcat
* %%
* Copyright (C) 2016 Cognifide Ltd.
* %%
* 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.
* #L%
*/
package com.cognifide.qa.bb.wait;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cognifide.qa.bb.guice.ThreadScoped;
import com.google.inject.Inject;

/**
* This is the go-to solution for handling dynamic elements with Bobcat.
* It is based on the {@link org.openqa.selenium.support.ui.WebDriverWait} mechanism.
*/
@ThreadScoped
public class BobcatWait {

private static final Logger LOG = LoggerFactory.getLogger(BobcatWait.class);

@Inject
private WebDriver webDriver;

private Timings timings = new TimingsBuilder().build();

private List<Class<? extends Throwable>> ignoredExceptions = new ArrayList<>();

/**
* Allows to customize the timings (explicit & implicit timeout + polling time).
*
* @param timings a {@link Timings} instance - use the {@link TimingsBuilder} to create one
* @return a self reference
* @see Timings
*/
public BobcatWait tweak(Timings timings) {
this.timings = timings;
return this;
}

/**
* Adds a list of exception to be ignored during condition evaluation
*
* @param exceptions list of exceptions to be ignored
* @return a self reference
* @see org.openqa.selenium.support.ui.FluentWait#ignoreAll(Collection)
*/
public BobcatWait ignoring(List<Class<? extends Throwable>> exceptions) {
ignoredExceptions.addAll(exceptions);
return this;
}

/**
* This method enhances Selenium's "until" method.
* First it reduces implicit timeout to a near-zero value.
* Then a timer is started and the condition is checked cyclically until it is fulfilled
* or the timer times out. Finally, implicit timeout is set back to the value
* defined in the property file (under "wait.implicitTimeout").
*
* @param condition Selenium's condition object that is queried cyclically inside the wait loop.
* @param <T> The function's expected return type.
* @return The ExpectedCondition's return value if the function returned something different.
* from null or false before the timeout expired.
* @see WebDriverWait#until(Function)
*/
public <T> T until(ExpectedCondition<T> condition) {
webDriver.manage().timeouts().implicitlyWait(Timings.NEAR_ZERO, TimeUnit.SECONDS);
final T result = getWebDriverWait()
.ignoreAll(ignoredExceptions)
.until(condition);
webDriver.manage().timeouts().implicitlyWait(timings.getImplicitTimeout(), TimeUnit.SECONDS);
return result;
}

/**
* Checks if the provided condition is met.
*
* @param condition condition to be checked
* @return boolean indicating if condition is met
*/
public boolean isConditionMet(final ExpectedCondition<?> condition) {
try {
until(condition);
} catch (TimeoutException | StaleElementReferenceException e) {
LOG.debug("{} condition has not been met before timeout ", condition, e);
return false;
}
return true;
}

private WebDriverWait getWebDriverWait() {
return new WebDriverWait(webDriver, timings.getExplicitTimeout(), timings.getPollingTime());
}
}
56 changes: 56 additions & 0 deletions bb-core/src/main/java/com/cognifide/qa/bb/wait/Timings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*-
* #%L
* Bobcat
* %%
* Copyright (C) 2018 Cognifide Ltd.
* %%
* 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.
* #L%
*/
package com.cognifide.qa.bb.wait;

/**
* A value object defining the set of timings used in {@link BobcatWait}.
* Use {@link TimingsBuilder} to create instances of this class.
* <p>
* Contains info about:
* <ul>
* <li>explicit timeout</li>
* <li>implicit timeout</li>
* <li>polling time</li>
* </ul>
*/
public class Timings {
public static final int NEAR_ZERO = 1;
private long explicitTimeout;
private long pollingTime;
private long implicitTimeout;

public Timings(long explicitTimeout, long pollingTime, long implicitTimeout) {
this.explicitTimeout = explicitTimeout;
this.pollingTime = pollingTime;
this.implicitTimeout = implicitTimeout;
}

public long getExplicitTimeout() {
return explicitTimeout;
}

public long getPollingTime() {
return pollingTime;
}

public long getImplicitTimeout() {
return implicitTimeout;
}
}
Loading