WebDriverEventListener take screenshot onException() - selenium

guys. Today I have done my custom realization for WebDriverEventListener. I need only onException() method which will create screenshot. But I got problem because I am using fluent wait.
new FluentWait<>(webDriver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class)
.until(someCondition)
So, finally, I have got screen for each ignoring(NoSuchElementException.class) - 20 screenshots for 1 fail ))). Had somebody the such problem or had someone resolve it?

when you use .ignoring(NoSuchElementException.class) you don't avoid that the exception is raised, you are just ignoring that exception. What is happening is that the exception is being raised by your FluentWait, but it is ignored (when you declare .ignoring(NoSuchElementException.class)).
You have three options here:
Capture the screen at the end of your test if the test failed [preferred].
Have a Try-Catch wherever you are using your FluentWait or any other Selenium code.
Use reflection to avoid capture when the event is raised from the method that implements the FluentWait.
This is an idea after what we have discussed:
private void ExceptionThrown(object sender, WebDriverExceptionEventArgs e)
{
if (e.ThrownException is NoSuchElementException)
{
// Get the stack trace from the current exception
StackTrace stackTrace = new StackTrace(e.ThrownException, true);
// Get the method stack frame index.
int stackTraceIndex = stackTrace.FrameCount - 1;
// Get the method name that caused the exception
string methodName = stackTrace.GetFrame(stackTraceIndex).GetMethod().Name;
if(methodName != "MyFindElement")
{
TakeSceenshot();
}
}
else
{
TakeSceenshot();
}
}
// This is an extension method of the DriverHelper interface
public IWebElement MyFindElement(this IWebDriver driver, By by, int timeOut = 0)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut));
wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
// I wait until the element exist
IWebElement result = wait.Until(drv => drv.FindElement(by) != null);
// it means that the element doesn't exist, so we throw the exception
if(result == null)
{
MyPersonalException(by);
}
}
// The parameter will help up to generate more accurate log
public void MyPersonalException(By by)
{
throw new NoSuchElementException(by.ToString());
}

This probably require changes in EventFiringWebDriver, because this class is without WebDriverWait instance and events for them. If you want avoid it, create bool variable in your EventFiringWebDriver extended class and check this value in your OnException like:
protected void OnException(WebDriverExceptionEventArgs e) {
if (IsWaitHandler)
return;
Your actions...
}
but this is not perfect solution.

Related

How to Take Screenshot when TestNG Assert fails?

String Actualvalue= d.findElement(By.xpath("//[#id=\"wrapper\"]/main/div[2]/div/div[1]/div/div[1]/div[2]/div/table/tbody/tr[1]/td[1]/a")).getText();
Assert.assertEquals(Actualvalue, "jumlga");
captureScreen(d, "Fail");
The assert should not be put before your capture screen. Because it will immediately shutdown the test process so your code
captureScreen(d, "Fail");
will be not reachable
This is how i usually do:
boolean result = false;
try {
// do stuff here
result = true;
} catch(Exception_class_Name ex) {
// code to handle error and capture screen shot
captureScreen(d, "Fail");
}
# then using assert
Assert.assertEquals(result, true);
1.
A good solution will be is to use a report framework like allure-reports.
Read here:allure-reports
2.
We don't our tests to be ugly by adding try catch in every test so we will use Listeners which are using an annotations system to "Listen" to our tests and act accordingly.
Example:
public class listeners extends commonOps implements ITestListener {
public void onTestFailure(ITestResult iTestResult) {
System.out.println("------------------ Starting Test: " + iTestResult.getName() + " Failed ------------------");
if (platform.equalsIgnoreCase("web"))
saveScreenshot();
}
}
Please note I only used the relevant method to your question and I suggest you read here:
TestNG Listeners
Now we will want to take a screenshot built in method by allure-reports every time a test fails so will add this method inside our listeners class
Example:
#Attachment(value = "Page Screen-Shot", type = "image/png")
public byte[] saveScreenshot(){
return ((TakesScreenshot)driver).getScreenshotAs(OutputType.BYTES);
}
Test example
#Listeners(listeners.class)
public class myTest extends commonOps {
#Test(description = "Test01: Add numbers and verify")
#Description("Test Description: Using Allure reports annotations")
public void test01_myFirstTest(){
Assert.assertEquals(result, true)
}
}
Note we're using at the beginning of the class an annotation of #Listeners(listeners.class) which allows our listeners to listen to our test, please mind the (listeners.class) can be any class you named your listeners.
The #Description is related to allure-reports and as the code snip suggests you can add additional info about the test.
Finally, our Assert.assertEquals(result, true) will take a screen shot in case the assertion fails because we enabled our listener.class to it.

Closing resources created in failed constructor

Assume I have a class C that holds resources that need to be closed as member variables.
public class C {
private ClosableResource1 closableResource1;
private ClosableResource2 closableResource2;
.....
public C(){
closableResource1 = new ClosableResource1();
closableResource2 = new ClosableResource2();
.....
// some logic that can fail
}
close(){
closableResource1.close()
closableResource2.close()
.....
}
}
If the constructor succeeds I can be sure that close() will be called eventually by some entity manager and all the resources will be freed.
But how can I make sure I close the resources when the constructor fails? The failure can happen because I have additional logic in the constructor that can throw exception or I get some RuntimeException outside of my control?
Some things I though of:
Wrapping the constructor body with a try-catch block. Then, assuming I have a lot of closable members I'll have to have a big if statement in the catch block checking which resources were already initializing and only close them.
Offloading the ClosableResources creation to some init() function. Then I would have to make sure init() succeeded every time I try to use the object.
Is there some elegant solution? Or is this much more implementation specific then that?
You can do something like below:
public class C {
private List<AutoCloseable> closableResources = new ArrayList();
private ClosableResource1 closableResource1;
private ClosableResource2 closableResource2;
.....
public C() {
closableResource1 = new ClosableResource1();
closableResources.add(closableResource1)
closableResource2 = new ClosableResource2();
closableResources.add(closableResource2);
.....
try {
// some logic that can fail
} catch(Exception e) {
close();
}
}
close(){
for (AutoCloseable closableResource : closableResources) {
if (closableResource != null) {
closableResource.close();
}
}
}
}
Surrounding your code with try-catch and closing all your resources in catch is the correct solution here. Also read about method finalize() (Here is one tutorial). In general, I would recommend one method that cleans up all the resources (like you suggested method close(), I would call it though cleanup()) and call that method in your catch section and in your finalize() method
I asked and answered a very similar question here. It is very important that a constructor either succeeds or fails completely i.e. leaving no resources open. In order to achieve that I would follow each resource creation statement by a try-catch block. The catch block closes the resource and rethrows the exception so it is not lost:
public C() {
closableResource1 = new ClosableResource1();
closableResource2 = new ClosableResource2();
try {
// .....
// some logic that can fail and throw MyCheckedException or some RuntimeException
} catch (RuntimeException | MyCheckedException e) {
try {closableResource1.close();} catch (Exception ignore) {}
try {closableResource1.close();} catch (Exception ignore) {}
throw e;
}
}
If creating a resource can fail you need nested try-catch blocks as demonstrated here.
Here's a wild idea: create a class called something like DefusableCloser (that you can "defuse", like an explosive device being made safe):
class DefusableCloser implements AutoCloseable {
boolean active = true;
final AutoCloseable closeable;
DefusableCloser(AutoCloseable closeable) {
this.closeable = closeable;
}
#Override public void close() throws Exception {
if (active) closeable.close();
}
}
Now you can use this in a try-with-resources block:
c1 = new CloseableResource();
try (DefusableCloseable d1 = new DefusableCloseable(c1)) {
c2 = new CloseableResource();
try (DefusableCloseable d2 = new DefusableCloseable(c2)) {
// Do the other stuff which might fail...
// Finally, deactivate the closeables.
d1.active = d2.active = false;
}
}
If execution doesn't reach d1.active = d2.active = false;, the two closeables (or one, if the exception was in creating the second resource) will be closed. If execution does reach that line, they won't be closed and you can use them.
The advantage of doing it like this is that the exceptions will be correctly handled.
Note that the ordering is important: don't be tempted to create the two CloseableResources first, then the two DefusableCloseables: doing that won't handle an exception from creating the second CloseableResource. And don't put the creation of the CloseableResources into the TWR, as that would guarantee their closure.
For closing the resources in your class' close() method, you can also use try-with-resources to ensure that both resources are closed:
try (c1; c2) {}
You don't actually have to declare a new variable in the TWR syntax: you can just effectively say "close the resource for this existing variable afterwards", as shown here.

Check if a WebElement is stale without handling an exception

I'm currently checking to see if a WebElement is stale by doing the following:
public static boolean isStale(WebElement element) {
try {
element.click();
return false;
} catch (StaleElementReferenceException sere) {
return true;
}
}
This is the same as the solution offered to this question:
Check for a stale element using selenium 2?
However, this seems rather messy to me. Is there a cleaner way that I can check if an element is stale, without having to throw and catch an exception?
(Also, as a side, if I have to stick with throwing and catching an exception, is there something better to do than clicking/sending keys/hovering to throw said exception? I might have a WebElement that I don't want to do any of these actions on, as it may inadvertently affect something else.)
Webdriver itself uses the try/catch-construction to check for staleness as well.
from org.openqa.selenium.support.ui.ExpectedConditions.java:
public static ExpectedCondition<Boolean> stalenessOf(final WebElement element) {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver ignored) {
try {
// Calling any method forces a staleness check
element.isEnabled();
return false;
} catch (StaleElementReferenceException expected) {
return true;
}
}
#Override
public String toString() {
return String.format("element (%s) to become stale", element);
}
};
}
The isEnabled() check is better than using a click action - clicking an element might cause unwanted side effects, and you just want to check the element's state.
I know this already has an accepted answer and I don't know the bigger context of how you use the staleness check but maybe this will help you or others. You can have ExpectedConditions.stalenessOf(WebElement) do the work for you. For example,
WebElement pageElement = driver.findElement(By.id("someId"));
WebDriverWait wait = new WebDriverWait(webDriver, 10);
// do something that changes state of pageElement
wait.until(ExpectedConditions.stalenessOf(pageElement));
In this case, you don't have to do pageElement.click(), etc. to trigger the check.
From the docs, .stalenessOf() waits until an element is no longer attached to the DOM.
References: ExpectedConditions
Classic statement for C# to check staleness of web element
protected bool IsStale
{
get { return ExpectedConditions.StalenessOf(webElement)(WebDriver); }
}
I don't fully understand what you want to do. What do you mean by 'messy' solution?
Maybe you can use an explicite wait an as expected condition stalenessOf in combination with not.
But every solution with that don't seems stable to me.
What I do is, that I have an clicking routine in a helperclass, the idea is like:
public void ClickHelper(WebDriver driver, By by){
int counter = 1;
int max = 5;
while (counter <= max) {
try {
WebElement clickableWebElement = driver.findElement(by);
clickableWebElement.click();
return;
} catch (StaleElementReferenceException e) {
System.out.print("\nTry " + counter + " with StaleElementReferenceException:\n" + e.getMessage() + "\n");
}
versuche++;
}
throw new RuntimeException("We tried " + max + " times, but there is still an Exception. Check Log!");
}
Be careful, I just entered this by simplyfying my own methode (there are some more checks and personally I use xpath and not by etc). There might be some typo-mistakes, but i guess you will understand the basic idea. Since I use this Helpermethode, I don't have to care about Staleness of webelements. You can alter the max-value, but personally I think, if the website is such unstable, that the Element is stale so much, I would talk to the developer, because this would not be a good website.
This should work without dependency of display/ enabled:
def is_element_on_page(element):
try:
element.get_attribute('')
return True
except StaleElementReferenceException:
return False

Trigger new onException route from onRedelivery

I have an ErrorHandler (DefaultErrorHandler) into which I have provided an onRedelivery ref. By default the ErrorHandler retries unlimited times. However, if a certain condition exists (currently determined by the onRedelivery ref) I would like to exit the redelivery loop and execute a different route.
My initial thought was to have the onRedelivery ref throw and exception and have an appropriate onException direct this to the appropriate route. However, I find that the RedeliveryErrorHandler catches this exception and keeps looping.
I have also found that I can set the Exchange.REDELIVERY_EXHAUSTED to true which will exit the redelivery loop but will not direct me to my recovery route.
Any suggestions?
Edit
So I have found that if I add the original exception type to the onException of the exception type in the RouteBuilder in which I have my ErrorHandler, and if I set the Exchange.REDELIVERY_EXHAUSTED to true, the original exception will be thrown to the RouteBuilder scope and caught by the onException. However, I would really prefer to throw and catch a new exception type so that the handling is explicit to this case.
Answer
So Peter's suggestion of using retryWhile was great in that it allows me to programmatically determine when to stop retrying. It's too. It only went half way thought. The second part was to send the failing exchange to a new / different route for error handling. This is accomplished by using the DeadLetterChannel instead of the DefaultErrorHandler.
Use retryWhile in combination with deadLetterChannel:
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() {
errorHandler(deadLetterChannel("direct:special")
.retryWhile(method(new MyPredicate())));
from("direct:start")
.log("Starting...")
.throwException(new Exception("dummy"));
from("direct:special")
.log("...Special");
}
}
public class MyPredicate implements Predicate {
#Override
public boolean matches(final Exchange exchange) {
AtomicInteger counter = exchange.getProperty("myCounter");
if (counter == null) {
counter = new AtomicInteger(0);
exchange.setProperty("myCounter", counter);
}
int count = counter.incrementAndGet();
LOG.info("Count = {}", count);
return count < 3; // or whatever condition is suitable
}
}
This prints:
INFO Starting...
INFO Count = 1
INFO Count = 2
INFO Count = 3
INFO ...Special

Problem attaching WatiN to IE

I am experimenting with WatiN for our UI testing, I can get tests to work, but I can't get IE to close afterwards.
I'm trying to close IE in my class clean up code, using WatiN's example IEStaticInstanceHelper technique.
The problem seems to be attaching to the IE thread, which times out:
_instance = IE.AttachTo<IE>(Find.By("hwnd", _ieHwnd));
(_ieHwnd is the handle to IE stored when IE is first launched.)
This gives the error:
Class Cleanup method
Class1.MyClassCleanup failed. Error
Message:
WatiN.Core.Exceptions.BrowserNotFoundException:
Could not find an IE window matching
constraint: Attribute 'hwnd' equals
'1576084'. Search expired after '30'
seconds.. Stack Trace: at
WatiN.Core.Native.InternetExplorer.AttachToIeHelper.Find(Constraint
findBy, Int32 timeout, Boolean
waitForComplete)
I'm sure I must be missing something obvious, has anyone got any ideas about this one?
Thanks
For completeness, the static helper looks like this:
public class StaticBrowser
{
private IE _instance;
private int _ieThread;
private string _ieHwnd;
public IE Instance
{
get
{
var currentThreadId = GetCurrentThreadId();
if (currentThreadId != _ieThread)
{
_instance = IE.AttachTo<IE>(Find.By("hwnd", _ieHwnd));
_ieThread = currentThreadId;
}
return _instance;
}
set
{
_instance = value;
_ieHwnd = _instance.hWnd.ToString();
_ieThread = GetCurrentThreadId();
}
}
private int GetCurrentThreadId()
{
return Thread.CurrentThread.GetHashCode();
}
}
And the clean up code looks like this:
private static StaticBrowser _staticBrowser;
[ClassCleanup]
public static void MyClassCleanup()
{
_staticBrowser.Instance.Close();
_staticBrowser = null;
}
The problem is that when MSTEST executes the method with the [ClassCleanup] attribute, it will be run on a thread that isn't part of the STA.
If you run the following code it should work:
[ClassCleanup]
public static void MyClassCleanup()
{
var thread = new Thread(() =>
{
_staticBrowser.Instance.Close();
_staticBrowser = null;
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
The WatiN website briefly mentions that WatiN won't work with threads not in the STA here but it isn't obvious that [TestMethod]'s run in the STA while methods like [ClassCleanup] and [AssemblyCleanupAttribute] do not.
By default when IE object are destroyed, they autoclose the browser.
Your CleanUp code may try to find a browser already close, which why you have an error.
Fixed this myself by dumping mstest and using mbunit instead. I also found that I didn't need to use any of the IEStaticInstanceHelper stuff either, it just worked.