WebElement Extensions Method

Before starting understanding the concept of WebElement Extensions Method in Selenium, let's first understand the need of it. Although Selenium WebDriver is a powerful framework for web test automation, there is always room for improvement. Luckily for us, much of this improvement can be made by leveraging the existing functionality of Selenium WebDriver. Let;s discuss of the cases where there is a need of altering Selenium Actions.

Case 1: WebElement SendKeys

You must have notice that on some text fields values are pre populated. When the Selenium SendKeys action work, it does not remove the old text and just add or append more text to it. So we usually opt the below workaround for it:

element.Clear(); element.SendKeys("TextToEnter")

Or we end up writing a function which will do the above task for us.

Case 2: WebElement Click

There can be situations where Click action does not work on any given element. In that case we end up clicking on the element with the help of JavaScript or MouseHover click. To make the code reusable we always create functions of reusable actions.

Case 3: Logging

Logging is very essential task in any framework. Logging can be Step Level or Action Level. Action Level logging is difficult to manage, as it is required to enter log after every action. And it become very annoying for an automation script writer to maintain the efficient logging in the framework. For e.g.

element.Click(); Log.info("Click action performed on an element")

Basic Approach

A Normal approach to avoid above problems is to create a Selenium class and write all the functions in it.

   public class Selenium
    {
        public static void EnterText(IWebElement element, string text)
        {
            element.Clear();
            Log.Info("Clear action is performed on an xyz element");
            element.Click();
            Log.Info("Click action is performed on an xyz element");
        }
    }

But a better and advance approach to resolve the Selenium Overcomes is to Implement WebElement Extensions Method of C# in Framework.

What are Extension Methods?

Extension Methods enable you to add methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. An extension method is a special kind of static method, but they are called as if they were instance methods on the extended type.

An extension method is a static method of a static class, where the "this" modifier is applied to the first parameter. The type of the first parameter will be the type that is extended.

How to Create Extension Method?

We create an extension method for a WebElement type so WebElement will be specified as a parameter for this extension method and that method will be called by a WebElement instance using the dot operator.

EnterText() in place of SendKeys()

	public static void EnterText(this IWebElement element, string text)
	{
		element.Clear();
		element.SendKeys(text);
	}

This function is very simple, all it does is make our code a little from concise. In the original Selenium Remote Control RC, SendKeys would clear a text field and then send the required text. In Selenium 2, text fields are not cleared first unless explicitly executed. In the above method EnterText(), we are passing a IWebElement type with 'this' so it will be called by the any element variable, in other words a IWebElement instance.

WebElement Extensions Method

Note: EnterText() method will appear just like any other method of IWebElement. A down arrow will identify WebElement Extensions Method

IsDisplayed() in place of Displayed()

	public static bool IsDisplayed(this IWebElement element)
	{
		bool result;
		try
		{
			result = element.Displayed;
		}catch(Exception)
		{
			result = false;
		}
		// Log the Action
		return result;            
	}

Selenium's default behaviour is to throw an exception if an element is not found. IsDisplayed method catches this exception to allow us to test for the visibility of the elements without stopping execution of the entire program.

SelectByText of Select Class

	public static void SelectByText(this IWebElement element, string text)
	{
		SelectElement oSelect = new SelectElement(element);
		oSelect.SelectByText(text);
		//Log the Action
	}

Like this you can implement every action of Selenium in your own way and do logging in that or use try catch block or anything.

Implementation of WebElement Extensions Method in Automation Framework

Step 1: Create a Element_Extensions Class

  1. Create a new folder and name it as Extensions.

  2. Create a new C# class in the Extensions folder, name it as Element_Extensions.

  3. Write the implementation of the Element_Extensions class.

Element_Extensions Class

using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System;

namespace OnlineStore.Extensions
{
    public static class Element_Extensions
    {
        public static void EnterText(this IWebElement element, string text, string elementName)
        {

            element.Clear();
            element.SendKeys(text);
            Console.WriteLine(text +" entered in the " + elementName + " field.");
        }

        public static bool IsDisplayed(this IWebElement element, string elementName)
        {
            bool result;
            try
            {
                result = element.Displayed;
                Console.WriteLine(elementName + " is Displayed.");
            }
            catch(Exception)
            {
                result = false;
                Console.WriteLine(elementName + " is not Displayed.");
            }

            return result;            
        }

        public static void ClickOnIt(this IWebElement element, string elementName)
        {
            element.Click();
            Console.WriteLine("Clicked on " + elementName); 
        }

        public static void SelectByText(this IWebElement element, string text, string elementName)
        {
            SelectElement oSelect = new SelectElement(element);
            oSelect.SelectByText(text);
            Console.WriteLine(text + " text selected on " + elementName);
        }

        public static void SelectByIndex(this IWebElement element, int index, string elementName)
        {
            SelectElement oSelect = new SelectElement(element);
            oSelect.SelectByIndex(index);
            Console.WriteLine(index + " index selected on " + elementName);
        }

        public static void SelectByValue(this IWebElement element, string text, string elementName)
        {
            SelectElement oSelect = new SelectElement(element);
            oSelect.SelectByValue(text);
            Console.WriteLine(text + " value selected on " + elementName);
        }
    }
}

HomePage PageObject Class

using OnlineStore.Extensions;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;

namespace OnlineStore.PageObjects
{
    public class HomePage
    {
        [FindsBy(How = How.Id, Using = "account")]
        [CacheLookup]
        private IWebElement MyAccount { get; set; }

        public void ClickOnMyAccount()
        {
            //Here we are just passing the WebElement Name, so that it can be used in the Logs
            MyAccount.ClickOnIt("MyAccount");
        }
    }
}

LogInPage PageObject Class

using OnlineStore.TestDataAccess;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;
using OnlineStore.Extensions;

namespace OnlineStore.PageObjects
{
    public class LoginPage
    {        
        [FindsBy(How = How.Id, Using = "log")]
        [CacheLookup]
        private IWebElement UserName { get; set; }

        [FindsBy(How = How.Id, Using = "pwd")]
        [CacheLookup]
        private IWebElement Password { get; set; }

        [FindsBy(How = How.Id, Using = "login")]
        [CacheLookup]
        private IWebElement Submit { get; set; }

        public void LoginToApplication(string testName)
        {
            var userData = ExcelDataAccess.GetTestData(testName);
            UserName.EnterText(userData.Username,"UserName");
            Password.EnterText(userData.Password, "Password");
            Submit.ClickOnIt("Submit Button");
        }
    }
}

LogInTest TestCase

using NUnit.Framework;
using OnlineStore.PageObjects;
using OnlineStore.WrapperFactory;
using OpenQA.Selenium;
using System.Configuration;

namespace OnlineStore.TestCases
{
    public class LogInTest
    {
       [Test]
        public void Test() {          

            BrowserFactory.InitBrowser("Firefox");
            BrowserFactory.LoadApplication(ConfigurationManager.AppSettings["URL"]);         

            Page.Home.ClickOnMyAccount();
            Page.Login.LoginToApplication("LogInTest");

            BrowserFactory.CloseAllDrivers();
        }

    }
}

Note: This is the beauty of well designed Automation Framework, that even after changing the most of inner functionality, the code for the Test Case will remain exactly the same as before (Previous Chapter).

Project Explorer

Extensions Method

Feature and Property of Extension Methods

The following list contains basic features and properties of extension methods. Make sure you follow the rules when you play with it.

  • It is a static method
  • It must be located in a static class
  • It uses the "this" keyword as the first parameter with a type in .NET and this method will be called by a given type instance on the client side.
  • It also shown by VS intellisense. When we press the dot (.) after a type instance, then it comes in VS intellisense.
  • *An extension method should be in the same namespace as it is used or you need to import the namespace of the class by a using statement.
  • You can give any name for the class that has an extension method but the class should be static.*
  • If you want to add new methods to a type and you don't have the source code for it, then the solution is to use and implement extension methods of that type.
  • If you create extension methods that have the same signature methods as the type you are extending, then the extension methods will never be called.
Page Generator
Page Generator
Previous Article
Download File using Selenium and Verifying
Download File using Selenium and Verifying
Next Article
Lakshay Sharma
I’M LAKSHAY SHARMA AND I’M A FULL-STACK TEST AUTOMATION ENGINEER. Have passed 16 years playing with automation in mammoth projects like O2 (UK), Sprint (US), TD Bank (CA), Canadian Tire (CA), NHS (UK) & ASOS(UK). Currently, I am working with RABO Bank as a Chapter Lead QA. I am passionate about designing Automation Frameworks that follow OOPS concepts and Design patterns.
Reviewers
Virender Singh's Photo
Virender Singh

Similar Articles

Feedback