Created a simple calculator app in webforms.
User enters a number in a text field MainContent_numberTb and clicks on results button.
Added a new 'coded UI Test Project' to my solution. Have tested the UI by adding '5', This all works fine. Would now like to compare the actual result against the expected result.
BrowserWindow Browser = BrowserWindow.Launch("http://url");
UITestControl UiInputField = new UITestControl(Browser);
UiInputField.TechnologyName = "Web";
UiInputField.SearchProperties.Add("ControlType", "Edit");
UiInputField.SearchProperties.Add("Id", "MainContent_numberTb");
//Populate input field
Keyboard.SendKeys(UiInputField, "5");
//Results Button
UITestControl ResultsBtn = new UITestControl(Browser);
ResultsBtn.TechnologyName = "Web";
ResultsBtn.SearchProperties.Add("ControlType", "Button");
ResultsBtn.SearchProperties.Add("Id", "MainContent_calBtn");
Mouse.Click(ResultsBtn);
All above code works fine, problem occurs when trying to access the label
<asp:Label ID="AllNumLbl_Res" runat="server"></asp:Label>
What do I insert beside control type? It's not edit as edit is the text field. Then also, what stores the actual result so I can compare AllNumsTB?
string expectedAllNums = "1, 2, 3, 4, 5";
UITestControl AllNumsTB = new UITestControl(Browser);
AllNumsTB.TechnologyName = "Web";
AllNumsTB.SearchProperties.Add("ControlType", "?????");
AllNumsTB.SearchProperties.Add("Id", "MainContent_AllNumLbl_Res");
if(expectedAllNums != AllNumsTB.??????)
{
Assert.Fail("Wrong Answer");
}
UPDATE
OK so using the debugger console I was able to get the value of the label using ((Microsoft.VisualStudio.TestTools.UITesting.HtmlControls.HtmlSpan)new System.Collections.ArrayList.ArrayListDebugView(((System.Collections.CollectionBase)(AllNumsTB.FindMatchingControls()).List).InnerList).Items[0]).DisplayText
but when I use this in the code & ArrayListDebugView are inaccessible due to protection??
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UPDATE
Thanks K Scandrett for the answer...If I may I was wondering could you also please help me with the validation...If the user enters a letter or a non positive number the error message will fire..
<asp:RegularExpressionValidator ID="regexpName"
//VALIDATION MESSAGE
UITestControl PositiveNumValMsg = new UITestControl(Browser);
PositiveNumValMsg.TechnologyName = "Web";
PositiveNumValMsg.SearchProperties.Add("Id", "MainContent_regexpName");
This all works fine, however I want to test if the label appears or not...so far I have tried
//bool visible = false;
//System.Drawing.Point p;
//// If the control is offscreen, bring it into the viewport
//PositiveNumValMsg.EnsureClickable();
// // Now check the coordinates of the clickable point
// visible = PositiveNumValMsg.TryGetClickablePoint(out p)
// && (p.X > 0 || p.Y > 0);
var isVisible = PositiveNumValMsg.WaitForControlPropertyNotEqual(UITestControl.PropertyNames.State, ControlStates.Invisible);
but they all return true even when the label is not shown, but it is still on the page just set to invisible. In that case I should check its style..something like
//string labelText3 = PositiveNumValMsg.GetProperty("style").ToString();
then check if the style contains visibility: visible?
You want to grab its InnerText property.
It's not mandatory to set ControlType, so some variation of the following should work:
UITestControl AllNumsTB = new UITestControl(Browser);
AllNumsTB.TechnologyName = "Web";
AllNumsTB.SearchProperties.Add(HtmlControl.PropertyNames.Id, "MainContent_AllNumLbl_Res");
var result = AllNumsTB.GetProperty(HtmlLabel.InnerText).Trim();
// var result = AllNumsTB.GetProperty("InnerText").Trim();
OR from https://social.msdn.microsoft.com/Forums/en-US/69ea15e3-dcfa-4d51-bb6e-31e63deb0ace/how-to-read-dynamic-text-from-label-using-coded-ui-for-web-application?forum=vstest:
var AllNumsTB = new HtmlLabel(Browser);
AllNumsTB.TechnologyName = "Web";
AllNumsTB.SearchProperties.Add(HtmlControl.PropertyNames.Id, "MainContent_AllNumLbl_Res");
var result = AllNumsTB.InnerText;
string result2;
// you may need to include this section, or you may not
if (result.Length > 0)
{
AllNumsTB.WaitForControlReady();
result2 = AllNumsTB.InnerText;
}
EDIT: Regarding testing an ASP.Net Validator
I've been able to check whether the validator message is displayed with the following method:
1) Created a test asp.net page with a regex validator that requires exactly 2 digits:
<asp:TextBox ID="numberTb" runat="server"></asp:TextBox>
<asp:RegularExpressionValidator ID="regexpName" ControlToValidate="numberTb" ValidationExpression="\d{2}" runat="server" ErrorMessage="Please enter 2 digits"></asp:RegularExpressionValidator>
<asp:Button ID="Button1" runat="server" Text="Button" />
2) Ran the Coded UI Test builder and started recording =>
Clicked Input box; typed s; hit tab (the validator error message is showing).
3) Paused the Recorder.
4) Clicked "Generate Code" icon and give it a method name; clicked "Add and Generate" button.
5) Now I dragged and dropped the Crosshair icon onto the validator message. Scrolling down the list of options is the ControlDefinition. Right-clicked it and selected "Add Assertion...".
6) Changed the Comparator to "Contains"; the Comparison Value to " visible;"; and gave it an Assertion Failure message.
7) Clicked the "Generate Code" icon, gave it a method name, etc.
Now we have code that will test the validator by running two methods - first to enter the input and trigger (or not) the validator message; the second to test the validator's message visibility. I copied and pasted the generated code and used it to write another opposing test using " hidden;" when given correct input. Ran both tests, and they both passed.
You will end up with something like (have substituted values):
public void DigitValidatorMsgShownWithIncorrectStringInput()
{
#region Variable Declarations
HtmlSpan uIAtleast2digitsPane = this.UIHomePageMyASPNETApplWindow.UIHomePageMyASPNETApplDocument.UIAtleast2digitsPane;
#endregion
// Verify that the 'ControlDefinition' property of 'At least 2 digits' pane contains ' visible;'
StringAssert.Contains(uIAtleast2digitsPane.ControlDefinition, " visible;", "The validator was not shown");
}
Of course all this can be coded manually once you know what you're looking for.
Related
End Goal
I have a textbox where the user enters data, and have a "CustomValidator" that checks to see if the textbox entry exist in database. If so, I want data from the database to populate other text boxes, If not, I want to enable a textbox that allows the user to manually enter the data in the other fields.
Example: User Enters a code, validator checks if code is valid. If code is valid, the items associated with that code populate fields, if the code is invalid they get an error message warning them that the code is not valid, but they may continue manually
I know I can use textbox.enabled to change status of the field.
I know how to change the error message
What I don't know is how to do is:
Use custom validator to open a sqlconnection and validate against a list generated by it.
Perform actions based on validations pass/fail status.
Just a kick in the pants to find the information about those two would thing be gratefully appreciate.
Google has not been my friend concerning those two things.
Well, in most cases, you just drop in a validator control, and it wires up the client side JavaScript all automatic for you. This works great for say email text box, or numbers, or whatever. And this type of validation is nice, since no server side code, or even a round trip occurs here.
While dropping in a validator control DOES have and allow server side code (code behind)? I don't think you get much of any advantage here then just coding this out.
I mean, user types something into text box. They will have to tab, or hit some search button or what not, right?
so, pull the data (or find out the data dont' exist).
And your grouping of conrols? Just put them all inside of a panel.
Now, you can simple enable or "disable" the whole panel and group of controls with great ease.
So, say I have a hotel "ID" prompt. You type in a number. If hotel exists, then we display the information and DISABLE the panel. User can see the panel, but not edit.
Or, if no value found, then display message, but ALLOW the user to edit those text fields. So, thinking about this problem, I don't think it is a job for validators, and worse you need the means to enable/disable a whole group of controls.
So, say we have this markup up:
Enter Hotel ID:
<asp:TextBox ID="HotelID" runat="server"></asp:TextBox>
<asp:Button ID="cmdSearch" runat="server" Text="Verify"
style="margin-left:15px" CssClass="btn"
/>
<br />
<asp:Label ID="lblmsg" runat="server" Text=""></asp:Label>
<br />
<asp:Panel ID="HotelInfo" runat="server" Visible="false">
<div style="float:left;width:15%">
<div style="text-align:right">
First Name :<asp:TextBox ID="txtFirstname" runat="server" Width="150"></asp:TextBox> <br />
Last Name :<asp:TextBox ID="txtLastname" runat="server" Width="150"></asp:TextBox> <br />
Hotel Name :<asp:TextBox ID="txtHotel" runat="server" Width="150"></asp:TextBox> <br />
City :<asp:TextBox ID="txtCity" runat="server" Width="150"></asp:TextBox> <br />
Active :<asp:CheckBox ID="Active" runat="server" Width="150"></asp:CheckBox>
</div>
</div>
</asp:Panel>
So, the panel visible = false.
The user will see this this (non valid ID).
So, user gets a message - can edit the controls.
but, if we type in a valid id, then they user sees this:
note how the data display - but we can NOT edit - since we disabled the panel.
I suppose you might have some additonal buttons like continue etc., but you get the general idea here.
The code for the button to verify?
This:
Protected Sub cmdSearch_Click(sender As Object, e As EventArgs) Handles cmdSearch.Click
Dim strSQL = "SELECT * FROM tblHotels WHERE ID = #ID"
Using conn = New SqlConnection(My.Settings.TEST4)
Using cmdSQL = New SqlCommand(strSQL, conn)
cmdSQL.Parameters.Add("#ID", SqlDbType.Int).Value = HotelID.Text
Dim rstData = New DataTable
conn.Open()
rstData.Load(cmdSQL.ExecuteReader)
If rstData.Rows.Count = 0 Then
' not found. Display message
lblmsg.Text = "Not found - enter values or search again"
' display panel
HotelInfo.Visible = True
HotelInfo.Enabled = True ' allow edit of controls
Else
' hotel found
lblmsg.Text = "Hotel found"
' display panel
HotelInfo.Visible = True
HotelInfo.Enabled = False ' disable edits
' now fill controls with data
Dim OneRow As DataRow = rstData.Rows(0)
txtHotel.Text = OneRow("HotelName")
txtCity.Text = OneRow("City")
txtFirstname.Text = OneRow("FirstName")
txtLastname.Text = OneRow("LastName")
End If
End Using
End Using
End Sub
Edit: Sorry - I see this was for c#
Here is a c# version:
string strSQL = "SELECT * FROM tblHotels WHERE ID = #ID";
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
cmdSQL.Parameters.Add("#ID", SqlDbType.Int).Value = HotelID.Text;
DataTable rstData = new DataTable();
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
if (rstData.Rows.Count == 0)
{
// not found - display message
lblmsg.Text = "Not found - enter values or search again";
// display panel
HotelInfo.Visible = true;
HotelInfo.Enabled = true; // allow edit of controls
}
else
{
// hotel found
lblmsg.Text = "Hotel found";
// display panel
HotelInfo.Visible = true;
HotelInfo.Enabled = false; // disable edits
//now fill controls with data
DataRow OneRow = rstData.Rows[0];
txtHotel.Text = OneRow["HotelName"].ToString();
txtCity.Text = OneRow["City"].ToString();
txtFirstname.Text = OneRow["FirstName"].ToString();
txtLastname.Text = OneRow["LastName"].ToString();
}
}
}
Edit:#3: Using a validator
Note that you ARE free to drop in a custom validator control. and that control WILL require that the textbox has auto-postback = true.
So at this point in time? All the extra work of using a custom valuator will STILL result in a post-back, will STILL require that the textbox has autopostback = true.
Hence given that you want to call server side code, then you might as well just set the text box auto postback=true, and use the text changed event of that text box. In both cases, you going to suffer a post-back, and thus the concept of a use a client side validator to prevent the page post-back is not something you gain, or achieve by using a custom validator + server side code for that validator.
As part of an automated test, I cannot click on the SharePoint Ribbon to select the "Alert Me" control. I am getting the following error:
Result Message:
Test method CodedUITestProject2.CodedUITest1.SetAlert threw exception:
Microsoft.VisualStudio.TestTools.UITest.Extension.FailedToPerformActionOnHiddenControlException: Cannot perform 'Click' on the hidden control. Additional Details:
TechnologyName: 'Web'
ControlType: 'Hyperlink'
TagName: 'A'
Id: 'Ribbon.Library.Share.AlertMe.Menu.Scope.AlertLibrary-Menu16'
Name: ''
Target: ''
InnerText: 'Set alert on this library'
---> System.Runtime.InteropServices.COMException: Exception from HRESULT: 0xF004F002
Please find my code below: 1. and 2. work and it errors out at 3. I've tried adding and subtracting different control settings.
//1. Select the Library Tab on the ribbon
UITestControl CLR = new UITestControl(browser);
CLR.TechnologyName = "Web";
CLR.SearchProperties.Add("InnerText", "LibraryLibrary Tools group. Tab 2 of 2.");
CLR.WaitForControlReady();
Mouse.Click(new Point(CLR.BoundingRectangle.X + CLR.BoundingRectangle.Width / 2, CLR.BoundingRectangle.Y + CLR.BoundingRectangle.Height / 2));
CLR.WaitForControlReady();
//Mouse.Click(CLR);
Playback.Wait(3000);
//2. set focus on the a pane control on the ribbon
UITestControl FRL = new UITestControl(browser);
FRL.TechnologyName = "Web";
FRL.SearchProperties.Add("TagName", "SPAN");
FRL.SearchProperties.Add("ControlType", "Pane");
FRL.SearchProperties.Add("Class", "ms-cui-groupTitle");
FRL.SearchProperties.Add("InnerText", "Share & Track");
FRL.WaitForControlExist();
FRL.SetFocus();
Mouse.Click(new Point(FRL.BoundingRectangle.X + FRL.BoundingRectangle.Width / 2, FRL.BoundingRectangle.Y + FRL.BoundingRectangle.Height / 2));
Playback.Wait(3000);
//3. Click on "Alert Me" ID
UITestControl AM = new UITestControl(browser);
AM.TechnologyName = "Web";
//AM.SearchProperties.Add("Inner Text", "Alert Me");
AM.SearchProperties.Add("Id", "Ribbon.Library.Share.AlertMe-Large");
AM.WaitForControlReady();
Mouse.Click(new Point(AM.BoundingRectangle.X + AM.BoundingRectangle.Width / 2, AM.BoundingRectangle.Y + AM.BoundingRectangle.Height / 2));
Playback.Wait(2000);
This is a common thing happens with SharePoint automation.
Two reasons could be keeping you back from clicking on the "Alert Me" link.
1. Alert me is kept under a parent and you are trying to click directly.
2. Two identical elements present where one is hidden and the other one is visible.
I will give code for the second reason, if it doesn't works then you can try clicking by following the parent child hierarchy which is very easy to perform by your own.
UITestControl AM = new UITestControl(browser);
//AM.TechnologyName = "Web";
//AM.SearchProperties.Add("Inner Text", "Alert Me");
AM.SearchProperties.Add("Id", "Ribbon.Library.Share.AlertMe-Large");
AM.WaitForControlReady();
UITestControlCollection uic=AM.FindMatchingControls();
foreach(UITestControl ui in uic)
{
if(ui.BoundingRectangle.Width !=-1)
{
Mouse.Click(ui);
break;
}
}
try above code. Else follow the parent child relationship. Also it is not recommended to use UITestControl all the time to identify the elements please try to use specific class names say for example if you are trying to click on hyperlink instead of UITestControl use HtmlHyperlink class so that you can use all possible attributes to identify the elements. This is a best practice which I follow.
I have been playing with Xamarin for a short time so far, and i just stumbled into something i couldn't find the answer into their documentation.
I am building a fairly simple app that retrieves "User Data" (username, email, password and so forth) from a RESTfull API and populates a listview with some of the data (This is the point i am at the moment. It works).
The next step is to build a "Edit User" screen, which is invoked uppon selecting (tapping) a user on the Listview i currently have.
I have managed to build a simple view that is basically two Entry Cells showing the data of the user picked into the previous listview screen. That also works.
The problem is that, once i edit the data into the "Entry Cell" it has no reflection into the "User Model" that populated the "entry cell" in first place.
How do i bind those together?
Code Sample:
// Entry Cell of Username (Should be Binded)
EntryCell ecUsername = new EntryCell()
{
Label = "Username:",
Placeholder = "username / login",
Text = _user.Username
};
// Entry Cell of Password (Should be Binded)
EntryCell ecEmail = new EntryCell ()
{
Label = "Email:",
Placeholder = "user email",
Text = _user.Email
};
Some Screenshots:
Once i click into a user, its data gets rendered into the next screen.
I haven't tested this, but something like this should work:
EntryCell ec = new EntryCell ();
ec.BindingContext = _user;
ec.SetBinding (EntryCell.TextProperty, "Username");
I have taken over maintenance of a site that makes calls through a WCF service. There is a validation summary that displays in a message box for some validators on the client-side. I also have a label that fires if any exceptions arise from my web service calls. After tweaking the layout, the label sits in an inconvenient spot. I want to know if there is a way to display the label text in the validation summary should the exception fire in the code behind.
Any advice is appreciated.
Example in cs file:
bool ResultUserExistence = register.CheckUniquenessUserID(txtUserId.Text);
if (ResultUniquenessEmail == null)
{
continue through code...
}
else
{
lblException.Text = "Please choose a different user name. The current user name is already registered.";
}
Validation Summary:
<asp:ValidationSummary ID="valSummary"
runat="server"
HeaderText="Please correct the following error(s):"
DisplayMode="List"
ForeColor="#FF9999"
ShowMessageBox="True"
ShowSummary="False" />
As notied in this answer you could create a custom validator, and set the message on that, which will make the message show up in your validation summary.
bool ResultUserExistence = register.CheckUniquenessUserID(txtUserId.Text);
if (ResultUniquenessEmail == null)
{
continue through code...
}
else
{
var err As new CustomValidator()
err.ValidationGroup = "UserUniqueness";
err.IsValid = False;
err.ErrorMessage = "Please choose a different user name. The current user name is already registered.";
Page.Validators.Add(err);
}
Ideally this would be factored out into a method for reusability.
I am writing a c# code for a Required field validator for a Multiline text box.
I have a issue in the run time:
when i won't enter any text inside the
text box
For first Click on submit (Button) it shows the error message
For second Click on submit it won't validate the text box and the form is submitted.
Same two issues when i even enter any
text inside the text box.
Overall it is not validating...
Please help me on what could be the possible bug in the below code.
txtReport = new InputFormTextBox();
txtReport.TextMode = TextBoxMode.MultiLine;
txtReport.RichText = true;
txtReport.RichTextMode = SPRichTextMode.Compatible;
txtReport.Rows = 5;
txtReport.Width = new Unit(200);
txtReport.ID = "txtReport";
txtReport.Text.Trim();
this.Controls.Add(txtReport);
reqVal = new RequiredFieldValidator();
reqVal.ID = "reqVal";
reqVal.ControlToValidate = txtReport.ID;
reqVal.SetFocusOnError = true;
reqVal.ErrorMessage = "*Comments field is mandatory";
reqVal.Enabled = true;
this.Controls.Add(reqVal);
Thanks in advance
From what it sounds like you are not re-adding the validator after the first submit, causing the second submit not to validate. But it's hard to tell from the fragment you posted (in what event/method is this being called?).