Skip to content

Commit

Permalink
Added timeouts to Ensures
Browse files Browse the repository at this point in the history
  • Loading branch information
wakaleo committed May 22, 2019
1 parent 175dd43 commit cab543a
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 165 deletions.

This file was deleted.

Expand Up @@ -238,7 +238,7 @@ public void should_timeout_if_takes_too_long() {
}


@Test(expected = IllegalArgumentException.class)
@Test(expected = TimeoutException.class)
public void should_check_that_condition_is_a_boolean_function() {
SlowPage page = new SlowPage(driver);

Expand Down
Expand Up @@ -6,7 +6,6 @@ import net.serenitybdd.screenplay.ensure.GrammaticalNumber.PLURAL
import net.serenitybdd.screenplay.ensure.GrammaticalNumber.SINGULAR
import net.serenitybdd.screenplay.ensure.collections.CollectionsComparison
import net.serenitybdd.screenplay.ensure.web.NamedExpectation
import net.serenitybdd.screenplay.questions.NamedPredicate

class CollectionEnsure<A>(val value: KnowableValue<Collection<A>?>,
private val targetDescription: String = "a collection",
Expand Down
@@ -1,25 +1,12 @@
package net.serenitybdd.screenplay.ensure.web

import net.serenitybdd.core.pages.WebElementFacade
import net.serenitybdd.screenplay.Actor
import net.serenitybdd.screenplay.ensure.KnowableValue
import org.openqa.selenium.By

class NamedExpectation<A>(val description: String, val predicate: (A) -> Boolean)

class KnownWebElementValue<A>(val value: A?, val description: String) : KnowableValue<A> {
override fun invoke(actor: Actor): A? = value
override fun toString() = description
}

class TheMatchingElement {

fun textValueOf(element: WebElementFacade): KnowableValue<String?> {
return object : KnowableValue<String?> {
override fun invoke(actor: Actor): String? = element.text
}
}

companion object {
@JvmStatic
fun isDisplayed() = NamedExpectation("is displayed", { it: WebElementFacade -> it.isDisplayed })
Expand Down
Expand Up @@ -11,6 +11,7 @@ import net.thucydides.core.annotations.DefaultUrl
import net.thucydides.core.steps.BaseStepListener
import net.thucydides.core.steps.StepEventBus
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Assertions.assertTimeout
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
Expand All @@ -20,6 +21,10 @@ import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.chrome.ChromeOptions
import java.nio.file.Files
import java.nio.file.Path
import java.time.Duration
import java.time.Duration.ofMinutes
import java.time.Duration.ofSeconds


@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class WhenUsingFluentAssertionsWithWebElementLocators {
Expand Down Expand Up @@ -208,7 +213,7 @@ class WhenUsingFluentAssertionsWithWebElementLocators {
shouldFailWithMessage("""|Expecting web element located by #heading with text value that is in: <[Wrong Heading, Another Wrong One]>
|But got.............................................................: <"Heading">"""
.trimMargin())
.whenChecking(that(ElementLocated.by("#heading")).text().isIn("Wrong Heading","Another Wrong One"), wendy)
.whenChecking(that(ElementLocated.by("#heading")).text().isIn("Wrong Heading", "Another Wrong One"), wendy)
}

@Test
Expand Down Expand Up @@ -346,6 +351,29 @@ class WhenUsingFluentAssertionsWithWebElementLocators {
shouldPassWhenChecking(that(ElementLocated.by("#stations")).containsElements(By.cssSelector(".station")), wendy)
}
}

@Nested
inner class IsDisplayedAfterADelay {

@Test
fun `when the element is on the page`() {
val aSlowDisplayingField: Target = ElementLocated.by(By.id("city"))
.waitingForNoMoreThan(Duration.ofSeconds(2))

shouldPassWhenChecking(that(aSlowDisplayingField).isDisplayed(), wendy)
}

@Test()
fun `when the element is not on the page`() {
val aMissingField: Target = ElementLocated.by(By.id("missing-field"))
.waitingForNoMoreThan(Duration.ofSeconds(1))

assertTimeout(ofSeconds(3)) {
shouldFailWhenChecking(that(aMissingField).isDisplayed(), wendy)
}
}

}
}

@Nested
Expand All @@ -366,26 +394,26 @@ class WhenUsingFluentAssertionsWithWebElementLocators {

@Test
fun `that have a certain number of elements`() {
shouldPassWhenChecking(thatTheSetOf(ElementsLocated.by(".station")).hasSize(3), wendy)
shouldPassWhenChecking(thatTheSetOf(ElementsLocated.by(By.cssSelector(".station"))).hasSize(3), wendy)
}

@Test
fun `that all match a predicate`() {
val isDisplayed = {it : WebElementFacade -> it.isDisplayed}
val isDisplayed = { it: WebElementFacade -> it.isDisplayed }

shouldPassWhenChecking(thatAmongst(ElementsLocated.by(".station")).allMatch("is displayed", isDisplayed), wendy)
shouldPassWhenChecking(thatAmongst(ElementsLocated.by(Target.the("list of stations").locatedBy(".station"))).allMatch("is displayed", isDisplayed), wendy)
}

@Test
fun `where some match a predicate`() {
val isDisplayed = {it : WebElementFacade -> it.isDisplayed}
val isDisplayed = { it: WebElementFacade -> it.isDisplayed }

shouldPassWhenChecking(thatAmongst(ElementsLocated.by(".station")).atLeast(2, "is displayed", isDisplayed), wendy)
}

@Test
fun `that fails to match a predicate`() {
val isDisplayed = {it : WebElementFacade -> it.isDisplayed}
val isDisplayed = { it: WebElementFacade -> it.isDisplayed }

shouldFailWhenChecking(thatAmongst(ElementsLocated.by(".station")).noMoreThan(1, "is displayed", isDisplayed), wendy)
}
Expand All @@ -397,7 +425,7 @@ class WhenUsingFluentAssertionsWithWebElementLocators {

@Test
fun `that no elements are displayed`() {
shouldPassWhenChecking(thatTheSetOf(ElementsLocated.by(".hidden-station")).noneMatch(TheMatchingElement.isDisplayed()), wendy)
shouldPassWhenChecking(thatAmongst(ElementsLocated.by(".hidden-station")).noneMatch(TheMatchingElement.isDisplayed()), wendy)
}

@Test
Expand Down
32 changes: 31 additions & 1 deletion serenity-ensure/src/test/resources/static-site/index.html
Expand Up @@ -3,8 +3,37 @@
<head>
<meta charset="UTF-8">
<title>Test Page</title>

<script type="text/javascript">
<!--

function initFields() {
hide('city')
displayFieldsAfterDelay();
}

function hide(id) {
var e = document.getElementById(id);
e.style.display = 'none';
}

function show(id) {
var e = document.getElementById(id);
e.style.display = 'block';
}

function displayCityField() {
show('city')
}

function displayFieldsAfterDelay() {
setTimeout("displayCityField()", 1000);
}

//-->
</script>
</head>
<body>
<body onLoad="initFields()">

<h3>Text and text content</h3>
<p id="block-of-text">
Expand All @@ -25,6 +54,7 @@ <h1 id="heading">Heading</h1>
<option value="yellow">Yellow</option>
<option value="purple">Purple</option>
</select>
<input id="city">
</form>
<div id="stations">
<div class="station">Canary Wharf</div>
Expand Down
Expand Up @@ -8,6 +8,7 @@
import org.openqa.selenium.By;
import org.openqa.selenium.remote.RemoteWebDriver;

import java.time.Duration;
import java.util.List;
import java.util.Optional;

Expand All @@ -28,12 +29,38 @@ public ByTarget(String targetElementName, By androidLocator, By iosLocator, Opti
this.iosLocator = iosLocator;
}

public ByTarget(String targetElementName, By androidLocator, By iosLocator, Optional<IFrame> iFrame, Optional<Duration> timeout) {
super(targetElementName, iFrame, timeout);
this.androidLocator = androidLocator;
this.iosLocator = iosLocator;
}


protected ByTarget(String targetElementName, By locator, By androidLocator, By iosLocator, Optional<IFrame> iFrame, Optional<Duration> timeout) {
super(targetElementName, iFrame, timeout);
this.locator = locator;
this.androidLocator = androidLocator;
this.iosLocator = iosLocator;
}

public WebElementFacade resolveFor(Actor actor) {
return TargetResolver.create(BrowseTheWeb.as(actor).getDriver(), this).find(getLocatorForPlatform(actor));
TargetResolver resolver = TargetResolver.create(BrowseTheWeb.as(actor).getDriver(), this);
if (timeout.isPresent()) {
return resolver.withTimeoutOf(timeout.get()).find(getLocatorForPlatform(actor));
} else {
return resolver.find(getLocatorForPlatform(actor));
}
// return TargetResolver.create(BrowseTheWeb.as(actor).getDriver(), this).find(getLocatorForPlatform(actor));
}

public List<WebElementFacade> resolveAllFor(Actor actor) {
return TargetResolver.create(BrowseTheWeb.as(actor).getDriver(), this).findAll(getLocatorForPlatform(actor));
TargetResolver resolver = TargetResolver.create(BrowseTheWeb.as(actor).getDriver(), this);
if (timeout.isPresent()) {
return resolver.withTimeoutOf(timeout.get()).findAll(getLocatorForPlatform(actor));
} else {
return resolver.findAll(getLocatorForPlatform(actor));
}
// return TargetResolver.create(BrowseTheWeb.as(actor).getDriver(), this).findAll(getLocatorForPlatform(actor));
}

public XPathOrCssTarget of(String... parameters) {
Expand Down Expand Up @@ -71,7 +98,12 @@ public String getCssOrXPathSelector() {
throw new UnsupportedOperationException("The getCssOrXPathSelector() method is not supported for By-type Targets");
}

@Override
public Target waitingForNoMoreThan(Duration timeout) {
return new ByTarget(targetElementName, locator, androidLocator, iosLocator, iFrame, Optional.ofNullable(timeout));
}

public ByTarget called(String name) {
return new ByTarget(name, locator, iFrame);
return new ByTarget(targetElementName, locator, androidLocator, iosLocator, iFrame, timeout);
}
}

0 comments on commit cab543a

Please sign in to comment.