I played with OpenAI’s custom GPT models and created the Mug Master GPT, which is something simple and entertaining to play with. Now, however, let’s look at creating something useful. How about a GPT that can create C# classes for Selenium automation based on an HTML element from a webpage? This is exactly what my Selenium C# Component Class Creator does.
Instructions
The high-level instructions for this custom GPT are as follows:
As the Selenium C# Component Class Creator, you are responsible for generating C# classes that represent reusable components from HTML elements. You should adhere to the Component Object design pattern, which focuses on encapsulating the functionality of complex UI components.
I also gave it many use cases so that the GPT performed how I wanted it. Here are some of those user cases:
- The constructor will accept an IWebDriver parameter and an optional By parameter named “containerLocator”.
- Declare the following private variables: An IWebDriver to interact with the web page, a By object for the “containerLocator”, and a WebDriverWait object to handle waits.
- Double check that you ALWAYS have a ContainerElement defined.
For some reason, I had to include the last one. It wasn’t including the ContainerElement without it.
Testing It Out
I found a test page at parasoft.com that had a simple header panel element on a set of test pages. I copied the header element HTML, which is below. It’s pretty basic.
<div id="headerPanel" style="background: url(/parabank/images/header-main.jpg) 0 0 no-repeat;">
<ul class="leftmenu">
<li class="Solutions">Solutions</li>
<li><a href="about.htm">About Us</a></li>
<li><a href="services.htm">Services</a></li>
<li><a href="http://www.parasoft.com/jsp/products.jsp">Products</a></li>
<li><a href="http://www.parasoft.com/jsp/pr/contacts.jsp">Locations</a></li>
<li><a href="admin.htm">Admin Page</a></li>
</ul>
<ul class="button">
<li class="home"><a href="/parabank/index.htm">home</a></li>
<li class="aboutus"><a href="about.htm">about</a></li>
<li class="contact"><a href="contact.htm">contact</a></li>
</ul>
</div>
I pasted that HTML into my Selenium C# Component Class Creator GPT, and here is the class it created:
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System;
public class HeaderPanelComponent
{
private readonly IWebDriver _driver;
private readonly By _containerLocator;
private readonly WebDriverWait _wait;
public HeaderPanelComponent(IWebDriver driver, By containerLocator = null)
{
_driver = driver;
_containerLocator = containerLocator ?? By.Id("headerPanel");
_wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10));
}
public IWebElement ContainerElement => _wait.Until(ExpectedConditions.ElementIsVisible(_containerLocator));
// Navigation Menu Links
private IWebElement SolutionsLink => ContainerElement.FindElement(By.CssSelector("ul.leftmenu > li.Solutions"));
private IWebElement AboutUsLink => ContainerElement.FindElement(By.LinkText("About Us"));
private IWebElement ServicesLink => ContainerElement.FindElement(By.LinkText("Services"));
private IWebElement ProductsLink => ContainerElement.FindElement(By.LinkText("Products"));
private IWebElement LocationsLink => ContainerElement.FindElement(By.LinkText("Locations"));
private IWebElement AdminPageLink => ContainerElement.FindElement(By.LinkText("Admin Page"));
// Button Links
private IWebElement HomeButton => ContainerElement.FindElement(By.CssSelector("ul.button > li.home > a"));
private IWebElement AboutButton => ContainerElement.FindElement(By.CssSelector("ul.button > li.aboutus > a"));
private IWebElement ContactButton => ContainerElement.FindElement(By.CssSelector("ul.button > li.contact > a"));
public void ClickLink(string linkText)
{
try
{
var link = ContainerElement.FindElement(By.LinkText(linkText));
link.Click();
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to click on link with text '{linkText}'.", ex);
}
}
// Additional methods for interacting with other elements in the header can be added here
}
It generated the HeaderPanelComponent class, The user can send the driver and the optional top-level By locator to the constructor. It created a public ContainerElement property that will be referenced when finding all child elements, and it created the links and buttons properties. The GPT added the ClickLink() method, which some testers will find useful. I would rather find these links and buttons by index, so I followed up and asked the GPT to add a method to click the link by index and another method to click those three buttons by index. It provided an update to the class, and the relevant portion is here:
public IWebElement ContainerElement => _wait.Until(ExpectedConditions.ElementIsVisible(_containerLocator));
private ReadOnlyCollection<IWebElement> NavigationLinks => ContainerElement.FindElements(By.CssSelector("ul.leftmenu > li > a"));
private ReadOnlyCollection<IWebElement> ButtonLinks => ContainerElement.FindElements(By.CssSelector("ul.button > li > a"));
public void ClickNavLinkByIndex(int index)
{
try
{
NavigationLinks[index].Click();
}
catch (ArgumentOutOfRangeException ex)
{
throw new InvalidOperationException("The specified index is out of range for navigation links.", ex);
}
catch (Exception ex)
{
throw new InvalidOperationException("Failed to click on the navigation link at the specified index.", ex);
}
}
public void ClickButtonLinkByIndex(int index)
{
try
{
ButtonLinks[index].Click();
}
catch (ArgumentOutOfRangeException ex)
{
throw new InvalidOperationException("The specified index is out of range for button links.", ex);
}
catch (Exception ex)
{
throw new InvalidOperationException("Failed to click on the button link at the specified index.", ex);
}
}
// Existing properties and methods...
It only took a minute to have the custom GPT generate this class. Can you imagine how many hours, days, or maybe even months this can save when implementing Selenium automation for your project? These component classes can be generated, and then the testers and/or developers can focus on writing the tests that use these components.
Table Class
For another example to demonstrate how time-efficient these custom GPTs can be, I asked Selenium C# Component Class Creator GPT to “Construct a C# class for an HTML Table”. The class is below.
It only took a few seconds to create this class, and if you have a typical HTML table with <table>
, <tr>
, and <td>
tags on your webpage, this class should work just fine in your Selenium Automation. The downside to this class would maybe be performance if you had a very large table with tons of data.
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.Generic;
public class HtmlTable
{
private readonly IWebDriver _driver;
private readonly By _containerLocator;
private readonly WebDriverWait _wait;
public HtmlTable(IWebDriver driver, By containerLocator = null)
{
_driver = driver;
_containerLocator = containerLocator ?? By.TagName("table");
_wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10));
}
public IWebElement ContainerElement => _wait.Until(ExpectedConditions.ElementIsVisible(_containerLocator));
public List<IWebElement> Rows => new List<IWebElement>(ContainerElement.FindElements(By.TagName("tr")));
public IWebElement GetCell(int rowIndex, int columnIndex)
{
return Rows[rowIndex].FindElements(By.TagName("td"))[columnIndex];
}
public int RowCount => Rows.Count;
// Additional methods for interacting with the table can be added here
}
Conclusion
This Selenium C# Component Class Creator GPT wasn’t that hard to make. It did take some time to tailor it to my specific needs and to output the classes that I wanted. However, each time I use this GPT to create component classes for Selenium automation, the time savings add up.