I am aware that doing Flow Control on a program using a try-catch block is bad practice, but I can't see how to do it in another way when the error caught needs a redirection of the code's execution.
For example, let's say I have screen where the user clicks a button, and on the buttons click I execute some code. After the code ends execution, I redirect the user to a new screen....
... But the code execution can failure, and in that case, I need to let the user know of the failure and redirect him to the previous screen.
The way I will do it is (C# example, but I think this is more of a not language related question, more like good practices on coding in general) :
try
{
ExcuteCode(); // Some code that can throw some Exception, it can be a .NET framework method or something else.
NavigateToNextScreen();
}
catch(Exception e)
{
Log.Write(e);
ShowErrorMessage();
GoBack();
}
Even if I change this to:
bool hasError = false;
try
{
ExecuteCode();
}
catch(Exception e)
{
Log.Write(e);
ShowErrorMessage();
hasError = true;
}
if(hasError) { GoBack(); }
else { NavigateToNextScreen();}
It's still doing Flow Control inside the try-catch block.
So, is it there a recommend way to handle this properly and avoid this bad practice?
Are you looking for the obvious?
try
{
if ( ExcuteCode() == false)
{
ShowErrorMessage();
GoBack();
}
else
{
NavigateToNextScreen();
}
}
catch(Exception e)
{
Log.Write(e);
ShowErrorMessage();
// handle critical error
}
Edit
If you have control over ExecuteCode() then instead of throwing an error return a null or false value and use that to check whether to go forward or backward.
Original
What if you always go back after the catch statement and put the go forward code at the end of the try, like this:
try
{
ExecuteCode();
NavigateToNextScreen();
}
catch(Exception e)
{
Log.Write(e);
ShowErrorMessage();
}
GoBack();
Now go back is the default and it only goes forward if everything executes correctly.
Related
This is an extract of a method in CDialog class:
void CDialog1::Method()
{
try
{
// Snip
}
catch (CException* e_)
{
const gsl::not_null<CException*> e{ e_ };
e->ReportError();
e->Delete();
}
catch (const _com_error& e)
{
AfxMessageBox(e.ErrorMessage(), MB_OK | MB_ICONERROR);
}
}
There is no issue with this function when it is ran from an instance of the modal dialog.
But, in another part of my application I load the same dialog as a hidden modeless dialog. And I call the same function. Eg:
void CDialog2::SomeTask()
{
if (m_pDialog1 != nullptr)
{
m_pDialog1->Method();
}
}
In this second scenario there is an issue with Method when an error is encountered. CDialog2 needs to handle the display of the errors from what I understand, because the hidden instance will appear if it shows a messagebox.
How do I get around this? Note that CDialog1 has a boolean method IsHiddenMode so we know if we are running it as a model or not.
What is the easy way to change my methods to cater for both scenarios:
When CDialog1 calls the method in it's modal dialog.
When CDialog2 calls the method using the modeless member variable of CDialog1.
I tend to overcomplicate my explanations so I hope it makes sense.
I adjusted the Method to detect if the dialog was in hidden mode and throw the exception, eg:
catch (const _com_error& e)
{
if (IsHiddenMode())
{
throw;
}
else
{
AfxMessageBox(e.ErrorMessage(), MB_OK | MB_ICONERROR);
}
}
That way, the calling dialog could catch and handle with a try / catch block.
I have this method using implicit wait pre configured to return me some WebElement:
private WebElement findElement(By locator) {
WebElement element = null;
for (int i = 0; i <= numberOfTries && element == null; i++)
try {
waiter.until(ExpectedConditions.elementToBeClickable(locator));
element = driver.findElement(locator);
} catch (TimeoutException | NoSuchElementException e) {
System.out.println(specificStringAboutTimeOutAndNoSuchEl);
} catch (WebDriverException e) {
Throwable cause = null;
Throwable result = e;
while (null != (cause = result.getCause()) && (result != cause))
result = cause;
System.out.println(specificStringAboutException);
System.out.println(result);
}
return element;
}
And this to wait to some other element vanish, like spinners and loading screens:
private void waitsElementToVanish(By locator, String previousOp) {
List<Class<? extends Throwable>> ignorableExceptions = new ArrayList<>();
ignorableExceptions.add(StaleElementReferenceException.class);
ignorableExceptions.add(NoSuchElementException.class);
try {
if (driver.findElements(locator).size() > 0)
System.out.println(locator.toString() + " exists");
waiter.ignoreAll(ignorableExceptions).until(ExpectedConditions.visibilityOfElementLocated(locator));
waiter.ignoreAll(ignorableExceptions).until(ExpectedConditions.invisibilityOfElementLocated(locator));
} catch (TimeoutException e) {
System.out.println("timeout waiting " + locator.toString() + " to vanish");
System.out.println(previousOp);
}
}
And I use them like this:
waitsElementToVanish(By.className("spinnerLoading"), "someString");
findElement(By.xpath(otherElement)).click();
And I get this error at .click():
org.openqa.selenium.WebDriverException: unknown error: Element <div class="menuContent ellipsis flex flexGrow">...</div> is not clickable at point (136, 240). Other element would receive the click: <div class="spinnerLoading">...</div>
This is the website I'm using and this application is purely educational. This is the entire code.
Should I wrap Selenium click method into some WebDriverException like:
Tries to click, if WebDriverException is thrown with spinnerClass on it, goes to waitsElementToVanish and then tries again
If number of tries goes beyond limit, then it throws some ReallyMessedUpExceptionDoSomething! exception.
My question is: I want to avoid Thread.sleep() at all costs. I want optimize test time waiting only for what it's coming, not for some pre fixed period without checking anything on page. The 'good practice actions' are really wrap click on many tries? How I can assure I'm avoiding spinner even when the line before tried that too? And I don't see any problem wrapping click on a loop to try again and again with a limit. But, actually, what is the best solution here?
i am using eclipse juno and testing the application actitime,which has a check box in login page "keepLoggedInCheckBox"
The HTML source of it,
<input type="checkbox" title="Do not select if this computer is shared"
id="keepLoggedInCheckBox" value="on" name="remember">
I am trying locate the check box "keepLoggedInCheckBox" by using ,
WebElement check = driver.findElement(By.id("keepLoggedInCheckBox"));
But getting this error,
Exception in thread "main" org.openqa.selenium.NoSuchElementException:
Unable to locate element:
{"method":"id","selector":"keepLoggedInCheckBox"}
i tried with xpath (//input[#id='keepLoggedInCheckBox']) ,also getting same error.
please help me, to solve this.
I have faced the same problem. The DOM looses the reference to the element in question. It can either be StaleStateReferenceException or NoSuchElementException. There are two ways to deal with the situation.
(Though my solution is in Java. The underlying concept is the same. )
By using the the following method, you can try clicking an element. If exception is thrown then catch the exception and try to click again until the element is present:
public boolean retryingFindClick(By by) {
boolean result = false;
int attempts = 0;
while(attempts < 2) {
try {
Actions action = new Actions(driver);
WebElement userClick = wait.until(ExpectedConditions.presenceOfElementLocated(by));
action.moveToElement(userClick).click().build().perform();
driver.findElement(by).click();
result = true;
break;
} catch(StaleElementReferenceException e) {
System.out.println("StaleElementReferenceException");
}
catch(NoSuchElementException e) {
System.out.println("No Such Element Found");
}
attempts++;
}
return result;
}
Please try this. I have added implicitlyWait which will allow your DOM content to load.
Note: Please replace Your URL with the exact URL.
WebDriver driver=new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.get("Your URL");
driver.findElement(By.xpath("//*[#id='keepLoggedInCheckBox']")).click();
consider a grammar like this ; speech.Recognizer.Grammars.AddGrammarFromList("answer",new string[] { "Go.","no" });
When I say something else that are not in grammar, she says "sorry didnt catch" and then tries to start it again. Same goes for null input.
What I want is that it should only recognize the words in grammar and for everything else it should just pass the recognition. I don't want to see anything like "sorry didnt catch" and second time recognotion. Any idea ? thanks.
Edit : with try-catch I can avoid from second time recognotion if the word is unknown but now it's waiting too long on "sorry didnt catch" part.
try
{
SpeechRecognizerUI speech = new SpeechRecognizerUI();
speech.Settings.ReadoutEnabled = false;
speech.Settings.ShowConfirmation = false;
speech.Recognizer.Settings.InitialSilenceTimeout = System.TimeSpan.FromSeconds(0.8);
speech.Recognizer.Grammars.AddGrammarFromList("answer", new string[] { "Go.", "no" });
SpeechRecognitionUIResult result = await speech.RecognizeWithUIAsync();
if (result.RecognitionResult.Text == "Go.") { .... }
}
catch
{
..... }
In my opinion, you must build your own UI to avoid this. So you should use SpeechRecognizer and then you can handle the input as you want.
In my case I even created two SpeechRecognizer, on with own Wordlist, the other one with default dictionary. It works like a charm, but I couldn't get it to work with SpeechRecognizerUI.
Trying a try-catch sequence that works fine in release version, but running it in debugger causes errors to be displayed. Obviously there errors, that's why I'm using this stuff inside try, but I'm wondering if there's any way I can get debugger to stop stopping. While I don't even mind the error message, the app no longer executes properly.
I've got a this[$val] that I needs to return a null if there is no such variable inside the class.
try {
return this[$val]+"";
} catch(error:ArgumentError) {
// Do nothing
}
return "";
again, this works like it is supposed to, but it causes errors in debugger
any ideas for an alternative?
I think you are catchin an argument error in place of the real problem of handling a null object + string error.Try Using;:
try {
return this[$val]+"";
} catch(error:Error) {
// Do nothing
}
return "";