I am trying to make a function to catch org.openqa.selenium.NoSuchElementException, and here is my implementation in scala:
def doesElementExists() = {
try {
//as long as isDisplayed() returns a boolean value, it means the element exists in the html code
seleniumElement.isDisplayed()
true
} catch {
case element_not_found_exception: org.openqa.selenium.NoSuchElementException => {
false
}
}
}
However, as soon as I check for a nonexistent element, which I expect the function to return a false, it blow off and throw back
org.openqa.selenium.NoSuchElementException,
: Unable to locate element: {"method":"id","selector":"nonexistent-element"};
I am wondering why the catch block did not handle the exception?
IsDisplayed is a property of an element that has already been found. What you are doing is essentially this (C# code):
var element = driver.FindById("nonexistent-element"); //<---This is what throws NoSuchElementException
try
{
var displayed = element.IsDisplayed;
}
catch(NoSuchElementException)
{
}
So to achieve what you want, your doesElementExists function should take in the locator as a parameter, and wrap the try-catch statement around finding the element.
Related
I have a controller whose create action I want to accept JSON either like this:
{ "foo": "bar" }
OR like this:
{ "widget": { "foo": "bar" } }
That is, I want to accept either the widget or the widget wrapped in a containing object. Currently, the create action for my controller looks a lot like this:
func createHandler(_ req: Request) throws -> Future<Widget> {
do {
return try req.content.decode(WidgetCreateHolder.self).flatMap(to: Widget.self) {
return createWidget(from: $0.widget)
}
} catch DecodingError.keyNotFound {
return try req.content.decode(WidgetCreateObject.self).flatMap(to: Widget.self) {
return createWidget(from: $0)
}
}
}
where WidgetCreateObject looks something like:
struct WidgetCreateObject { var foo: String? }
and where WidgetCreateHolder looks like:
struct WidgetCreateHolder { var widget: WidgetCreateObject }
That is, my create action should try to create a holder, but if that fails it should catch the error and try just creating the inner object (a WidgetCreateObject). However, when I deploy this code to Heroku and make a request with just the inner object JSON, I get this in my logs:
[ ERROR ] DecodingError.keyNotFound: Value required for key 'widget'. (ErrorMiddleware.swift:26)
even though I am trying to catch that error!
How can I get my create action to accept two different formats of JSON object?
Figured it out!
The decode method returns a Future, such that the actual decoding (and hence the error) occurs later, not during the do/catch. This means there's no way to catch the error with this do catch.
Luckily, Futures have a series of methods prepended with catch; the one I'm interested in is catchFlatMap, which accepts a closure from Error -> Future<Decodable>. This method 'catches' the errors thrown in the called Future, and passes the error to the closure, using the result in any downstream futures.
So I was able to change my code to:
func createHandler(_ req: Request) throws -> Future<Widget> {
return try req.content.decode(WidgetCreateHolder.self).catchFlatMap({ _ in
return try req.content.decode(WidgetCreateObject.self).map(to: WidgetCreateHolder.self) {
return WidgetCreateHolder(widget: $0)
}
}).flatMap(to: Widget.self) {
return createWidget(from: $0.widget)
}
}
I would like to figure out how to pattern match against an enum-with-associated-value property of an error type in a catch. Everything works as expected with an enum without associated values, but I can't seem to figure out the correct pattern for this situation.
struct MyError: Error {
enum Size {
case big, small
}
enum Solution {
case runAway
case other(String)
}
let size: Size
let solution: Solution
}
func action() {
do {
// ...
}
catch let error as MyError where error.size == .big {
// This works fine, as `size` has no associated values.
}
catch let error as MyError where error.solution == .other {
// I want to handle all cases of `Solution.other` here, regardless of the associated value.
}
catch {
// ...
}
}
The second catch pattern won't compile (as expected due to the enum with associated value). The usual way I'd accomplish this would be a if case .runAway = error.solution {...}, but integrating this in the catch pattern is the problem.
I tried many combinations of if case/let case/case let, but couldn't get this working in a single catch pattern matching statement. This feels like it should be possible given the power and flexibility of pattern matching, so I'm hoping I've just overlooked something.
Thanks for the assistance!
This feels possible, but isn't :/. What you are trying to use is an enum case pattern. According to here, an enum case pattern is only allowed in switch, if, while, guard, and for statements.
You can add an isOther property in Solution:
var isOther: Bool {
if case .other = self {
return true
} else {
return false
}
}
And then use it in the catch:
do {
// ...
}
catch let error as MyError where error.size == .big {
// ...
}
catch let error as MyError where error.solution.isOther {
// ...
}
catch {
// ...
}
There are 2 things which should be fixed in your sample:
To compare cases of an enum it should be equitable, isn't it? For such a simple enum just mark Solution as Equitable.
Default case for a catch isn't handled, so you need to add it, eg:
do {
...
}
catch let error as MyError where error.size == .big {
// This works fine, assizehas no associated values.
}
catch let error as MyError where error.solution == .runAway {
// I want to accomplish this comparison.
}
catch let error {
...
}
I've been trying to figure out what is going on to no avail. I've distilled the code as much as possible but I still get the "Result of operator && is unused warning (even though it is used) if I do it in a project but the same code copied to Playground is working fine with no warnings. This is just some dummy code, after me rewriting the basic code again while trying to find the problem.
enum WordError: Error {
case tooShort
case tooLong
}
func isTooShort(_ word: String) throws -> Bool {
if word.count < 3 { throw WordError.tooShort }
return true }
func isTooLong(_ word: String) throws -> Bool {
if word.count > 5 { throw WordError.tooLong }
return true }
func check(_ word: String) {
do {
try isTooShort(word) && isTooLong(word)
print(word)
} catch let error as WordError {
print("\(error)")
} catch {
}
}
Is this just a bug or am I doing something wrong here?
I figured I can silence the warning if I use:
try _ = isTooShort(word) && isTooLong(word)
But I'm not sure whether that's the right way of 'patching' it.
There is nothing wrong with doing it that way. The "right" way, when something like isTooShort belongs to you and you want to call it without capturing the result, is to mark it with #discardableResult. If you did that, then you could write
do {
try isTooShort(word)
try isTooLong(word)
print(word) // if we get here, it's neither too short nor too long
} catch ...
But what you're doing is also "right" in these circumstances.
The real question is why you would both return a Bool and throw an error. Your implementation of isTooShort is very odd. You seem to be misusing throw. It isn't clear what problem you are trying to solve by implementing it in this odd way. isTooShort can only fail one way: the word is too short. So why doesn't it just return a Bool? isTooShort asks a simple yes/no question, so just answer it: return a Bool and stop.
If your goal is to answer a three-way question - i.e., to tell the caller whether this word was too short, too long, or just right, then again, just return a custom enum that answers the question:
enum WordLength {
case tooShort
case tooLong
case justRight
}
func howIs(_ word: String) -> WordLength {
if word.count < 3 { return .tooShort }
if word.count > 5 { return .tooLong }
return .justRight
}
I have written 2 codes .The functionality of both the code is same.Both the codes take user data then store it in map and on providing keys we get correspoding user data. I have written an extra logic in code2, whic I have mentioned below.
Code1:
class user(var name:String,var id:Int, var gender:Option[String])
{
override def toString="("+ name+","+id+","+gender+")"
}
object a
{
def main(args:Array[String]):Unit={
var a=new user("kl",90,Some("Male"))
println(a.name,a.id,a.gender)//ACESS VALUES
//DEFINING MAP
var mm=Map(1-> new user("jh",189,Some("Male")),2->new user("gh",12,None),3
->new user("io",100,Some("Female")))
// defining method giving o/p value of specific key of mm
def getkey(i:Int)=
{ mm.get(i)
}
var u1=getkey(readLine("ENTER THE KEY").toInt) // some[user]
println(u1.getClass.getName)
if(u1.isDefined)
{
println(u1.get+","+u1.get.name+","+u1.get.id+","+u1.get.gender)
}
}
}
Code1 1 works properly and O/P is right. I have added extra logic in Code2. The extra logic is getKey method. I have written a code for checking whether the input key is present in map. There I am getting an error:
**value get is not a member of java.io.Serializable**_
Code2:
class user(var name:String,var id:Int, var gender:Option[String])
{
override def toString="("+ name+","+id+","+gender+")"
}
object a
{
def main(args:Array[String]):Unit={
var a=new user("kl",90,Some("Male"))
println(a.name,a.id,a.gender)//ACESS VALUES
//DEFINING MAP
var mm=Map(1-> new user("jh",189,Some("Male")),2->new user("gh",12,None),3-> new user("io",100,Some("Female")))
// defining method giving o/p value of specific key of mm
def getkey(i:Int)=
{
//EXTRA LOGIC
var a=(mm.keys).toList
if(a.contains(i)){mm.get(i)}
else {"NO SUCH ELEMENT EXCEPTION , KEY DOESNT MATCH"}
}
print("ENTER THE KEY \n")
var u1=getkey(1) // some[user]
println(u1.get)
}
}
ERROR -
enter code here
eg1.Option.scala:27: error: value get is not a member of
java.io.Serializable
println(u1.get)
^
one error found
Why does the seriliazable errors occurs in Code2 and not in Code1? Is the error due extra logic in Code2? How to fix an error?
Thank you!
It happens because your getKey function return type is io.Serializable.
Reason for this is that every branch of your if expression is returning a different type:
def getkey(i:Int) = { // io.Serializable
//EXTRA LOGIC
var a=(mm.keys).toList
if(a.contains(i)) { mm.get(i) } // option here
else { "NO SUCH ELEMENT EXCEPTION , KEY DOESNT MATCH" } // string here
}
Consider rewriting your function, so its return type is Option[User], one way of doing so is:
def getkey(i:Int): Option[user] = {
//EXTRA LOGIC
var a=(mm.keys).toList
if(a.contains(i)) { mm.get(i) }
else { None }
}
However, there is no need for checking keys, you can simplify this function to:
def getkey(i:Int): Option[user] = {
//EXTRA LOGIC
m.get(i)
}
Hint: write expected return type for functions to see what's going wrong in such cases.
I need to set a variable depending on a condition. But since variables are immutable, I find myself in a sticky situation having to repeat code. What I'd like to do is:
def doSomething(x:Int):Int = {
if(x==1){
val player="Andy"
} else {
val player="Rob"
}
getSomeValue(player) // Another function
}
But the variable "player" is no longer in scope. Only way I see is to call the function "getSomeValue" in both the condition blocks, but that's not something I'd like to do. How do I get around this using immutable variables?
def doSomething(x:Int):Int = {
val player = if(x==1){
"Andy"
} else {
"Rob"
}
getSomeValue(player)
}