Creating Your Own Custom HtmlControls
Let's suppose you're testing a web site that uses a third party or custom control. You can easily create your own custom HtmlControl class and then design tests that interact with the custom control via your custom HtmlControl class.
As an example, let's create a custom HtmlControl that wraps the ASP.NET calendar control. We'll give it some methods for reading and controlling the date selection along with a custom ClientSideLocator just for an example. First here's our ASPX web page containing a calendar control that we want to test
<% @ Page Language="C#" MasterPageFile="~/AppMaster.master" Title="Untitled Page" %>
<% @ Import Namespace="System.Data" %>
<% @ Register Assembly="ArtOfTest.WebAii.AspNet" Namespace="ArtOfTest.WebAii.AspNet.WebControls" TagPrefix="test" %>
<script runat="server">
/// <summary>
/// Page Load
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// Bind the grid and cache the data in the session.
grid1.DataSource = GetData();
DataBind();
}
}
/// <summary>
/// Return a DataSet of some random data.
/// </summary>
/// <returns>DataSet</returns>
private DataSet GetData()
{
DataSet data = new DataSet();
DataTable dt = new DataTable();
Random r = new Random(3);
data.Tables.Add(dt);
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Date", typeof(DateTime));
dt.Columns.Add("FirstName", typeof(string));
dt.Columns.Add("LastName", typeof(string));
dt.Columns.Add("Balance", typeof(int));
for (int i = 0; i < 15; i++)
{
DataRow row = dt.NewRow();
row.ItemArray = new object[] {i,DateTime.Today.AddDays(i),"Name" + i.ToString(),
"Last" + i.ToString(), r.Next(3000)};
dt.Rows.Add(row);
}
return data;
}
/// <summary>
/// OnCalendarSelectionChange()
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void cal1_SelectionChanged(object sender, EventArgs e)
{
// Get DataSet from Session
TimeSpan diffDate = cal1.SelectedDate.Subtract(DateTime.Today);
if (cal1.SelectedDate >= DateTime.Today && diffDate.Days < 15)
{
grid1.SelectedIndex = diffDate.Days;
grid1.EditIndex = diffDate.Days;
}
grid1.DataSource = GetData();
grid1.DataBind();
}
</script>
<asp:Content ID="Content1" ContentPlaceHolderID="PageContent" runat="Server">
<!-- This Data Page Content -->
<test:TestRegion ID="DataPageContent" runat='server'>
You are logged in.
<table style="border: dotted 1px black; background-color: beige; width:80%;" cellpadding="15">
<tr>
<td>
Select A Date:
<!-- The Calendar Control Region -->
<test:TestRegion ID="CalendarControl" runat="server">
<asp:Calendar ID="cal1" runat="server" OnSelectionChanged="cal1_SelectionChanged"
BackColor="#FFFFCC" BorderColor="#FFCC66" BorderWidth="1px" Font-Names="Verdana"
Font-Size="8pt" ForeColor="#663399" Height="200px" Width="220px" DayNameFormat="Shortest"
ShowGridLines="True">
<SelectedDayStyle BackColor="#CCCCFF" Font-Bold="True" />
<TodayDayStyle BackColor="#FFCC66" ForeColor="White" />
<OtherMonthDayStyle ForeColor="#CC9966" />
<NextPrevStyle Font-Size="9pt" ForeColor="#FFFFCC" />
<DayHeaderStyle Font-Bold="True" BackColor="#FFCC66" Height="1px" />
<TitleStyle BackColor="#990000" Font-Bold="True" Font-Size="9pt" ForeColor="#FFFFCC" />
<SelectorStyle BackColor="#FFCC66" />
</asp:Calendar>
</test:TestRegion>
<!-- The Calendar Control Region -->
</td>
<td valign="top" style="border: solid 1px black;">
Customer Balances:
<!-- The GridView Region -->
<test:TestRegion ID="GridControl" runat="server">
<asp:GridView ID="grid1" runat="server" AutoGenerateColumns="False" BackColor="White"
BorderColor="#CC9966" BorderStyle="None" BorderWidth="1px" CellPadding="4" Font-Size="XX-Small">
<Columns>
<asp:TemplateField HeaderText="ID">
<ItemTemplate>
<%# Eval("ID") %>
</ItemTemplate>
<EditItemTemplate>
<!-- ID Column Region [Will persist only in Edit Mode] -->
<test:TestRegion ID="GridEditId" runat="server">
<%# Eval("ID") %>
</test:TestRegion>
<!-- ID Column Region -->
</EditTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="FirstName" DataField="FirstName" ReadOnly="true" />
<asp:BoundField HeaderText="LastName" DataField="LastName" ReadOnly="true" />
<asp:BoundField HeaderText="Date" DataField="Date" ReadOnly="true" />
<asp:TemplateField HeaderText="Balance">
<ItemTemplate>
<%# Eval("Balance") %>
</ItemTemplate>
<EditItemTemplate>
<!-- Balance Column Region [Will persist only in Edit Mode] -->
<test:TestRegion ID="GridEditBalance" runat="server">
<asp:TextBox ID="newBalance" Text='<%# Eval("Balance") %>' runat="server"></asp:TextBox>
</test:TestRegion>
<!-- Balance Column Region -->
</EditItemTemplate>
</asp:TemplateField>
</Columns>
<FooterStyle BackColor="#FFFFCC" ForeColor="#330099" />
<RowStyle BackColor="White" ForeColor="#330099" />
<SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="#663399" />
<PagerStyle BackColor="#FFFFCC" ForeColor="#330099" HorizontalAlign="Center" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="#FFFFCC" />
</asp:GridView>
</test:TestRegion>
<!-- The GridView Region -->
</td>
</tr>
</table>
</test:TestRegion>
<!-- This Data Page Content -->
</asp:Content>
Let's put together our custom HtmlControl that we can use interact with an ASP.NET calendar control:
Notice how we derive from an HtmlTable. That way we can take advantage of all the functionality already built into a standard table. We'll just add all the functions useful for our calendar control which include:
NextMonth
PrevMonth
GetYear
GetMonth
GetDate
GotoDate
GotoNow
ClickOnDate
All these functions are fairly straightforward Telerik Testing Framework code that don't really need explanation.
For the purposes of demonstration there's also a ClientSideLocator override in lines 201-207 so you can see how it works and how to implement it when you want to create a more complex custom control. For our HtmlControl extenders, you can make your HtmlControl map to any object on the client side. Previously an HtmlControl object had to map to element with an HTML tag. This restriction has been removed. You can override the HtmlControl "ClientSideLocator" property and give it any JavaScript find logic to execute on the client (e.g. in ASP.NET $find("foo") ) and the HtmlControl will map itself to that object on the client. Any future calls on this object using GetValue, SetValue or CallMethod, will use this JavaScript to select the right object on the client side before getting or setting it's value, or calling your custom method on it.