Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#148 Added optionalWaitUntilCondition and optionalWaitWhileCondition #191

6 changes: 6 additions & 0 deletions config/neodymium.properties
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@
#
# How long should Selenide wait between retries in case of element staleness
# neodymium.selenideAddons.staleElement.retry.timeout = 500
#
# How often should Selenide try to match a condition for optional elements
# neodymium.selenideAddons.optional.retry.count = 5
#
# How longshould Selenide wait between retries for optional elements
# neodymium.selenideAddons.optional.retry.timeout = 2000

#############################
#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ public interface NeodymiumConfiguration extends Mutable
@DefaultValue("500")
public int staleElementRetryTimeout();

@Key("neodymium.selenideAddons.optional.retry.count")
@DefaultValue("5")
public int optionalElementRetryCount();

@Key("neodymium.selenideAddons.optional.rety.timeout")
@DefaultValue("2000")
public int optionalElementRetryTimeout();

@Key("neodymium.javaScriptUtils.timeout")
@DefaultValue("2000")
public int javaScriptTimeout();
Expand Down
73 changes: 73 additions & 0 deletions src/main/java/com/xceptance/neodymium/util/SelenideAddons.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.xceptance.neodymium.util;

import static com.codeborne.selenide.Condition.not;
import static com.codeborne.selenide.Selenide.$$;
import static com.codeborne.selenide.Selenide.open;
import static com.codeborne.selenide.Selenide.sleep;
Expand Down Expand Up @@ -473,4 +474,76 @@ public static void openHtmlContentWithCurrentWebDriver(String htmlContent)
String encodedStuff = Base64.getEncoder().encodeToString(htmlContent.getBytes());
open("data:text/html;charset=utf-8;base64," + encodedStuff);
}

/**
* Waits until an optional element matches a condition. This function will return false if the element does not
* match the given condition or can not be found in the given timeframe.
* <p>
* The following settings can be configured within the Neodymium configuration to tune the retry behavior:
* </p>
* <ul>
* <li>neodymium.selenideAddons.optional.retry.count (default 5 retries)</li>
* <li>neodymium.selenideAddons.optional.retry.timeout (default 2000ms pause between retries)</li>
* </ul>
*
* @param element
* the element to match
* @param condition
* the condition for the element
* @param waitingTime
* the time to wait between retries
* @return if the element did match the condition within the given retries
*/
public static boolean optionalWaitUntilCondition(SelenideElement element, Condition condition, long waitingTime)
{
boolean result = false;
int counter = 0;
while (counter < Neodymium.configuration().optionalElementRetryCount())
{
counter++;
if (element.has(condition))
{
result = true;
break;
}
Selenide.sleep(waitingTime);
}
return result;
}

/**
* Waits while an optional element matches a condition. This function will return false if the element does match
* the given condition or can not be found after the given timeframe.
* <p>
* The following settings can be configured within the Neodymium configuration to tune the retry behavior:
* </p>
* <ul>
* <li>neodymium.selenideAddons.optional.retry.count (default 5 retries)</li>
* <li>neodymium.selenideAddons.optional.retry.timeout (default 2000ms pause between retries)</li>
* </ul>
*
* @param element
* the element to match
* @param condition
* the condition for the element
* @param waitingTime
* the time to wait between retries
* @return if the element did stop matching the condition within the given retries
*/
public static boolean optionalWaitWhileCondition(SelenideElement element, Condition condition, long waitingTime)
{
boolean result = false;
int counter = 0;
while (counter < Neodymium.configuration().optionalElementRetryCount())
{
counter++;
if (element.has(not(condition)))
{
result = true;
break;
}
Selenide.sleep(waitingTime);
}
return result;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, we can reuse the optionalWaitUntilCondition method here because not(condition) is also a condition

Suggested change
boolean result = false;
int counter = 0;
while (counter < Neodymium.configuration().optionalElementRetryCount())
{
counter++;
if (element.has(not(condition)))
{
result = true;
break;
}
Selenide.sleep(waitingTime);
}
return result;
return optionalWaitUntilCondition(element, not(condition), waitingTime);

}
}
36 changes: 36 additions & 0 deletions src/test/java/com/xceptance/neodymium/util/SelenideAddonsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import static com.codeborne.selenide.Condition.hidden;
import static com.codeborne.selenide.Condition.visible;
import static com.codeborne.selenide.Selenide.$;
import static org.junit.Assert.assertFalse;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the static imports for assertFalse and assertTrue and call the functions like

Assert.assert...

Until now we use this scheme at most of our test cases and I would like to have the same approach for similar things.

import static org.junit.Assert.assertTrue;

import java.time.Duration;
import java.util.ArrayList;
Expand All @@ -13,6 +15,7 @@
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.lang3.Range;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -640,4 +643,37 @@ public void testOpenHtmlContentWithCurrentWebDriver()
SelenideAddons.openHtmlContentWithCurrentWebDriver(textHtml);
Assert.assertEquals(text, $("body").getText());
}

@Test
public void testOptionalWaitUntil()
{
openBlogPage();
SelenideElement privaceDialog = $("#privacy-message");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

privacyDialog

boolean isVisible = SelenideAddons.optionalWaitUntilCondition(privaceDialog, visible, Neodymium.configuration().optionalElementRetryTimeout());
assertTrue("the privacy message dialog was not found within the timeframe", isVisible);
long startTime = new Date().getTime();
boolean isHidden = SelenideAddons.optionalWaitUntilCondition(privaceDialog, hidden, Neodymium.configuration().optionalElementRetryTimeout());
long endTime = new Date().getTime();
assertFalse("the privacy message dialog was unexpectedly hidden during the timeframe", isHidden);
int waitingTime = Neodymium.configuration().optionalElementRetryTimeout() * Neodymium.configuration().optionalElementRetryCount();
Assert.assertTrue("Runtime was shorter than expected", Range.between(waitingTime, waitingTime + Neodymium.configuration().optionalElementRetryTimeout())
.contains(Math.toIntExact(endTime - startTime)));
}

@Test
public void testOptionalWaitWhile()
{
openBlogPage();
SelenideElement privaceDialog = $("#privacy-message").shouldBe(visible);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

privacyDialog

long startTime = new Date().getTime();
boolean isHidden = SelenideAddons.optionalWaitWhileCondition(privaceDialog, visible, Neodymium.configuration().optionalElementRetryTimeout());
long endTime = new Date().getTime();
assertFalse("the privacy message dialog was unexpectedly during within the timeframe", isHidden);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assertFalse("the privacy message dialog was unexpectedly during within the timeframe", isHidden);
assertFalse("the privacy message dialog was unexpectedly hidden during the timeframe", isHidden);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you agree with the suggested changes? Why?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, did not see. Should be in now.

int waitingTime = Neodymium.configuration().optionalElementRetryTimeout() * Neodymium.configuration().optionalElementRetryCount();
Assert.assertTrue("Runtime was shorter than expected", Range.between(waitingTime, waitingTime + Neodymium.configuration().optionalElementRetryTimeout())
.contains(Math.toIntExact(endTime - startTime)));
privaceDialog.find(".btn-link").click();
isHidden = SelenideAddons.optionalWaitWhileCondition(privaceDialog, visible, Neodymium.configuration().optionalElementRetryTimeout());
assertTrue("the privacy message dialog remained visible during the timeframe", isHidden);
}
}