I need a way to use an object or variable, which is inside of an try/catch, outside of the try/catch.
Im doing automated tests with selenium on a blazor webpage.
There is an element on the webpage, which does change its name dynamically.
My idea now is:
In 99 out of 100 cases, it does always find the variable called selector
, which means, no exception is being thrown. In this case i want to use the object Field
outside of the try/catch.
But in one case, there is one element on the webpage //div[@class='ql-editor']//p
that changes its name during the test to //div[@class='ql-editor ql-blank']//p
. Now, before the test throws me an exception, it should check, if //div[@class='ql-editor ql-blank']//p
is visible.
If yes, then i want to use the object Field
from the catch block outside of the try/catch.
If no, it should throw me an exception
NOTE: Im aware of the fact, that maybe the way i think to fix that problem, isnt the best. I just want to prevent creating another method just for 1 out of 100 cases.
try
{
IWebElement Field = webDriver.FindElement(By.XPath(selector));
Field.SendKeys(textToType);
}
catch (Exception e)
{
IWebElement Field = webDriver.FindElement(By.XPath("//div[@class='ql-editor ql-blank']//p"));
Field.SendKeys(textToType);
}
string checkText = Field.GetAttribute("value");
string checkInstruction = Field.Text;
CodePudding user response:
What RB said...
IWebElement field;
try
{
field = webDriver.FindElement(By.XPath(selector));
}
catch
{
field = webDriver.FindElement(By.XPath("//div[@class='ql-editor ql-blank']//p"));
}
field.SendKeys(textToType);
string checkText = field.GetAttribute("value");
string checkInstruction = field.Text;
There are times when you adopt this pattern you might see "use of unassigned local variable ..." compiler messages - in those cases, you can assign null
or default
when you declare, or you can assign some value that is a suitable default:
IWebElement field = "some sensible default";
try{
...
RB's wisely pointed out in the comments that you get this message because C# can see some path through your code where the variable never got assigned any value. That might be what you expect, or it might not; only you can know that. If you're looking at some code and thinking "by the time I reach line X, variable Y will definitely have some usable value", and C# is telling you not, it's worth checking again. While it's not perfect/doesn't deep dive into every possible scenario (some things cannot be known at compile time, and others are not worth calculating) you should make sure your value is assigned if you're expecting it to have a value by that time
ps; please declare locals using camelCase, and you can optionally omit the e
in Exception e
or even the entire exception type after the catch if you're catching everything and not doing anything with the exception
CodePudding user response:
Just declare the variable outside the try...catch...
block.
IWebElement Field;
try
{
Field = webDriver.FindElement(By.XPath(selector));
}
catch (Exception e)
{
Field = webDriver.FindElement(By.XPath("//div[@class='ql-editor ql-blank']//p"));
}
Field.SendKeys(textToType);
string checkText = Field.GetAttribute("value");
string checkInstruction = Field.Text;
CodePudding user response:
The other two answers are the "easy" answer but, in my opinion, not the right answer. Your posted code isn't following best practices which would clean up a lot of the code and remove the problem you are asking about.
There are two better approaches to what you are attempting.
The preferred way would be to create a locator that checks for both
selector
and theql-blank
case. I can't show you that because you haven't posted the definition ofselector
. As an example, I'll show you using the two locators you did post. Instead of using XPath here, the better choice is CSS selector. The syntax is simpler and easier to read, it's faster executing, and better supported. If you want some more info, watch some of the seleniumconf yt videos where the contributors are talking about locators.Here are the two XPaths you provided.
//div[@class='ql-editor']//p //div[@class='ql-editor ql-blank']//p
Let's convert these two to CSS selectors.
div.ql-editor p div.ql-editor.ql-blank p
and now combine them into a single CSS selector using an OR operator (,).
div.ql-editor p, div.ql-editor.ql-blank p
Now you can update your code to
By locator = By.CssSelector("div.ql-editor p, div.ql-editor.ql-blank p"); IWebElement Field = webDriver.FindElement(locator); Field.SendKeys(textToType); string checkText = Field.GetAttribute("value"); string checkInstruction = Field.Text;
As you can see, this code is much simpler and accomplishes the same thing.
Another approach that follows best practices on dealing with elements that may not exist, would be to use
.FindElements()
and check for an empty list instead of using Exceptions.ReadOnlyCollection<IWebElement> Field = webDriver.FindElements(selector); if (!Field.Any()) { Field = webDriver.FindElements(By.XPath("//div[@class='ql-editor ql-blank']//p")); } Field.ElementAt(0).SendKeys(textToType); string checkText = Field.GetAttribute("value"); string checkInstruction = Field.Text;
This method is not quite as clean as method 1 but this is the better and cleaner approach vs using Exceptions.