Catch ElementClickInterceptedException in Selenium with C# - c#

I'm trying to catch a ElementClickInterceptedException in C#, but it apppears I'm doing something wrong since it doesn't go to the catch code line when I get that exception while debugging. Strange thing is that if the test runs normally, it doesn't throw the exception at that point, but when it runs in debug mode, it does...
I try catching the exception because Selenium keeps throwing it and I don't know what to do to solve it.

Seems like I have been catching the wrong exception all along. Anyway, I'll leave the code that worked for me when I got a TargetInvocationException or ElementClickInterceptedException so anyone facing the same issue can solve it like I did:
public bool clickBtn(IWebElement btnElement)
{
bool result = false;
int attempts = 0;
while (attempts < 10)
{
try
{
waitForClickable(btnElement);
btnElement.Click();
result = true;
break;
}
catch (TargetInvocationException e)
{
}
catch (StaleElementReferenceException e)
{
}
attempts++;
Thread.Sleep(2000);
}
return result;
}
I think you can get rid of the second catch and it will work all the same :)
Also, I leave the code for the "waitForClickable" method:
internal void waitForClickable(IWebElement button)
{
try
{
wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementToBeClickable(button));
}
catch (NoSuchElementException e)
{
throw new NoSuchElementException("It wasn't possible to click the element.\n" + e);
}
}

I wrote a Click() method for my framework that takes care of exceptions, retries, etc. Also, you don't need the Thread.Sleep() in there since the WebDriverWait takes care of waiting for the element to be clickable already. In my code, I replaced the loop and counter with a pure timeout in seconds.
/// <summary>
/// Clicks the element.
/// </summary>
/// <param name="locator">The By locator for the desired element.</param>
/// <param name="timeOut">[Optional] How long to wait for the element (in seconds). The default is 10s.</param>
public void Click(By locator, int timeOut = 10)
{
DateTime now = DateTime.Now;
while (DateTime.Now < now.AddSeconds(timeOut))
{
try
{
new WebDriverWait(Driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementToBeClickable(locator)).Click();
return;
}
catch (Exception e) when (e is ElementClickInterceptedException || e is StaleElementReferenceException)
{
// do nothing, loop again
}
}
throw new Exception($"Not able to click element <{locator}> within {timeOut}s.");
}

Related

"Unhandled" Exception not being caught from inside a try-catch block

I am attempting to run an async output that will last a large amount of time, and then closing the application during execution which causes the textbox to dispose. I thought this would be handled by simply returning in a try-catch statement, but VS still says there is an "unhandled" exception. Here is the code:
public void AppendOutput(string text)
{
var timeNow = DateTime.Now;
if ((DateTime.Now - previousTime).Milliseconds <= 50) return;
try
{
synchronizationContext.Post(new SendOrPostCallback(o =>
{
Output.AppendText((string)o);
}), text);
}
catch(ObjectDisposedException e)
{
return;
}
previousTime = timeNow;
}
Here is what happens in debug:
I there a reason why this is considered unhandled? I thought that's what try-catch was for. My understanding was that I could simply return because there's no need to handle exceptions for a program that is attempting to write to a textbox that has been disposed; the program should be ending the thread on its own.
What is the correct way to deal with this problem?
According to your description, you want to solve the abnormal problem that occurs during debugging.
You can add the following code in the initialization component function, as shown below:
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
Result:

Xamarin.Forms Index was out of range exception sometimes showing up, but not always, How do I fix this?

I'm trying to get a new page shown depending on the selectedIndex in Xamarin.Forms.
public void NavigateToNextPage()
{
try
{
Result selected = lvwQuesions.SelectedItem as Result;
if (selected != null)
{
Navigation.PushAsync(new DetailQuizMasterPage(selected));
lvwQuesions.SelectedItem = null;
}
}
catch (Exception ex)
{
throw ex;
}
}
This code works most of the time, but sometimes (I can't repcoduce effectively) my app crashes and I get the "Index was out of range. Must be non-negative and less than the size of the collection parameter name:index" exception.
private void lvwQuesions_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
NavigateToNextPage();
}
this is where i call my function. I don't really know where i'm trying to access anything by index so thiss error comes as a surprise.
Also this is a school project so i'm very new to Xamarin.Forms

Trigger QuerySubmitted once

I have a AutoSuggestBox with QuerySubmitted property, so when I hit enter button , it will search for products and will show error message when no data found , my problem is it will show twice or multiple times when i hit enter multiple times too.
here is my code:
try {
if (!ViewModel.IsBusy) {
ViewModel.IsBusy = true;
await this.ViewModel.FindAsync(args.QueryText);
}
}
catch (Exception e) {
}
finally {
ViewModel.IsBusy = false;
}
Its because the second call to your function is making the bool false and hence the 3rd call will go into if condition and will do a FindAsync()
Instead you can do this :
try {
if (!ViewModel.IsBusy) {
ViewModel.IsBusy = true;
await this.ViewModel.FindAsync(args.QueryText);
ViewModel.IsBusy = false;
}
}
catch (Exception e) {
ViewModel.IsBusy = false;
}
Or you can really use Task Cancellation for better design and you will get the benefit of sending the latest args.QueryText to the FindAsync if there are changes in querytext between multiple Enter key hit. Of course, you need to cancel the earlier Task if you encounter that there is a new call.

Exception in bound Property's Set method not caught by Application.ThreadException event

It appears that exceptions that occur in a property's Set method do not bubble up to the Application's ThreadException event.
We use that event along with the AppDomain.CurrentDomain.UnhandledException event to catch any unexpected mishaps that occur in the application. The exception details are written to a log so our support and development team can better evaluate the issue. Sadly it looks like this Catch All falls short in this particular case.
There are several similar questions on StackOverflow, But no answer addresses the issue of the global exception handling not catching the exception. I already know we can fix it so no exception occurs. We could add a TryCatch block to every setter. We could add the BindingComplete event to each databinding and get the exception that way. But all of that defeats the purpose of having global exception handling which works perfectly in any other case.
How do I 'globally' catch exceptions thrown in object instances
Data Binding and throwing exception in setter
Neither Application.ThreadException nor AppDomain.CurrentDomain.UnhandledException are respected
To reproduce the issue, simply create a form with a text box, bind the text box to a property and throw an exception in the property's set method. Add the ThreadException and UnhandledException events to the program.cs. Run the program and type in the text box to trigger the exception. The debugger will break on the exception, press Continue (F5) the let the exception bubble up as it would outside of the debugger. Any normal exception would end up in those events, but this one does not.
Form1.cs
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
textBox1.DataBindings.Add("Text", this, "TestValue", true, DataSourceUpdateMode.OnPropertyChanged);
}
private string _TestValue = "";
public string TestValue
{
get{return _TestValue;}
set
{
_TestValue = value;
throw new Exception("Something bad happened in here");
}
}
Program.cs
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += ThreadExceptionHandler;
AppDomain.CurrentDomain.UnhandledException += new System.UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
Application.Run(new Form1());
}
private static void ThreadExceptionHandler(object sender, System.Threading.ThreadExceptionEventArgs args)
{
try
{
//RR.Common.ErrorLogRt.WriteError(args.Exception.StackTrace.ToString(), args.Exception.Message.ToString(), true);
MessageBox.Show(args.Exception.Message);
}
catch
{
MessageBox.Show("Error writing to exception log. This program will now terminate abnormally.");
Application.Exit();
}
}
static void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs e)
{
try
{
if (e != null)
{
Exception ex = e.ExceptionObject as Exception;
//RR.Common.ErrorLogRt.WriteError(ex.StackTrace.ToString(), ex.Message.ToString(), true);
MessageBox.Show(ex.Message);
}
else
{
MessageBox.Show("Unhandled Error: " + e.ToString());
}
}
catch
{
MessageBox.Show("Error writing to exception log. This program will now terminate abnormally.");
Application.Exit();
}
}
static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
try
{
if (e != null && e.Exception != null && e.Exception.InnerException != null)
{
//The unobserved exception is always the same, The actual exception that cause it will be the inner exception.
Exception ex = e.Exception.InnerException;
MessageBox.Show(e.Exception.Message);
//RR.Common.ErrorLogRt.WriteError(ex.StackTrace.ToString(), ex.Message.ToString(), true);
}
else
{
MessageBox.Show("Unhandled Error: " + e.ToString());
}
}
catch
{
MessageBox.Show("Error writing to exception log. This program will now terminate abnormally.");
Application.Exit();
}
}
}
Remarks from Binding.FormattingEnabled Property
Setting this property to true also enables error-handling behavior and
causes the BindingComplete event to be raised. The handler of this
event can take the appropriate action, based on the success, error, or
exceptions in the binding process, by examining the
BindingCompleteState property of the BindingCompleteEventArgs
parameter.
The code involved
internal bool PushData(bool force)
{
Exception ex = null;
if (!force && this.ControlUpdateMode == ControlUpdateMode.Never)
{
return false;
}
if (this.inPushOrPull && this.formattingEnabled)
{
return false;
}
this.inPushOrPull = true;
try
{
if (this.IsBinding)
{
object value = this.bindToObject.GetValue();
object propValue = this.FormatObject(value);
this.SetPropValue(propValue);
this.modified = false;
}
else
{
this.SetPropValue(null);
}
}
catch (Exception ex2)
{
ex = ex2;
if (!this.FormattingEnabled)
{
throw;
}
}
finally
{
this.inPushOrPull = false;
}
if (this.FormattingEnabled)
{
BindingCompleteEventArgs bindingCompleteEventArgs = this.CreateBindingCompleteEventArgs(BindingCompleteContext.ControlUpdate, ex);
this.OnBindingComplete(bindingCompleteEventArgs);
return bindingCompleteEventArgs.Cancel;
}
return false;
}
As you can see, passing 4th parameter as true: DataBindings.Add("Text", this, "TestValue", true is responsible for catching the exception inside PushData and passing it to BindingComplete event. There is no other way (except AppDomain.CurrentDomain.FirstChanceException) to find the exception anywhere else than in BindingComplete if formatting is enabled.
I know a solution exists for WPF, but I could not make it work for winforms.
It seems like the exception is somehow trapped by the framework and I cant find the right trace to listen to.
What you could do though is handle first-chance exceptions (beware that this will probably make you catch way more than what you want).
This will show a message box with "Something bad happened in here" in your example:
AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException;
//...
private static void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs firstChanceExceptionEventArgs)
{
if(firstChanceExceptionEventArgs.Exception is TargetInvocationException)
{
if(firstChanceExceptionEventArgs.Exception.InnerException != null)
MessageBox.Show(firstChanceExceptionEventArgs.Exception.InnerException.Message);
else
MessageBox.Show(firstChanceExceptionEventArgs.Exception.Message);
}
}
If you are curious, this is the WPF solution I was talking about:
https://web.archive.org/web/20140809204919/https://www.tech.pro/tutorial/940/wpf-snippet-detecting-binding-errors
It looks like it has been reported as a defect to Microsoft, who have closed it as 'Won't Fix':
ReflectPropertyDescriptor.SetValue does not preserve stack trace
in the Microsoft Reference Source, the code for the SetValue method (lines 1085 to 1173) contains a block with a structure like this:
try // <--- This ...
{
try
{
// Code to invoke SetMethod.
}
catch(Exception)
{
// Code to rewind.
// Code to throw inner or rethrow.
}
}
finally // <--- ... and this consume the exception before you can handle it.
{
// Code to raise change notification.
}
The outer try ... finally block is consuming the (second chance) exception that is preventing you from handling it in your code. The dbugger can still catch the (first chance) exception, but it wont get out of the SetValue method.

Simple C# Windows App - Catch statement always executes no matter what

Here's the code for the event handler involved:
private void textBox1_TextChanged(object sender, EventArgs e)
{
try
{
seed = Convert.ToInt32(this.Text);
}
catch (FormatException)
{
MessageBox.Show("Input string is not a sequence of digits.");
}
catch (OverflowException)
{
MessageBox.Show("The number cannot fit in an Int32.");
}
}
It's supposed to ensure a user doesn't type anything but a number allowable by Int32 into the text box, but the first catch statement executes EVERY time you try to type ANYTHING into the box. I've looked around but I can't seem to figure out why...
Probably because this.Text doesn't read from the input box, but rather the class the handler is defined in.
I believe what you want is:
try
{
seed = Convert.ToInt32(((TextBox)caller).Text);
}
It might be helpful to see the error message, using the following (temporarily of course):
catch (FormatException exception)
{
MessageBox.Show("Input string is not a sequence of digits."
+ "Exception message was: " + exception.getMessage());
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
try
{
seed = Convert.ToInt32(textBox1.text);
}
catch (FormatException)
{
MessageBox.Show("Input string is not a sequence of digits.");
}
catch (OverflowException)
{
MessageBox.Show("The number cannot fit in an Int32.");
}
}
Please use the above statement and it should work correctly. If you type in a number the first exception will not execute.

Categories

Resources