Kotlin Java streams - map Selenium WebElement(s) to List - selenium

I'm struggling a bit with a pretty simple case of mapping a list of Selenium WebElements to a List of classes using Java Streams.
The element:
val elements: List<WebElement> = element.findElements(By.cssSelector("[data-e2e-selector=expense]"))
(Currently, there are only two elements in the list.)
I'm currently mapping the WebElement list to a MutableList of classes the "classic way":
val expenseElements: MutableList<ExpenseElement> = ArrayList()
for (element in elements) {
expenseElements += ExpenseElement(element)
}
Which is working fine. But I feel I should learn to use Stram() to do this more "elegantly". Or, at least, because I want to :-)
But my feeble attempt at using Stream()
val expenseElements = elements.stream().map { UtgiftElement(element) }.collect(Collectors.toList())
results in only the first element being included. So the first elements takes up both places in the the list.
The first method:
expenseElements[0].expense() = "Entry 1"
expenseElements[1].expense() = "Entry 2"
The non-working Stream() method:
expenseElements[0].expense() = "Entry 1"
expenseElements[1].expense() = "Entry 1"
This is basic I know, but I've tried replicating code that does the same in Java. I have to start somewhere.

There's a mistake in your mapping lambda. You do:
map { UtgiftElement(element) }
But that is not correct. The map function provides you with a single input, named it by default. Your lambda should either by map { UtgiftElement(it) } or map { element -> UtgiftElement(element) }.
I do not know where your element variable comes from, but I think it is not one of the elements in the stream.

Related

Extracting Nested POJO Object with Rest-Assured

I'm writing some tests using rest-assured and its Kotlin extensions to test some simple Spring MVC endpoints. I'm trying to understand how to extract values.
One endpoint returns a BookDetailsView POJO, the other returns a Page<BookDetailsView> (where Page is an interface provided by Spring for doing paging).
BookDetailsView is a really simple Kotlin data class with a single field:
data class BookDetailsView(val id: UUID)
For the single object endpoint, I have:
#Test
fun `single object`() {
val details = BookDetailsView(UUID.randomUUID())
whenever(bookDetailsService.getBookDetails(details.id)).thenReturn(details)
val result: BookDetailsView = Given {
mockMvc(mockMvc)
} When {
get("/book_details/${details.id}")
} Then {
statusCode(HttpStatus.SC_OK)
} Extract {
`as`(BookDetailsView::class.java)
}
assertEquals(details.id, result.id)
}
This works as expected, but trying to apply the same technique for the Page<BookDetailsView> runs afoul of all sorts of parsing challenges since Page is an interface, and even trying to use PageImpl isn't entirely straightforward. In the end, I don't even really care about the Page object, I just care about the nested list of POJOs inside it.
I've tried various permutations like the code below to just grab the bit I care about:
#Test
fun `extract nested`() {
val page = PageImpl(listOf(
BookDetailsView(UUID.randomUUID())
))
whenever(bookDetailsService.getBookDetailsPaged(any())).thenReturn(page)
val response = Given {
mockMvc(mockMvc)
} When {
get("/book_details")
} Then {
statusCode(HttpStatus.SC_OK)
body("content.size()", `is`(1))
body("content[0].id", equalTo(page.first().id.toString()))
} Extract {
path<List<BookDetailsView>>("content")
}
println(response[0].javaClass)
}
The final println spits out class java.util.LinkedHashMap. If instead I try to actually use the object, I get class java.util.LinkedHashMap cannot be cast to class BookDetailsView. There are lots of questions and answers related to this, and I understand it's ultimately an issue of the underlying JSON parser not knowing what to do, but I'm not clear on:
Why does the "simple" case parse without issue?
Shouldn't the type param passed to the path() function tell it what type to use?
What needs configuring to make the second case work, OR
Is there some other approach for grabbing a nested object that would make more sense?
Digging a bit into the code, it appears that the two cases may actually be using different json parsers/configurations (the former seems to stick to rest-assured JSON parsing, while the latter ends up in JsonPath's?)
I don't know kotlin but here is the thing:
path() doesn't know the Element in your List, so it'll be LinkedHashMap by default instead of BookDetailsView.class
to overcome it, you can provide TypeReference for this.
java example
List<BookDetailsView> response = ....then()
.extract().jsonPath()
.getObject("content", new TypeRef<List<BookDetailsView>>() {});
kotlin example
#Test
fun `extract nested`() {
var response = RestAssured.given().get("http://localhost:8000/req1")
.then()
.extract()
.jsonPath()
.getObject("content", object : TypeRef<List<BookDetailsView?>?>() {});
println(response)
//[{id=1}, {id=2}]
}

How to get all properties with the ids

I'm new to all the graph database stuff and I'm having a hard time with some basic queries.
I'm using Gremlin with Kotlin to connect to AWS Neptune.
I want to get all my vertex properties including the Id.
I have added an vertex with:
g.addV("foo")
.property("name", "Foo 1")
.next()
And to retrieve the properties I have tried:
g.V()
.hasLabel("foo")
.valueMap<String>()
.by(unfold<String>())
.forEach {
// val name = it["name"] -> works great!
// val id = it["id"] -> doesn't exist
}
In this first approach I get a map for each item but this map does not contain the ID.
g.V()
.hasLabel("foo")
.forEach {
// it is an ReferenceVertex that has an ID!
val name = it.property<String>("name") // This returns an EmptyVertexProperty, so I can't read the name
}
I'm using
<dependency>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>gremlin-driver</artifactId>
<version>3.4.4</version>
</dependency>
Bonus question
I couldn't figure out (nor find in the documentation) what the generics on valueMap and unfold method do. Kotlin does not allow me to ommit them (as I have seem in some java code...?), but changing them to Int, for instance, changes nothing in the outcome for these examples... So what is it for? D:
Thanks in advance!
If you want to get the Id with all the other properties you need to run valueMap().with(WithOptions.tokens) or you can use elementMap().

How to copy or clone mutableList of data object without using collection map in Kotlin

I create copy of one MutableList. When I update element value of copy MutableList But Original List element value also changed. When I use map It working fine but It is like a iteration of whole list, Is any way to do achieve without iteration ? how to copy elements of the MutableList.
val array: MutableList<UserData> = ArrayList()
val userData = UserData("DataOne")
array.add(userData)
val arrayCopy = ImmutableList.copyOf(array)// not working
//val arrayCopy = array.toMutableList()// not working
// val arrayCopy = array.map { it.copy() }.toMutableList()//working
Log.i("----> array ", array[0].name)//print DataOne
Log.i("----> arrayCopy ", arrayCopy[0].name)//print DataOne
arrayCopy[0].name = "DataTwo"
Log.d("----> array ", array[0].name)//print DataTwo
Log.d("----> arrayCopy", arrayCopy[0].name) //print DataTwo
ImmutableList.copyOf does copy the list. The problem is that you want to copy elements of the list as well. Of course you have to iterate over the list to do that, but so does copyOf and I don't see why you expect it's possible to avoid. A slightly better version of map is
array.mapTo(mutableListOf()) { it.copy() }
because it iterates only once.
Sorry but there wouldn't be any other way cause to convert one element you will have to read/copy it once, for n number of element you'll have to iterate n times to get the proper copy.
The only other way I can think of is to create the desired immutable/mutable list in the first place and not copying it all at once later.
Hope this helps

how to add Array index value in Kotlin?

first, I create empty Array(Kotlin) instance in companion object.
companion object {
var strarray: Array<String> = arrayOf()
var objectarray: LinkedHashMap<Int, List<Any>> = LinkedHashMap<Int, List<Any>>()
}
and I expected that I use empty array instance when read textString from CSV File.
fun csvFileToString():String {
val inputStream = File(Paths.get("").toAbsolutePath().toString()
.plus("/src/main/SampleCSVFile_2kb.csv")).inputStream()
val reader = inputStream.bufferedReader()
var iterator = reader.lineSequence().iterator()
var index:Int = 1;
while (iterator.hasNext()){
var lineText:String = iterator.next()
strarray.set(index, lineText)
index++
}
return ""
}
but when I run that source code
a.csvFileToString()
println(CsvParser.strarray)
occured exception
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
strarray.set(index, lineText) <<<<<<<<< because of this line
can I use Array(from kotlin collection) like ArrayList(from java collection)?
You can add a new item to an array using +=, for example: item += item
private var songs: Array<String> = arrayOf()
fun add(input: String) {
songs += input
}
Size of Array is defined at its creation and cannot be modified - in your example it equals 0.
If you want to create Array with dynamic size you should use ArrayList.
arrayOf gives you an array. Arrays have fixed length even in Java.
listOf gives you an immutable list. You cannot add or remove items in this list.
What you're looking for is mutableListOf<String>.
In your current approach, reusing a member property, don't forget to clear the list before every use.
Your code can be further simplified (and improved) like so:
out.clear()
inputStream.bufferedReader().use { reader -> // Use takes care of closing reader.
val lines = reader.lineSequence()
out.addAll(lines) // MutableList can add all from sequence.
}
Now imagine you wanted to consume the output list but needed to parse another file at the same time.
Consider working towards a pure function (no side effects, for now no accessing member properties) and simplifying it even further:
fun csvFileToString(): String { // Now method returns something useful.
val inputStream = File(Paths.get("").toAbsolutePath().toString()
.plus("/src/main/SampleCSVFile_2kb.csv")).inputStream()
inputStream.bufferedReader().use {
return it.lineSequence().joinToString("\n")
}
}
In this case we can totally skip the lists and arrays and just read the text:
inputStream.bufferedReader().use {
return it.readText()
}
I'm assuming that's what you wanted in the first place.
Kotlin has a lot of useful extension functions built-in. Look for them first.

How run a Query on an Element?

Issue and how I would do it with the plain Selenium API
I often need to query an element on the page (say with cssSelector().element), use it, and then want to find a descendent element. With the plain Selenium API, I would write something like:
val foo = webDriver.findElement(By.cssSelector(".foo"))
val bar = foo.findElement(By.cssSelector(".bar"))
How can I do this with the ScalaTest Selenium DSL? I can get the "foo" element with:
val foo = cssSelector(".foo").element
But then how to get "bar" from "foo"? Of course, I could just use the Selenium API in that case (i.e. val bar = foo.underlying.findElement(By.cssSelector(".bar"))), but end up with a WebElement instead of a ScalaTest Element.
Workaround running another query
For now, I just run the query all over again, as shown below, but find this verbose, less clear, and not always equivalent to just looking for elements under an element.
val fooSelector = cssSelector(".foo")
val foo = fooSelector.element
val boo = cssSelector(fooSelector.queryString + " .bar").element
The cssSelector method creates a CssSelectorQuery object. You can pass that object as an argument to the find method:
val foo = find(cssSelector(".foo")).get