How to use Exhaustive class of io.kotest.property.exhaustive package

Best Kotest code snippet using io.kotest.property.exhaustive.Exhaustive

RoomsKtTest.kt

Source:RoomsKtTest.kt Github

copy

Full Screen

...6import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder7import io.kotest.matchers.should8import io.kotest.matchers.shouldBe9import io.kotest.property.Arb10import io.kotest.property.Exhaustive11import io.kotest.property.arbitrary.ShortShrinker12import io.kotest.property.arbitrary.arbitrary13import io.kotest.property.arbitrary.enum14import io.kotest.property.arbitrary.set15import io.kotest.property.checkAll16import io.kotest.property.exhaustive.ints17import io.kotest.property.exhaustive.map18import io.kotest.property.forAll19import org.jetbrains.exposed.sql.insert20import org.jetbrains.exposed.sql.select21import org.jetbrains.exposed.sql.selectAll22import org.jetbrains.exposed.sql.transactions.transaction23import kotlin.random.nextInt24val directionSets = Arb.set(Arb.enum<Direction>(), 0..Direction.values().size)25val rotations = Exhaustive.ints(0..3).map { it.toShort() }26val invalidRotationValues = (Short.MIN_VALUE..Short.MAX_VALUE) - (0..3)27val invalidRotations = arbitrary(listOf(Short.MIN_VALUE, -1, 4, Short.MAX_VALUE), ShortShrinker) {28 it.random.nextInt(invalidRotationValues.indices).let { i -> invalidRotationValues[i] }.toShort()29}30class RoomsKtTest : DescribeSpec({31 useDatabase()32 describe("returnRoomToStack") {33 it("returns to empty stack") {34 transaction {35 val gameId = "ABCDEF"36 val stackId =37 RoomStacks.insert {38 it[this.gameId] = gameId39 it[curIndex] = null...

Full Screen

Full Screen

TestCodeGenerators.kt

Source:TestCodeGenerators.kt Github

copy

Full Screen

1import io.kotest.property.Arb2import io.kotest.property.Exhaustive3import io.kotest.property.arbitrary.bind4import io.kotest.property.arbitrary.list5import io.kotest.property.arbitrary.take6import io.kotest.property.exhaustive.azstring7import io.kotest.property.exhaustive.collection8import konnekt.HeadersDeclaration9import konnekt.MimeEncodingsDeclaration10import konnekt.SourcesDeclaration11import konnekt.names12import konnekt.prelude.FormUrlEncoded13import konnekt.prelude.Multipart14fun functions(source: SourcesDeclaration): List<String> {15 val annotations = annotationVariants(source)16 return when (source) {17 SourcesDeclaration.PATH -> annotations.mapIndexed { i, annotation ->18 """|@GET("/test/{p}")19 |suspend fun test${source.name}$i($annotation r: Int): String""".trimMargin()20 }21 SourcesDeclaration.BODY, SourcesDeclaration.QUERY, SourcesDeclaration.PART, SourcesDeclaration.FIELD, SourcesDeclaration.HEADER -> annotations.mapIndexed { i, annotation ->22 """|${source.optInAnnotation()}23 |@GET("/test")24 |suspend fun test${source.name}$i($annotation r: Int): String""".trimMargin()25 }26 }27}28fun headerFunctions(): Iterable<String> {29 val annotations = headerAnnotationVariants.take(50)30 return annotations.mapIndexed { i, annotation ->31 """|@GET("/test")32 |$annotation33 |suspend fun testHEADERS_$i(): String""".trimMargin()34 }.asIterable()35}36fun mimeEncodingFunctions(encoding: MimeEncodingsDeclaration): Iterable<String> {37 val annotations = encoding.names.map { "@$it" }38 return annotations.mapIndexed { i, annotation ->39 """|$annotation40 |@GET("/test")41 |suspend fun testMIME_ENCODING_$i(): String""".trimMargin()42 }43}44private fun annotationVariants(it: SourcesDeclaration): List<String> {45 return when (it) {46 SourcesDeclaration.BODY -> it.names.map { "@$it" }47 SourcesDeclaration.PATH -> (it.names product listOf("\"p\"").named("value"))48 .let { oneArg ->49 val stringOnly = oneArg.map { (name, str) -> "@$name($str)" }50 val complete = (oneArg product booleanLiterals.named("encoded")).map { (name, str, bool) -> "@$name($str, $bool)" }51 stringOnly + complete52 }53 SourcesDeclaration.QUERY, SourcesDeclaration.FIELD -> (it.names product stringLiterals.named("value"))54 .let { oneArg ->55 val stringOnly = oneArg.map { (name, str) -> "@$name($str)" }56 val complete = (oneArg product booleanLiterals.named("encoded")).map { (name, str, bool) -> "@$name($str, $bool)" }57 stringOnly + complete58 }59 SourcesDeclaration.PART, SourcesDeclaration.HEADER -> (it.names product stringLiterals.named("value"))60 .map { (name, str) -> "@$name($str)" }61 }62}63private fun SourcesDeclaration.optInAnnotation(): String {64 val name = when (this) {65 SourcesDeclaration.PART -> Multipart::class.java.simpleName66 SourcesDeclaration.FIELD -> FormUrlEncoded::class.java.simpleName67 else -> null68 }69 return name?.let { "@$it" } ?: ""70}71private val headerAnnotationVariants = Arb.bind(72 Exhaustive.collection(HeadersDeclaration.names),73 Arb.list(Exhaustive.azstring(1..10).toArb())74) { name, args ->75 val varargs = args.joinToString(", "){ "\"$it\"" }76 "@$name($varargs)"77}78private val stringLiterals = listOf(""""p"""", "\"\"")79private val booleanLiterals = listOf("true", "false")80infix fun <T, E> List<T>.product(other: List<E>): List<Pair<T, E>> {81 return flatMap { l -> other.map { r -> l to r } }82}83@JvmName("productTriple")84infix fun <T, E, L> List<Pair<T, E>>.product(other: List<L>): List<Triple<T, E, L>> {85 return flatMap { (l1, l2) -> other.map { r -> Triple(l1, l2, r) } }86}87private fun List<String>.named(name: String): List<Argument> = flatMap {...

Full Screen

Full Screen

AxisBindingTest.kt

Source:AxisBindingTest.kt Github

copy

Full Screen

...6import edu.wpi.first.wpilibj.simulation.XboxControllerSim7import io.kotest.matchers.doubles.shouldBeExactly8import io.kotest.matchers.shouldBe9import io.kotest.property.Arb10import io.kotest.property.Exhaustive11import io.kotest.property.arbitrary.int12import io.kotest.property.checkAll13import io.kotest.property.exhaustive.enum14import io.kotest.property.exhaustive.exhaustive15class AxisBindingTest : ShuffleboardWordSpec({16 // These are lazy so that they don't get created until after HAL.initialize has been called17 val xboxController by lazy { XboxController(0) }18 val xboxControllerSim by lazy { XboxControllerSim(0) }19 val ps4Controller by lazy { PS4Controller(1) }20 val oi by lazy { OISubsystem(xboxController, ps4Controller) }21 beforeTest {22 XboxController.Axis.values().forEach {23 xboxControllerSim.setRawAxis(it.value, 0.0)24 }25 xboxControllerSim.notifyNewData()26 }27 "AxisBinding.get" should {28 "return the value of the bound axis" {29 val binding = AxisBinding(AxisActions.LEFT_DRIVE, oi, container)30 xboxControllerSim.setRawAxis(AxisActions.LEFT_DRIVE.defaultChannel, 0.5)31 xboxControllerSim.notifyNewData()32 binding.get() shouldBeExactly 0.533 }34 }35 "AxisBinding.getBoundChannelName" should {36 "return the name of XboxController axes" {37 val binding = AxisBinding(AxisActions.LEFT_DRIVE, oi, container)38 checkAll<XboxController.Axis>(Exhaustive.enum()) { axis ->39 binding.bindTo(xboxController, axis.value)40 binding.boundChannelName shouldBe "$axis"41 }42 }43 "return the name of PS4Controller axes" {44 val binding = AxisBinding(AxisActions.LEFT_DRIVE, oi, container)45 checkAll<PS4Controller.Axis>(Exhaustive.enum()) { axis ->46 binding.bindTo(ps4Controller, axis.value)47 binding.boundChannelName shouldBe "$axis"48 }49 }50 "return the channel number if not a known channel" {51 val binding = AxisBinding(AxisActions.LEFT_DRIVE, oi, container)52 checkAll(53 30,54 Arb.int(20),55 listOf(xboxController, ps4Controller, GenericHID((2))).exhaustive()56 ) { channel, controller ->57 binding.bindTo(controller, channel)58 binding.boundChannelName shouldBe "$channel"59 }...

Full Screen

Full Screen

NotePitchTest.kt

Source:NotePitchTest.kt Github

copy

Full Screen

...3import io.kotest.data.row4import io.kotest.matchers.collections.shouldContainExactly5import io.kotest.matchers.shouldBe6import io.kotest.property.Arb7import io.kotest.property.Exhaustive8import io.kotest.property.arbitrary.element9import io.kotest.property.arbitrary.list10import io.kotest.property.checkAll11import io.kotest.property.exhaustive.collection12import io.kotest.property.exhaustive.enum13import io.loskunos.midi.Octave.Companion.o014import io.loskunos.midi.Octave.Companion.o115import io.loskunos.midi.Octave.Companion.o216import io.loskunos.midi.Octave.Companion.o317import io.loskunos.midi.Octave.Companion.o418import io.loskunos.midi.Octave.Companion.o519import io.loskunos.midi.Octave.Companion.o620import io.loskunos.midi.Octave.Companion.o721import io.loskunos.midi.Octave.Companion.o822import io.loskunos.midi.PitchClass.C23import kotlinx.coroutines.runBlocking24import org.junit.jupiter.api.Nested25import org.junit.jupiter.api.Test26class NotePitchTest {27 private val allPitchClassInstances = PitchClass::class.sealedSubclasses.map { it.objectInstance!! }28 @Nested29 inner class PitchClassToNotePitch {30 @Test31 fun `should be the same note`() {32 runBlocking {33 checkAll(Exhaustive.collection(allPitchClassInstances)) { pitchClass ->34 pitchClass.octave(o1).pitchClass shouldBe pitchClass35 }36 }37 }38 @Test39 fun `should have given octave`() {40 runBlocking {41 checkAll(Exhaustive.enum<Octave>()) { givenOctave ->42 C.octave(givenOctave) shouldBe NotePitch(C, givenOctave)43 }44 }45 }46 }47 @Test48 fun `adding octave to a list of PitchClasses returns a list of NotePitches with correct octave`() {49 runBlocking {50 checkAll(iterations = 10, Arb.list(Arb.element(allPitchClassInstances), range = 0..10)) { pitchClasses ->51 checkAll(Exhaustive.enum<Octave>()) { givenOctave ->52 forAll(53 row { octave(givenOctave, *pitchClasses.toTypedArray()) },54 row { octave(givenOctave) { pitchClasses } },55 row { pitchClasses.octave(givenOctave) }56 ) { octaveFun ->57 val result = octaveFun()58 result.map { it.octave }.forEach { it shouldBe givenOctave }59 result.map { it.pitchClass } shouldContainExactly pitchClasses60 }61 }62 }63 }64 }65 @Test...

Full Screen

Full Screen

GeneratorTests.kt

Source:GeneratorTests.kt Github

copy

Full Screen

1package test.kotest.propertyTest2import io.kotest.core.spec.style.StringSpec3import io.kotest.property.Arb4import io.kotest.property.Exhaustive5import io.kotest.property.RandomSource6import io.kotest.property.arbitrary.*7import io.kotest.property.exhaustive.enum8import io.kotest.property.exhaustive.exhaustive9import io.kotest.property.exhaustive.ints10import io.kotest.property.forAll11import java.time.LocalDateTime12enum class Season { Winter, Fall, Spring, Summer }13data class Person(val name: String, val age: Int)14class GeneratorTests : StringSpec({15 //根据类型自动选择合适的generator16 "use forAll" {17 forAll<Int, Double, Boolean, String, LocalDateTime, Season>(10) { a, b, c, d, e, f ->18 println("$a $b $c $d $e $f")19 true20 }21 }22 //使用底层生成器Arbitrary 无限随机生成器23 "use generator" {24 Arb.int(1, 200).take(10).toList().run(::println)25 Arb.intArray(Arb.int(2, 8), Arb.int(200..400)).take(10).map { it.toList() }.toList().run(::println)26 Arb.char('a'..'z').take(10).toList().run(::println)27 Arb.stringPattern("\\w+[0-9]").take(10).toList().run(::println)28 Arb.list(Arb.int(), 1..5).take(10).toList().run(::println)29 }30 //使用有限生成器 Exhaustive31 "use exhaustive" {32 Exhaustive.enum<Season>().values.run(::println)33 Exhaustive.ints(1..10).values.run(::println)34 }35 //使用组合生成器36 "use complex operation" {37 Arb.choice(Arb.int(1..10), Arb.double(20.0..50.0)).take(10).toList().run(::println)38 Arb.bind(Arb.string(), Arb.int()) { name, age ->39 Person(name, age).run(::println)40 }41 Arb.choose(1 to Arb.int(1, 10), 2 to Arb.double(1.0, 5.0)).take(10).toList().run(::println)42 Arb.shuffle(listOf(1, 2, 3, 4, 5, 6)).take(10).toList().run(::println)43 Arb.subsequence(listOf(1, 2, 3, 4, 5, 6)).take(10).toList().run(::println)44 }45 //自定义生成器46 "custom generator" {47 val arb = arbitrary { rs: RandomSource ->...

Full Screen

Full Screen

Exhaustive.kt

Source:Exhaustive.kt Github

copy

Full Screen

1package utils2import io.kotest.property.Arb3import io.kotest.property.Exhaustive4import io.kotest.property.Gen5import io.kotest.property.RandomSource6import io.kotest.property.arbitrary.byte7import io.kotest.property.arbitrary.next8import io.kotest.property.exhaustive.exhaustive9import io.kotest.property.exhaustive.filter10import io.kotest.property.exhaustive.ints11import io.kotest.property.exhaustive.map12fun <N : Number> Exhaustive<N>.toInt() = map { it.toInt() }13fun <N : Number> Exhaustive<N>.toShort() = map { it.toShort() }14fun Exhaustive.Companion.shorts(min: Short = Short.MIN_VALUE, max: Short = Short.MAX_VALUE) =15 Exhaustive.ints(min..max).map { it.toShort() }16fun Exhaustive.Companion.ubytes(min: UByte = UByte.MIN_VALUE, max: UByte = UByte.MAX_VALUE): Exhaustive<UByte> =17 Exhaustive.ints(min.toInt()..max.toInt()).map { it.toUByte() }18fun Exhaustive.Companion.ushorts(min: UShort = UShort.MIN_VALUE, max: UShort = UShort.MAX_VALUE): Exhaustive<UShort> =19 Exhaustive.ints(min.toInt()..max.toInt()).map { it.toUShort() }20fun Exhaustive.Companion.byteArrays(length: IntRange, byte: Gen<Byte> = Arb.byte()): Exhaustive<ByteArray> {21 val generator = byte.generate(RandomSource.Default).iterator()22 return length.map { ByteArray(it) { generator.next().value } }.exhaustive()23}24operator fun <A> Exhaustive<A>.minus(other: Exhaustive<A>) =25 filter { it !in other.values }26inline fun <reified T> Exhaustive.Companion.arrayOf(value: Arb<T>, length: IntRange): Exhaustive<Array<T>> {27 return length.map { Array(it) { value.next() } }.exhaustive()28}...

Full Screen

Full Screen

GeneratorSpec.kt

Source:GeneratorSpec.kt Github

copy

Full Screen

1package ru.iopump.qa.sample.property2import io.kotest.core.spec.style.FreeSpec3import io.kotest.property.Arb4import io.kotest.property.Exhaustive5import io.kotest.property.arbitrary.*6import io.kotest.property.exhaustive.enum7import io.kotest.property.exhaustive.ints8import io.kotest.property.exhaustive.merge9import io.kotest.property.exhaustive.times10import org.slf4j.event.Level11/** For string generator with leading zero */12/*1*/val numberCodepoint: Arb<Codepoint> = Arb.int(0x0030..0x0039)13 .map { Codepoint(it) }14/** For english string generator */15/*2*/val engCodepoint: Arb<Codepoint> = Arb.int('a'.toInt()..'z'.toInt())16 .merge(Arb.int('A'.toInt()..'Z'.toInt()))17 .map { Codepoint(it) }18class GeneratorSpec : FreeSpec() {19 init {20 "/*3*/ random number supported leading zero" {21 Arb.string(10, numberCodepoint).next()22 .also(::println)23 }24 "/*4*/ random english string" {25 Arb.string(10, engCodepoint).orNull(0.5).next()26 .also(::println)27 }28 "/*5*/ random russian mobile number" {29 Arb.stringPattern("+7\\(\\d{3}\\)\\d{3}-\\d{2}-\\d{2}").next()30 .also(::println)31 }32 "/*6*/ exhaustive collection and enum multiply" {33 Exhaustive.ints(1..5).times(Exhaustive.enum<Level>()).values34 .also(::println)35 }36 "/*7*/ exhaustive collection and enum merge" {37 Exhaustive.ints(1..5).merge(Exhaustive.enum<Level>()).values38 .also(::println)39 }40 }41}...

Full Screen

Full Screen

option.kt

Source:option.kt Github

copy

Full Screen

...3import arrow.core.Option4import arrow.core.Some5import arrow.core.some6import io.kotest.property.Arb7import io.kotest.property.Exhaustive8import io.kotest.property.arbitrary.constant9import io.kotest.property.arbitrary.map10import io.kotest.property.arbitrary.merge11import io.kotest.property.exhaustive.exhaustive12/**13 * Returns an Exhaustive that contains a None and a Some with the given value14 */15fun <A> Exhaustive.Companion.option(a: A) = exhaustive(listOf(None, Some(a)))16fun <A> Exhaustive.Companion.none() = exhaustive(listOf(None))17/**18 * Wraps each element generated by the given Arb in a Some.19 */20fun <A> Arb.Companion.some(arb: Arb<A>): Arb<Option<A>> = arb.map { it.some() }21fun <A> Arb.Companion.none(): Arb<Option<A>> = Arb.constant(None)22fun <A> Arb.Companion.option(arb: Arb<A>): Arb<Option<A>> = some(arb).merge(none())...

Full Screen

Full Screen

Exhaustive

Using AI Code Generation

copy

Full Screen

1val intExhaustive = Exhaustive.ints(0..10)2val intExhaustive = Exhaustive.ints(0, 10)3val intExhaustive = Exhaustive.ints(0, 10, 2)4val intExhaustive = Exhaustive.ints(0, 10, 2, 5)5val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7)6val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7, 8)7val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7, 8, 9)8val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7, 8, 9, 10)9val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7, 8, 9, 10, 11)10val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7, 8, 9, 10, 11, 12)11val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7, 8, 9, 10, 11, 12, 13)12val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7, 8, 9, 10, 11, 12, 13, 14)13val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15)14val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)15val intExhaustive = Exhaustive.ints(0, 10, 2, 5, 7, 8, 9, 10, 11, 12,

Full Screen

Full Screen

Exhaustive

Using AI Code Generation

copy

Full Screen

1 val intRange = Exhaustive.of(1..10)2 val intList = Exhaustive.of(listOf(1, 2, 3, 4, 5))3 val intArray = Exhaustive.of(arrayOf(1, 2, 3, 4, 5))4 val intSequence = Exhaustive.of(sequenceOf(1, 2, 3, 4, 5))5 val intIterable = Exhaustive.of(Iterable { listOf(1, 2, 3, 4, 5).iterator() })6 val intIterator = Exhaustive.of(Iterator { listOf(1, 2, 3, 4, 5).iterator() })7 val intRange = Exhaustive.of(1..10)8 val intList = Exhaustive.of(listOf(1, 2, 3, 4, 5))9 val intArray = Exhaustive.of(arrayOf(1, 2, 3, 4, 5))10 val intSequence = Exhaustive.of(sequenceOf(1, 2, 3, 4, 5))11 val intIterable = Exhaustive.of(Iterable { listOf(1, 2, 3, 4, 5).iterator() })12 val intIterator = Exhaustive.of(Iterator { listOf(1, 2, 3, 4, 5).iterator() })13 val intRange = Exhaustive.of(1..10)14 val intList = Exhaustive.of(listOf(1, 2, 3, 4, 5))15 val intArray = Exhaustive.of(arrayOf(1, 2, 3, 4, 5))16 val intSequence = Exhaustive.of(sequenceOf(1, 2, 3, 4, 5))17 val intIterable = Exhaustive.of(Iterable { listOf(1, 2, 3, 4, 5).iterator() })18 val intIterator = Exhaustive.of(Iterator { listOf(1, 2, 3, 4, 5).iterator() })

Full Screen

Full Screen

Exhaustive

Using AI Code Generation

copy

Full Screen

1val a = Exhaustive.ints(1, 10)2val b = Exhaustive.strings()3val c = Exhaustive.ints(1, 10).map { it * 2 }4val d = Exhaustive.ints(1, 10).flatMap { Exhaustive.ints(1, it) }5val e = Exhaustive.ints(1, 10).filter { it % 2 == 0 }6val f = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }7val g = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }8val h = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }9val i = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }10val j = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }11val k = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }12val l = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }13val m = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }14val n = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }15val o = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }16val p = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10)) { a, b -> a + b }17val q = Exhaustive.ints(1, 10).zip(Exhaustive.ints(1, 10

Full Screen

Full Screen

Exhaustive

Using AI Code Generation

copy

Full Screen

1val exhaustive = Exhaustive.ints(1..10)2val result = exhaustive.take(10)3result.forEach { println(it) }4val exhaustive = Exhaustive.longs(1L..10L)5val result = exhaustive.take(10)6result.forEach { println(it) }7val exhaustive = Exhaustive.floats(1f..10f)8val result = exhaustive.take(10)9result.forEach { println(it) }10val exhaustive = Exhaustive.doubles(1.0..10.0)11val result = exhaustive.take(10)12result.forEach { println(it) }13val exhaustive = Exhaustive.chars('a'..'z')14val result = exhaustive.take(10)15result.forEach { println(it) }

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Kotest automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful