Browse Category: Selenium WebDriver

Recording Selenium Test Execution

After long time, got few min to think about new blog. There are many blog available for each and every solution but I was thinking to have few which is either not available or very limited information available over internet. I have free version of sauce lab and I am always fascinated by this kind of tool and I would love to build such tool sometime in future. There is one feature that is recording the session is always attracted me. I tried to find some resources which can help me to achieve so in my framework.

I found Microsoft expression encoder to do recording your screen. You can use their dlls to add into your C# based framework to execute and record the session. In you framework you can write a method which starts recording since beginning and later during cleanup task, you can have some login to determine if you want to save recording or not. For example, I my framework, I start recording based on my configuration file and in teardown methods, I check if there is an error or not. if yes then I encode into wmv format else I discard recording.




Follow following steps to have code and settings into framework:

Step 1:

Install Microsoft Encoder Expression: Refer CerebrumLabs.com for that (http://www.cerebrumlabs.com/free-screen-recording-software/). Once you install, you may get following folder in installation location. C:\Program Files (x86)Microsoft Expression. If you try to explore few folders inside this folder you will find SDK folder @: C:\Program Files (x86)\Microsoft Expression\Encoder 4\SDK, where you can see Microsoft.Expression.Encoder.dlls which you can use in your framework code.

Step 2:

Include dlls given in SDK folders into your framework. You can write a method and call that. I have a key value pair in my framework config file and I can decide if I want to do recording or not.  In your test’s [setup] method, you can call this method which will start recording at the beginning of the test.

using System;

.

.

using OpenQA.Selenium;

.

.

using Microsoft.Expression.Encoder.ScreenCapture;

using System.Drawing;

using Microsoft.Expression.Encoder.Profiles;

using Microsoft.Expression.Encoder;

namespace FRAMEWORK

{

    //Call this method in setup method.   
    public static void StartRecordingVideo()

    {

        //Provide setting in config file if you want to do recording or not.
        if (testEInfo.isRecording)

        {

            job = new ScreenCaptureJob();

            job.CaptureRectangle = Screen.PrimaryScreen.Bounds;

            job.ShowFlashingBoundary = true;

            //provide the location where you want to save the recording.
            job.OutputPath = AutomationLogging.newLocationInResultFolder;

            job.Start();

        }

    }

}

Step 3:

Now your test started and in the background your screen recording going on. once you reach to the [teardown] method. you can decide if you want to keep the recording or not. In my case I want to keep recording only if there is test failure so my developers can review else there is no point of having recording if tests are passing. To do so I have following method in above code which I call in code at the very end.

public static void StopRecordingVideo()
        {
            if (testEInfo.isRecording)
            {
                string filename = job.ScreenCaptureFileName;
                job.Stop();
                if (AutomationLogging.countOfError > 0)
                {
                    MediaItem src = new MediaItem(filename);
                    Job jb = new Job();
                    jb.MediaItems.Add(src);
                    jb.ApplyPreset(Presets.VC1HD720pVBR);
                    jb.OutputDirectory = AutomationLogging.newLocationInResultFolder;
                    string output = ((Microsoft.Expression.Encoder.JobBase)(jb)).ActualOutputDirectory;
                    jb.Encode();
                }

                File.Delete(filename);
            }
        }

Conclusion:

during encoding, you may notice that encoder is eating little more memory and you system may little slow. Try at your end and let me know if you have any question.

Smart click (part 1)

When using the Selenium Webdriver tool for testing web-based applications, I faced a problem: sometimes the common Click() method does not work for specific elements. Or, for example, it may work fine in the FF browser and fails to click in Internet Explorer. After a little investigation, I noticed that instead of the Click() method I can use methods from the Actions class, or I can click elements with JavaScript. But I also discovered that I have to use one action for FF and another for IE – often an action worked with one browser but failed with the other. I had to add extra logic for specific elements and it began spreading some mess in my code.

Then a couple of months later “funny” things started to happen regularly. Guys from Mozilla Corp. or Microsoft delivered a new version of their browser. The old version of Selenium Webdriver didn’t support this new browser, so I had to upgrade it to the latest one. But oops… most of my specific clicks turned out to work conversely. Or did not work at all, and I had to return to the common Click() method. Chaos in my code was about to come.

That’s why I started looking for a method that would work consistently with any browser, webdriver, or elements and would also give me some additional helpful features like events logging with screenshots, handling exceptions, coded-behind verification, etc. Finally, I realized I had to invent it myself.

I asked myself what I do when I click a web element (assume a button) in a browser manually and came up with the following list:

  1. I determine what the button I am going to click.
  2. I am sure if I can click the button. I check if it is present on the page, is displayed, is enabled for a click, etc. In other words, I verify conditions for a successful click.
  3. Then I click the button.
  4. I verify that click has been successful, that some changes has occurred – expected or not – even if I’ve got an error, it means that the click itself has happened. So, I verify conditions after the click.

I do all the thing from the list above unconsciously. So does everyone else.

So I decided to write my own version of the Click() method reproducing all my manual actions for clicking a button in real life. Here is the recipe:

If you have separate classes for different types of web elements in your testing framework, such as buttons or links, you can add the method Click() to this class(es) and use a private IWebElement instance defined inside the class for interactions. For example:

public class WebButton
{    
    private IWebElement element;
    public WebButton(/*constructor parameters*/) 
    {
        element = //instance of IWebElement according to constructor parameters
        //bla-bla
    }

    public void Click(/*possible parameters*/)
    {
        //logic for clicking the element in a smart way
    }
}

If you use an ordinary IWebElement interface for describing web elements, you can create an extension method for the interface. Like this:

public static class Extensions
{
    public static void Click(this IWebElement buttonToClick, /*possible parameters*/)
    {
        //logic for smart click on buttonToClick
    } 
}

You will be able to invoke the methods in your tests in this way:

//1st case
WebButton button = new WebButton(/*constructor parameters*/);
button.Click();

//2nd case
IWebElement button = driver.FindElement(By.Id("buttonID"));
button.Click();

 

 

Smart click (part 2)

Here is the explanation how you can implement your own Click() method and what is behind the scenes. I will describe the method using a pure IWebElement instance. To be able to invoke the method out of an IWebElement, it should be declared as an IWebElement interface extension method. The method will have a couple of overridden versions for different sets of input parameters.

Ok, let’s start. First of all let’s define what the method should do:

  • It checks if the clicking action may be done
  • It checks if all the necessary conditions for successful clicking are met (for example, some other elements are displayed in the specified state)
  • It clicks the element
  • It verifies if the clicking action has been performed and checks the result of the click

How it does it:

  1. It verifies the element exists, is visible and is available for clicking
  2. It starts the loop. The number of iterations is presented by one of the parameters
  3. It invokes a method which is passed as an input parameter and verifies preconditions for successful clicking (checks if some necessary elements are in the correct state, clicks some other elements to meet the expected conditions, and performs all the actions required to prepare your web element for successful clicking)
  4. It tries to click the element with one of the approaches passed as a parameters (list of clicking actions)
  5. It invokes a method passed as a parameter which verifies that the clicking action has been performed and the expected result has been achieved.
  6. If the expected result is not met, it proceeds to the next clicking action from the parameter list

This is the end of the theory, now let’s begin with practice.

Create a simple test aka testing Google Search page:

using System;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;

namespace SmartClick
{
   [TestFixture]
   public class TestClass
   {
      IWebDriver driver;

      [SetUp]
      public void Setup()
      {
         driver = new FirefoxDriver();
      }

      [TearDown]
      public void Teardown()
      {
         driver.Quit();
      }

      [Test]
      public void GoogleSearch()
      {
         driver.Navigate().GoToUrl("http://www.google.com ");
         IWebElement query = driver.FindElement(By.Name("q"));
         query.SendKeys("selenium");

         IWebElement btnSearch = driver.FindElement(By.Name("btnG"));
         //assume this method is working fine now but does not work with previous version of your browser (or with another browser) and the customer just eager to run your tests with both versions
         btnSearch.Click();

         WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
         wait.Until((d) => { return d.Title.StartsWith("selenium"); });
         Assert.AreEqual("selenium - Google Search", driver.Title);
      }
   }
}

Now let’s start writing our own clicking method. I named it SmartClick(). Add a static class to the namespace and put a static void method SmartClick() into it:

public static class Extensions
{
   public static void SmartClick(this IWebElement element)
   {
      element.Click();
   }
}

Now you can replace btnSearch.Click(); with btnSearch.SmartClick();

Or you can invoke the method this way:

Extensions.SmartClick(btnSearch);

because it is static.

Now let’s check that you did not pass null as a parameter and the element is displayed and enabled for clicking (step 1)

public static class Extensions
{
   public static void SmartClick(this IWebElement element)
   {
      if (element == null) 
      { 
         //add 'Element is null' error message into your log file or throw NoSuchElement or NullReference exception 
      }
      if(!element.Displayed) 
      { 
         //add 'Element is not displayed and cannot be clicked' error message into your log file 
         //you may add a screenshot here
      }
      if(!element.Enabled) 
      {
         //add 'Element is not displayed and cannot be clicked' error message into your log file
         //plus a screenshot
      }
      element.Click();
   }
}

Step 2 – wrap the clicking action into a loop. There is no sense in it right now but in the future it will be used for multiple attempts to click the element if it is necessary. The number of iterations is one of the method parameters with value 1 as default.

public static class Extensions
{
   public static void SmartClick(this IWebElement element, int iterations = 1)
   {
      int i = iterations;
   
      if (element == null) 
      { 
         //add 'Element is null' error message into your log file or throw NoSuchElement or NullReference exception 
      }
      if(!element.Displayed) 
      { 
         //add 'Element is not displayed and cannot be clicked' error message into your log file 
         //you may add a screenshot here
      }
      if(!element.Enabled) 
      {
         //add 'Element is not displayed and cannot be clicked' error message into your log file
         //plus a screenshot
      }
      
      while (i > 0)
      {
         i--;
         element.Click();
      }      
   }
}

Inside the loop, you can do any precondition, clicking actions and post-clicking verification to make successful click.

Step 3 – invoke a method that checks or does some preparation for successful clicking actions. You can put here almost any method which will be doing almost anything you need. To do this, you have to create a delegate for a method and then to initialize it, pass it as a parameter to the method and invoke it inside the loop. Add the following delegate to the namespace:

public delegate bool CustomFunction(params object[] obj);

and pass the delegate as a parameter to the SmartClick method:

public static void SmartClick(this IWebElement element, CustomFunction precondition = nullint iterations = 1)
   {
      int i = iterations;
      string elementName = element.Text;

      if (precondition == null)
         precondition = x => true; //if you did not specify the method let's assume it has passed (return true)
      
      while (i > 0)
      {
         i--;
         if (!precondition.Invoke())
         {
            //add string.Format("Preconditions for clicking '{0}' web element are not met", elementName) error message into your log file
            //screenshot
            continue; //there is no sense to do clicking action if precondition method has failed. Return back to the beginning of the loop and start again from the very beginning
         }
         if (element == null)   
         {   
            //add 'Element is null' error message into your log file or throw NoSuchElement or NullReference exception   
         }
         if(!element.Displayed)   
         {   
            //add 'Element is not displayed and cannot be clicked' error message into your log file   
            //you may add a screenshot here  
         }  
         if(!element.Enabled)   
        {  
           //add 'Element is not displayed and cannot be clicked' error message into your log file      //plus a screenshot  
         }
         element.Click();
      }      
   }

Now you can invoke the SmartClick method in this way:

btnSearch.SmartClick(x =>
{
   try
   {
      IWebElement query = driver.FindElement(By.Name("q"));
      query.SendKeys("selenium");
      return true;
   }
   catch (Exception e)
   {
      //add "SmartClick preconditions error: " + e.Message error message into your log file
      return false;
   }
});

Above I passed an anonymous method as a parameter but actually there are a lot of ways to use this delegate – and this is your choice how to do it. A couple of examples:

btnSearch.SmartClick();//preconditions are always true because precondition parameter is null by default
btnSearch.SmartClick(x => SomeMethod("blah", "blah-blah", "blah-blah-blah"));//invokes precondition method with parameters
CustomFunction myDelegate = SomeMethod;
btnSearch.SmartClick(myDelegate);//using the delegate instance

Step 4 – clicking the element. I mentioned that the method must perform different clicking actions on the web element according to input parameters. Therefore there must be additional parameter which specifies the action. You are free to implement it as you wish but I used an enumerator for it. I pass its value to the method and then handle it inside the switch operator.

Add a new enumerator inside the namespace

public enum ClickAction
{
   Click,
   Submit,
   DoubleClick,
   LeftMBClick,
   RightMBClick,
   JSClick,
   CursorClick,
   SendKeyEnter,
   SendKeyReturn,
   SendKeySpacebar
}

This is the list of clicking actions I sometimes use in relation to specific web elements. You can use some of them or implement your own ones. Keep it in mind that some of the actions used here require an instance of IWebDriver, therefore you have to pass it to the method as a parameter or to make it available for use inside the method.

Now update the method with new input parameters and inner implementation:

public static void SmartClick(this IWebElement element, IWebDriver driver = null, CustomFunction precondition = nullint iterations = 1, params ClickAction[] clicks)
   {
      int i = iterations;

      //if you do not specify what actions to use for clicking the following default actions will be used
      ClickAction[] clickActions = clicks != null ? clicks : new ClickAction[] { ClickAction.Click, ClickAction.LeftMBClick, ClickAction.JSClick };
   
      string elementName = element.Text;

      if (precondition == null)
         precondition = x => true; //if you did not specify the method let's assume it has passed (return true)
      
      while (i > 0)
      {
         i--;
         if (!precondition.Invoke())
         {
            //add string.Format("Preconditions for clicking '{0}' web element are not met", elementName) error message into your log file
            //screenshot
            continue; //there is no sense to do clicking action if precondition method has failed. Return back to the beginning of the loop and start again from the very beginning
         }
         if (element == null)   
        {
           //add 'Element is null' error message into your log file or throw NoSuchElement or NullReference exception   
        }  
        if(!element.Displayed)   
        {    
           //add 'Element is not displayed and cannot be clicked' error message into your log file      
          //you may add a screenshot here  
        }  
        if(!element.Enabled)   
        {  
           //add 'Element is not displayed and cannot be clicked' error message into your log file  
          //plus a screenshot  
        }
         foreach (var action in clickActions)
         {
            //here you may add string.Format("Clicking '{0}' web element with {1} click action", elementName, action) message into your log file
            switch (action)
            {
               case ClickAction.Click:
                  try
                  {
                      element.Click();
                  }
                  catch (Exception e)
                  {
                      //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.Submit:
                  try
                  {
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.DoubleClick:
                  try
                  {
                     var builder = new Actions(driver);
                     builder.DoubleClick().Build().Perform();
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  } 
                  break;
              
               case ClickAction.RightMBClick:
                  if (driver == null)
                  {
                     //"SmartClick clicking error: IWebDriver instance must be passed as a parameter and connot be null if you use clicking with right mouse button action" error message
                     break;
                  }
                  try
                  {
                      var builder = new Actions(driver);
                      builder.MoveToElement(element).ContextClick(element).Build().Perform();
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.JSClick: 
                  if (driver == null)
                  {
                     //"SmartClick clicking error: IWebDriver instance must be passed as a parameter and connot be null if you use clicking with JavaScript action" error message
                     break;
                  }
                  try
                  {
                     ((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].click()", element);
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.CursorClick:
                  try
                  {
                     var X = element.Location.X;
                     var Y = element.Location.Y;
                     SetCursorPos(X, Y);
                     mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.SendKeyEnter:
                  try
                  {
                     element.SendKeys(Keys.Enter);
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.SendKeyReturn:
                  try
                  {
                     element.SendKeys(Keys.Return);
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.SendKeySpacebar:
                  try
                  {
                     element.SendKeys(Keys.Space);
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
            }
            //For now this part of code is placed here just to avoid multiple clicking on the same web element. It will be replaced with Step 5 on the next stage
           if(true)
               break;
         }
      }      
   }

The ClickAction.CursorClick action requires the use of some additional variables. Add them to the Extensions class:

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, int dx, int dy, uint cButtons, uint dwExtraInfo);

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern long SetCursorPos(int X, int Y);

private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;

Also you need to add reference to System.Drawing library and use following namespaces:

using System;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Interactions;
using System.Runtime.InteropServices;

Steps 5 – invoking a method passed as a parameter which verifies that the clicking action has been performed and the expected result matches the actual one.

To be sure that a clicking action has been successfully done and the expected result has occurred, you can pass one more function to the method and invoke it after every attempt to click the web element. This function has the same signature as the method which verifies preconditions. Let’s name it ‘postcondition’.

If you specify your own method which will verify post-click conditions or you can not to specify the method itself but pass IWebDriver instance to the method – in this case the method will use default actions defined in the method. If you specify neither post-click verification conditions method nor IWebDriver instance there no verification will be performed. Here is an example of how I implemented it, but you can change the functionality in your own way.

public static void SmartClick(this IWebElement element, IWebDriver driver = null, CustomFunction precondition = null, CustomFunction postcondition = nullint iterations = 1, params ClickAction[] clicks)
   {
      int i = iterations;

      //if you do not specify what actions to use for clicking the following default actions will be used
      ClickAction[] clickActions = clicks != null ? clicks : new ClickAction[] { ClickAction.Click, ClickAction.LeftMBClick, ClickAction.JSClick };
   
      string elementName = element.Text;

      if (precondition == null)
         precondition = x => true; //if you did not specify the method let's assume it has passed (return true)

      if (postcondition == null)
      {
         if (driver == null)
         {
            //"SmartClick: IWebDriver is null, no postcondition verification provided" message to log file
            postcondition = x => true//assume if you do not pass IWebDriver to the mathod you do not need any post-click conditions verification. Therefore, this method always returns true
         }
         else
         {
            //"SmartClick: No click verification conditions are specified. Default verification wil be used." message to log file
            var numOfWindows = driver.WindowHandles.Count;
            var pageHashCode = PageHashCode(driver);
            var pageTitle = driver.Title;
            var pageUrl = driver.Url;
            //the method returns true if any of the following conditions are met, otherwise it returns false
            postcondition = delegate
            {
               //page title is changed
               if (pageTitle != driver.Title)
               {
                  //log message "SmartClick: Click validation - Title of the page has changed"
                  //screenshot
                  return true;
               }
               //page url address is changed
               if (pageUrl != driver.Url)
               {
                  //log message "SmartClick: Click validation - Url address of the page has changed"
                  //screenshot
                  return true;
               }
               //alert pop-up is displayed
               try
               {
                  driver.SwitchTo().Alert();
                  //log message "SmartClick: "Element_ClickWhile: Click validation - Alert pop-up is displayed"
                  //screenshot
                  return true;
               }
               catch {  }
               //number of opened windows or tabs is changed
               if (numOfWindows != driver.WindowHandles.Count)
               {
                  //log message "SmartClick: "Element_ClickWhile: Click validation - Number of opened windows (tabs) has changed"
                  //screenshot
                  return true;
               }
               //page hash code is changed. It indicates that some changes has occurred on the page
               if (pageHashCode != PageHashCode(driver))
               {
                  //log message "SmartClick: "Element_ClickWhile: Click validation - Hash code of the page has changed"
                  //screenshot
                  return true;
               }
               return false;
            }
         }
      }
      
      while (i > 0)
      {
         i--;
         if (!precondition.Invoke())
         {
            //add string.Format("Preconditions for clicking '{0}' web element are not met", elementName) error message into your log file
            //screenshot
            continue; //there is no sense to do clicking action if precondition method has failed. Return back to the beginning of the loop and start again from the very beginning
         }
         if (element == null)   
         {   
            //add 'Element is null' error message into your log file or throw NoSuchElement or NullReference exception   
         }  
         if(!element.Displayed)   
         {   
            //add 'Element is not displayed and cannot be clicked' error message into your log file   
            //you may add a screenshot here  
         }  
         if(!element.Enabled)   
         {  
            //add 'Element is not displayed and cannot be clicked' error message into your log file  
            //plus a screenshot  
         }
         foreach (var action in clickActions)
         {
            //here you may add string.Format("Clicking '{0}' web element with {1} click action", elementName, action) message into your log file
            switch (action)
            {
               case ClickAction.Click:
                  try
                  {
                      element.Click();
                  }
                  catch (Exception e)
                  {
                      //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.Submit:
                  try
                  {
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.DoubleClick:
                  try
                  {
                     var builder = new Actions(driver);
                     builder.DoubleClick().Build().Perform();
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  } 
                  break;
              
               case ClickAction.RightMBClick:
                  if (driver == null)
                  {
                     //"SmartClick clicking error: IWebDriver instance must be passed as a parameter and connot be null if you use clicking with right mouse button action" error message
                     break;
                  }
                  try
                  {
                      var builder = new Actions(driver);
                      builder.MoveToElement(element).ContextClick(element).Build().Perform();
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.JSClick: 
                  if (driver == null)
                  {
                     //"SmartClick clicking error: IWebDriver instance must be passed as a parameter and connot be null if you use clicking with JavaScript action" error message
                     break;
                  }
                  try
                  {
                     ((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].click()", element);
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.CursorClick:
                  try
                  {
                     var X = element.Location.X;
                     var Y = element.Location.Y;
                     SetCursorPos(X, Y);
                     mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.SendKeyEnter:
                  try
                  {
                     element.SendKeys(Keys.Enter);
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.SendKeyReturn:
                  try
                  {
                     element.SendKeys(Keys.Return);
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
               case ClickAction.SendKeySpacebar:
                  try
                  {
                     element.SendKeys(Keys.Space);
                  }
                  catch (Exception e)
                  {
                     //"SmartClick clicking error: " + e.Message error message
                  }
                  break;
            }
            if (postcondition())
               return;
            //add string.Format("Post-conditions for clicking '{0}' web element are not met", elementName) error message into your log file
            //screenshot
         }
      }      
   }

Note: In the code above I invoked a method named PageHashCode(). This is a custom method which gets html-code of the current page (IWebDriver.PageSource property) and computes its hash code. The result is returned as a string. Here is the code of the method. Put it into the Extensions class:

static string PageHashCode(IWebDriver driver)
{
   MD5 md5 = MD5.Create();
   byte[] bytesArray = Encoding.ASCII.GetBytes(driver.PageSource);
   byte[] hashCode = md5.ComputeHash(bytesArray);
   var sb = new StringBuilder();
   foreach (byte t in hashCode)
      sb.Append(t.ToString("X2"));
   return sb.ToString();
}

Step 6 – If the expected result is not met, it tries to clicking the elements with the next clicking action from the list.

You can implement it in many ways according to your objectives. For example, you may just add an error message to log file or your can throw an exception. You should add the code for this right after the switch() operator.

Also, I recommend to add one more input parameter to the method: a delay between the clicking attempts. Obviously, after a click on a web element it takes some time for something to happen. Usually, when you click a button, a request is sent to a server, and then the server sends a response which your browser handles and displays the final result. Sometimes it happens almost immediately and sometimes it may be a time-consuming process. So, you can pass a delay parameter (period of time in seconds during which the method should do nothing, assuming this time is enough for performing all the actions described above) with some default value, for example 1 second.

public static void SmartClick(this IWebElement element, IWebDriver driver = null, CustomFunction precondition = null, CustomFunction postcondition = nullint iterations = 1, int delay = 1, params ClickAction[] clicks)
{
   //method code
}

Put its use right after switch() operator

foreach (var action in clickActions)
{        
   ...
   switch (action)
   {
        ... 
   }
   Thread.Sleep(delay * 1000);
   if(postcondition())
      ...
}

Note: you may use global variables instead of the method parameters. For example, you can store such variables as delay or IWebDriver instance in external classes and have them visible all over the project. In that case, you do not need pass them as a parameter. Anyway, you are free to modify the method as you wish. This is just a common point of view, one of possible implementations.

In the next part, I will show how the method may be used in a test.

 

 



Notice: Undefined variable: font_family in /home/chyqruxavcln/public_html/learnseleniumtesting.com/wp-content/plugins/gdpr-cookie-compliance/moove-modules.php on line 282