Published on

Essential Selenium Extensions in C#

Essential Selenium Extension Methods

Selenium Web-driver is a powerful framework for web test automation. Some 'evil' people also use it to overcome difficulties in web scraping. (Shh don't tell!🤫).

These are some extensions to help us write code a little quicker than the conventional way of doing things with the selenium web driver and not getting exceptions along the way.

What are extension methods?

Extension methods, as the name suggests, are additional methods. Extension methods allow you to inject additional methods without modifying, deriving or recompiling the original class, struct or interface. Extension methods can be added to your own custom class, .NET framework classes, or third party classes or interfaces.


The code 💪

Please note that some of these require the helper nuget package DotNetSeleniumExtras.WaitHelpers

public static class SeleniumExtensions
    {
        /// <summary>
		/// Waits till document has its readyState set to complete.
		/// </summary>
		/// <param name="timeout">Timeout in seconds</param>
        public static void WaitTillDocumentReady(this IWebDriver driver, int timeout = 180)
        {
            IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
            WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeout));
            wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
        }

        /// <summary>
        /// Waits till element exists on page.
        /// </summary>
        /// <param name="by">Path to element</param>
        /// <param name="timeout">Timeout in seconds</param>
        public static IWebElement WaitUntilElementExists(this IWebDriver driver, By elementLocator, int timeout = 20)
        {
            try
            {
                var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout));
                return wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementExists(elementLocator));
            }
            catch (NoSuchElementException)
            {
                //Console.WriteLine("WaitUntilElementExists: Element with locator: '" + elementLocator + "' was not found in current context page.");
                throw;
            }
        }

        /// <summary>
        /// Waits till element is visible on page.
        /// </summary>
        /// <param name="by">Path to element</param>
        /// <param name="timeout">Timeout in seconds</param>
        public static IWebElement WaitUntilElementVisible(this IWebDriver driver, By elementLocator, int timeout = 20)
        {
            try
            {
                var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout));
                return wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(elementLocator));
            }
            catch (NoSuchElementException)
            {
                //Console.WriteLine("WaitUntilElementVisible: Element with locator: '" + elementLocator + "' was not found.");
                throw;
            }
        }

        /// <summary>
        /// Waits till element is clickable.
        /// </summary>
        /// <param name="by">Path to element</param>
        /// <param name="timeout">Timeout in seconds</param>
        public static IWebElement WaitUntilElementClickable(this IWebDriver driver, By elementLocator, int timeout = 20)
        {
            try
            {
                var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout));
                return wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementToBeClickable(elementLocator));
            }
            catch (NoSuchElementException)
            {
                //Console.WriteLine("WaitUntilElementClickable: Element with locator: '" + elementLocator + "' was not found in current context page.");
                throw;
            }
        }

        /// <summary>
        /// Clicks on element and waits for page to finish loading.
        /// </summary>
        /// <param name="by">Path to element</param>
        /// <param name="timeout">Timeout in seconds</param>
        public static void ClickAndWaitForPageToLoad(this IWebDriver driver, By elementLocator, int timeout = 120)
        {
            try
            {
                var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout));
                var element = driver.FindElement(elementLocator);
                element.Click();
                wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.StalenessOf(element));
            }
            catch (NoSuchElementException)
            {
                //Console.WriteLine("ClickAndWaitForPageToLoad: Element with locator: '" + elementLocator + "' was not found in current context page.");
                throw;
            }
        }

        /// <summary>
        /// Waits till element is present or timeouts
        /// </summary>
        /// <param name="by">Path to element</param>
        /// <param name="timeout">Timeout in seconds</param>
        /// <returns>True if element is present or false if not present and timedout</returns>
        public static bool WaitTillElementPresent(this IWebDriver driver, By by, int timeout = 180)
        {
            var linkWait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout));

            var element = linkWait.Until(condition =>
            {
                try
                {
                    var elementToBeDisplayed = driver.FindElement(by);

                    if (elementToBeDisplayed == null) return false;

                    return elementToBeDisplayed.Displayed;
                }
                catch (StaleElementReferenceException)
                {
                    return false;
                }
                catch (NoSuchElementException)
                {
                    return false;
                }
                catch (Exception) { return false; }
            });
            return true;

        }

        /// <summary>
        /// Informs if element is present on the page.
        /// </summary>
        /// <param name="by">Path to element</param>
        /// <returns>True if element is present or false if not.</returns>
        public static bool IsElementPresent(this IWebDriver driver, By by)
        {
            try
            {
                driver.FindElement(by);
                return true;
            }
            catch (NoSuchElementException)
            {
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Gives the driver's interface of JS execution.
        /// </summary>
        /// <returns>IJavaScriptExecutor</returns>
        public static IJavaScriptExecutor Scripts(this IWebDriver driver)
        {
            return (IJavaScriptExecutor)driver;
        }
    }