Skip to content

Commit

Permalink
Added some improvements to the features
Browse files Browse the repository at this point in the history
  • Loading branch information
wakaleo committed Jun 23, 2019
1 parent d5a9c80 commit 39af150
Show file tree
Hide file tree
Showing 15 changed files with 458 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,26 @@ class CollectionEnsure<A>(val value: KnowableValue<Collection<A>?>,

fun atLeast(n: Int, expectation: NamedExpectation<A>) = atLeast(n, expectation.description, expectation.predicate)

/**
* Verifies that at least _n_ elements in a collection that match a given predicate
* @param predicateDescription A short description of the predicate, to appear in error messages
* @param predicate A predicate operating on the elements of the collection
*/
fun exactly(n: Int, predicateDescription: String, predicate: (A) -> Boolean): PerformablePredicate<KnowableValue<Collection<A>>> {
val number: GrammaticalNumber = if (n == 1) SINGULAR else PLURAL
val elements = if (n == 1) "element" else "elements"
return PerformablePredicate(value,
containsExactlyElementsThatMatch(n, "exactly $n $elements",
number,
IS_ARE,
predicateDescription,
predicate),
isNegated(),
targetDescription)
}

fun exactly(n: Int, expectation: NamedExpectation<A>) = exactly(n, expectation.description, expectation.predicate)

/**
* Verifies that no more than _n_ elements in a collection that match a given predicate
* @param predicateDescription A short description of the predicate, to appear in error messages
Expand Down Expand Up @@ -594,4 +614,21 @@ class CollectionEnsure<A>(val value: KnowableValue<Collection<A>?>,
predicateNumber
)

private fun containsExactlyElementsThatMatch(n: Int,
overallDescription: String,
predicateNumber: GrammaticalNumber,
qualifier: ElementQualifier,
predicateDescription: String,
predicate: (A) -> Boolean) = expectThatActualContainsElementsThat(
overallDescription,
fun(actor: Actor?, actual: KnowableValue<Collection<A>>?): Boolean {
if (actual == null) return false
val actualValue = actual(actor!!) ?: return false
BlackBox.logAssertion(actualValue, null)
return actualValue.filter(predicate).size == n
},
predicateDescription,
qualifier,
predicateNumber
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,13 @@ open class CommonEnsure<A, E>(open val value: KnowableValue<A>,

fun asAString() = StringEnsure(KnowableStringValue(value, expectedDescription), expectedDescription)
fun asAnInteger() = ComparableEnsure(KnowableIntValue(value, expectedDescription), null, expectedDescription)
fun asADouble() = ComparableEnsure(KnowableDoubleValue(value, expectedDescription), null, expectedDescription)
fun asAFloat() = ComparableEnsure(KnowableFloatValue(value, expectedDescription), null, expectedDescription)
fun asADouble() = DoubleEnsure.fromKnowable(KnowableDoubleValue(value, expectedDescription))
fun asAFloat() = FloatEnsure.fromKnowable(KnowableFloatValue(value, expectedDescription))
fun asABigDecimal() = ComparableEnsure(KnowableBigDecimalValue(value, expectedDescription), null, expectedDescription)
fun asADate() = DateEnsure(KnowableLocalDateValue(value, expectedDescription), naturalOrder<LocalDate>())
fun asADate() = DateEnsure(KnowableLocalDateValue(value, expectedDescription), naturalOrder())
fun asADate(format: String) = DateEnsure(KnowableLocalDateValue(value, expectedDescription, format), naturalOrder())
fun asATime() = TimeEnsure(KnowableLocalTimeValue(value, expectedDescription), naturalOrder())
fun asATime(format: String) = TimeEnsure(KnowableLocalTimeValue(value, expectedDescription, format), naturalOrder())
fun asABoolean() = BooleanEnsure(KnowableBooleanValue(value, expectedDescription))

private val IS_EQUAL_TO = expectThatActualIs("equal to",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.serenitybdd.screenplay.ensure

import net.serenitybdd.screenplay.Actor


class DoubleEnsure(override val value: KnowableValue<Double?>, comparator: Comparator<Double>) : ComparableEnsure<Double>(value, comparator) {

companion object {
fun fromKnowable(value: KnowableValue<Double?>) : DoubleEnsure = DoubleEnsure(value, naturalOrder<Double>())
}

constructor(value: Double?) : this(KnownValue<Double?>(value, value.toString()), naturalOrder<Double>())

/**
* Verifies that the actual {@code LocalDate} is before a specified date
*/
fun isCloseTo(expected: Double, margin: Double) = PerformableExpectation(value, within(margin), expected, isNegated())
override fun not(): DoubleEnsure = negate() as DoubleEnsure
override fun silently(): DoubleEnsure = silently() as DoubleEnsure

fun within(margin: Double) = expectThatActualIs("close to(within a margin of " + margin + ")",
fun(actor: Actor?, actual: KnowableValue<Double?>?, expected: Double): Boolean {
CommonPreconditions.ensureActualNotNull(actual)
val actualValue = actual!!(actor!!) ?: return false
return actualValue >= (expected - margin) && actualValue <= (expected + margin)
})
}

Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ import net.serenitybdd.screenplay.ensure.web.TargetEnsure
import net.serenitybdd.screenplay.targets.Target
import org.openqa.selenium.By
import java.time.LocalDate
import java.time.LocalTime

fun that(value: String?) = StringEnsure(value)
fun that(value: LocalDate?) = DateEnsure(value)
fun that(value: LocalTime?) = TimeEnsure(value)
fun that(value: Boolean?) = BooleanEnsure(value)
fun that(value: Float?) = FloatEnsure(value)
fun that(value: Double?) = DoubleEnsure(value)
fun <A> that(value: Comparable<A>) = ComparableEnsure(value)
fun <A> that(value: Collection<A>?) = CollectionEnsure(value)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.serenitybdd.screenplay.ensure

import net.serenitybdd.screenplay.Actor


class FloatEnsure(override val value: KnowableValue<Float?>, comparator: Comparator<Float>) : ComparableEnsure<Float>(value, comparator) {

constructor(value: Float?) : this(KnownValue<Float?>(value, value.toString()), naturalOrder<Float>())

companion object {
fun fromKnowable(value: KnowableValue<Float?>) : FloatEnsure = FloatEnsure(value, naturalOrder<Float>())
}

/**
* Verifies that the actual {@code LocalDate} is before a specified date
*/
fun isCloseTo(expected: Float, margin: Float) = PerformableExpectation(value, within(margin), expected, isNegated())
override fun not(): FloatEnsure = negate() as FloatEnsure
override fun silently(): FloatEnsure = silently() as FloatEnsure

private fun within(margin: Float) = expectThatActualIs("close to (within a margin of " + margin + ")",
fun(actor: Actor?, actual: KnowableValue<Float?>?, expected: Float): Boolean {
CommonPreconditions.ensureActualNotNull(actual)
val actualValue = actual!!(actor!!) ?: return false
return actualValue >= (expected - margin) && actualValue <= (expected + margin)
})
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ package net.serenitybdd.screenplay.ensure
import net.serenitybdd.core.pages.WebElementFacade
import net.serenitybdd.screenplay.Actor
import net.serenitybdd.screenplay.Question
import net.serenitybdd.screenplay.questions.EnumValues
import net.serenitybdd.screenplay.targets.Target
import org.openqa.selenium.By
import java.math.BigDecimal
import java.time.LocalDate
import java.time.LocalTime
import java.time.format.DateTimeFormatter


typealias KnowableValue<A> = (Actor) -> A?
Expand Down Expand Up @@ -36,12 +39,30 @@ class KnowableBigDecimalValue<A>(val value : KnowableValue<A>, val description:
override fun toString() = description
}

class KnowableLocalDateValue<A>(val value : KnowableValue<A>, val description: String) : KnowableValue<LocalDate?> {
class KnowableLocalDateValue<A>(val value : KnowableValue<A>, val description: String, val format: String? = null) : KnowableValue<LocalDate?> {
override fun invoke(actor: Actor): LocalDate? {
val resolvedValue = value(actor)
return if (resolvedValue is LocalDate) resolvedValue else LocalDate.parse(resolvedValue.toString())
return if (resolvedValue is LocalDate) resolvedValue else parsedDateFor(resolvedValue.toString())
}
override fun toString() = description

private fun parsedDateFor(dateValue: String) : LocalDate {
val formatter = if (format != null) DateTimeFormatter.ofPattern(format) else DateTimeFormatter.ISO_LOCAL_DATE
return LocalDate.parse(dateValue, formatter)
}
}

class KnowableLocalTimeValue<A>(val value : KnowableValue<A>, val description: String, val format: String? = null) : KnowableValue<LocalTime?> {
override fun invoke(actor: Actor): LocalTime? {
val resolvedValue = value(actor)
return if (resolvedValue is LocalTime) resolvedValue else parsedTimeFor(resolvedValue.toString())
}
override fun toString() = description

private fun parsedTimeFor(dateValue: String) : LocalTime {
val formatter = if (format != null) DateTimeFormatter.ofPattern(format) else DateTimeFormatter.ISO_LOCAL_TIME
return LocalTime.parse(dateValue, formatter)
}
}

class KnowableBooleanValue<A>(val value : KnowableValue<A>, val description: String) : KnowableValue<Boolean?> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package net.serenitybdd.screenplay.ensure

import net.serenitybdd.screenplay.Actor
import net.serenitybdd.screenplay.ensure.CommonPreconditions.ensureActualAndActorNotNull

import java.time.DayOfWeek
import java.time.LocalTime
import java.time.Month


class TimeEnsure(override val value: KnowableValue<LocalTime?>, comparator: Comparator<LocalTime>) : ComparableEnsure<LocalTime>(value, comparator) {

constructor(value: LocalTime?) : this(KnownValue<LocalTime?>(value, value.toString()), naturalOrder<LocalTime>())

/**
* Verifies that the actual {@code LocalTime} is before a specified date
*/
fun isBefore(expected: LocalTime) = PerformableExpectation(value, BEFORE, expected, isNegated())

/**
* Verifies that the actual {@code LocalTime} is after a specified date
*/
fun isAfter(expected: LocalTime) = PerformableExpectation(value, AFTER, expected, isNegated())

override fun not(): TimeEnsure = negate() as TimeEnsure
override fun silently(): TimeEnsure = silently() as TimeEnsure

override fun usingComparator(comparator: Comparator<LocalTime>): TimeEnsure {
return TimeEnsure(value, comparator)
}

companion object {

val BEFORE = expectThatActualIs("before",
fun(actor: Actor?, actual: KnowableValue<LocalTime?>?, expected: LocalTime): Boolean {
ensureActualAndActorNotNull(actual, actor)
val actualValue = actual!!(actor!!) ?: return false
return actualValue.isBefore(expected)
})

val AFTER = expectThatActualIs("after",
fun(actor: Actor?, actual: KnowableValue<LocalTime?>?, expected: LocalTime): Boolean {
ensureActualAndActorNotNull(actual, actor)
val actualValue = actual!!(actor!!) ?: return false
return actualValue.isAfter(expected)
})

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ class TargetEnsure(val value: Target, val targetDescription: String = value.toSt
fun isDisplayed() = PerformablePredicate(value, IS_DISPLAYED, isNegated(), targetDescription)

/**
* Verifies that the element is currently displayed
* Verifies that the element is currently disabled
*/
fun isDisabled() = PerformablePredicate(value, IS_DISABLED, isNegated(), targetDescription)

/**
* Verifies that the element is not currently displayed
* Verifies that the element is currently enabled
*/
fun isEnabled() = PerformablePredicate(value, IS_ENABLED, isNegated(), targetDescription)

Expand All @@ -49,6 +49,11 @@ class TargetEnsure(val value: Target, val targetDescription: String = value.toSt
*/
fun textContent(): StringEnsure = StringEnsure(textValueOf(value), "$targetDescription with text content")

/**
* Verifies the text content of the specified element
*/
fun textContentValues(): CollectionEnsure<String> = CollectionEnsure(textContentsOf(value), "$targetDescription with text contents")

/**
* Verifies the value attribute of an element
*/
Expand Down Expand Up @@ -103,12 +108,24 @@ class TargetEnsure(val value: Target, val targetDescription: String = value.toSt
return target.resolveFor(actor).text
}

private fun textContentOf(target: Target): KnowableValue<String> =
fun(actor: Actor?): String {
if (actor == null) return ""
return target.resolveFor(actor).textContent
}

private fun textValuesOf(target: Target): KnowableValue<List<String>?> =
fun(actor: Actor?): List<String> {
if (actor == null) return emptyList()
return target.resolveAllFor(actor).map { it.text }
}

private fun textContentsOf(target: Target): KnowableValue<List<String>?> =
fun(actor: Actor?): List<String> {
if (actor == null) return emptyList()
return target.resolveAllFor(actor).map { it.textContent }
}

private fun valueOf(target: Target): KnowableValue<String> =
fun(actor: Actor?): String {
if (actor == null) return ""
Expand Down
Loading

0 comments on commit 39af150

Please sign in to comment.