CodedUI "FindMatchingControls()" works 10% of the time but usually returns about half of the controls - coded-ui-tests

Problem: I am using FindMatchingControls() to create a Collection of rows in a WPF table. I have written a loop that will set the ComboBox in each row to a given value. The whole thing works sometimes but more often than not, FindMatchingControls() actually finds about half of the rows. How can I configure timeouts or change settings to make it find all 50 controls every time or perhaps to find the first 10 and then to find the next 10 etc?
Background: I am testing a WPF window and on it, there's a table, each row in the table has a drop down list. There are 50 rows and in future there could be more so it is not feasible for me to record the setting of each one, my recorded test would be out of date with each new version (every month or so).
I have therefore recorded the setting of 1 ComboBox and then I used FindMatchingControls() to create a Collection. I loop through the Collection setting each ComboBox in that collection to the desired selection. The first 23 rows are shown on my current screen resolution. The only problem is that FindMatchingControls() sometimes returns 23, sometimes 26 , sometimes 34 and sometimes it returns all 50 rows! My question is, how do I fix the code below so that it always return all 50 rows (and possibly more in future).
You can see from the code that I found the Parent control twice so pseudo code is below.
Psuedo Code:
1) Find Parent Container (table)
2) Define a row (that is a child of the parent table)
3) Use FindMatchingControls to get a Collection of Rows
4) Loop through the Collection, finding the ComboBox in each row and setting it's selection to a value passed into the method.
CODE:
public void PlaceAnOrderScreen_SelectItems_List(String item /*Value to set all 50 ComboBoxes to*/)
{
WpfControl rowOfOrderItems = new WpfControl(this.UIOptimalOrderSystemClientShWindow.UIItemCustom22.UIListViewAutoID37Table);
rowOfOrderItems.SearchProperties[WpfControl.PropertyNames.ControlType] = "DataItem";
rowOfOrderItems.SearchProperties[WpfControl.PropertyNames.ClassName] = "Uia.ListViewItem";
rowOfOrderItems.WindowTitles.Add("Order Management System");
rowOfOrderItems.Find();
rowOfOrderItems.DrawHighlight(); //Visible diagnostic
//should get a collection of 50 controls ...
//... but this is dodgy, it sometimes finds 23, 26, 34 or ocassionaly all 50 controls.
//There are 23 visible controls and the rest, you have to scroll down to see.
UITestControlCollection itemRows = rowOfOrderItems.FindMatchingControls();
int c = 0;
int i = 1;
string label = String.Empty;
foreach (var auditSelectionBox in itemRows)
{
//After the top 15 drop down selections have been made, strat scrolling down.
//This is because setting the Value for a list box that is off the screen
//causes it to complain the control is blocked...
if (c >= 15)
{
if (i >= 3) //The scroll wheel moves 3 rows at a time, so only scroll once for every 3 rows...
{
Mouse.MoveScrollWheel(-1);
i = 0;
}
}
i++;
c++;
WpfCell auditDDL1 = new WpfCell(auditSelectionBox);
auditDDL1.SearchProperties[WpfCell.PropertyNames.ColumnHeader] = "Total";
auditDDL1.WindowTitles.Add("OrderSystem 5");
//Works but takes 5 - 16 seconds per drop down list
auditDDL1.Value = item;
}
}

Instead of trying to find matching controls based on another row, you could use a method that takes the parent (in your case the table) and returns all it's children in a recursive way. It digs all the way down until all available children have been found. It shouldn't matter how much row's your table has, it will try and get all of them. It's usable for any UITestControl.
public ParentControl GetChildControls(UITestControl parentControl)
{
ParentControl parent = new ParentControl();
if (parentControl != null)
{
List<ParentControl> children = new List<ParentControl>();
foreach (UITestControl childControl in parentControl.GetChildren())
{
children.Add(GetChildControls(childControl));
}
parent.Children = new KeyValuePair<UITestControl, List<ParentControl>>(parentControl, children);
}
return parent;
}
The parent class
public class ParentControl
{
public KeyValuePair<UITestControl, List<ParentControl>> Children { get; set; }
public string Value
{
get
{
return Children.Key.Name;
}
}
}
I just added the Value property for easy access to the name of UITestControl.

PixelPlex (above) has provided the best answer. All I had to add to PixelPlex's code was an If statement to set the ComboBox to a value when it was found. The foreach is therefore as below in my case ...
foreach (UITestControl childControl in parentControl.GetChildren())
{
children.Add(GetChildControls(childControl));
//Added below If statement to set ComboBox selected item to "Carrots"...
if (childControl.ClassName == "Uia.ComboBox")
{
WpfComboBox cb = (WpfComboBox)childControl;
cb.SelectedItem = "Carrots";
}
}
This selects Carrots from my ComboBox... Everything that does not satisfy my If statement is not relevant so I don't do anything with it.

Related

Tabulator: add class to class list, on cells when hidden by pagination

I need to add and/or remove a class to all cells even when they are hidden by pagination. I am able to add a class, but only the cells on the active page are getting the class. I understand that is because it is only updating what is available in the DOM and the hidden rows are not active in the DOM at the time, I'm adding the class.
Is there a way that Tabulator handles this?
As you can see from below i'm getting the rows (not shown) and then looping over the rows and attempting to update the cell classList.
for (var i = 0; i < rows.length; i++) {
if (rows[i] != this){
var row = rows[i],
cell = row.getCell(col),
cellElement = cell.getElement();
cellElement.classList.add('disable-cell');
console.log(cell);
}
}

How to click on an exact row on wintable with codedui?

I want to click on an exact row in a WinTable where my criteria meets but couldnt succeed so far. I can search criteria for an exact row but I can not get total number of rows so that I would make a loop for all rows. I tried collection and table.Rows.Count,but both brings nothing to me. Can someone help me on this ?
#region Variable Declarations
WinTable uIG1Table = this.UIProMANAGEWindow.UIDefinitionsWindow.UIG1Window.UIG1Table;
WinRow dataGridrow = uIG1Table.GetRow(0);
#endregion
UITestControlCollection rows = uIG1Table.Rows;
// MessageBox.Show(rows[5].RowIndex.ToString());
foreach (WinRow row in uIG1Table.Rows)
{
foreach (WinCell cell in row.Cells)
{
if (cell.Value.ToString() == "E81")
Mouse.Click(cell, new Point(5, 0));
}
}
and this is the code with for loop
int rows = uIG1Table.Rows.Count;
for (int i = 0; i < rows; i++)
{
foreach (WinCell cell in dataGridrow.Cells)
{
if (cell.Value.ToString() == "E81")
Mouse.Click(cell, new Point(5, 0));
}
}
When doing a GetChildren() on a row, you will notice that the first child is of type RowHeader. A user typically clicks the row header to select the row.
Following code will iterate all the rows in a DataGridView and click the row header, effectively selecting the row:
UITestControlCollection rows = YourUIMapTable.Rows;
foreach (UITestControl row in rows)
{
UITestControl rowHeader = row.GetChildren().Single(child => child.ControlType == ControlType.RowHeader);
Mouse.Click(rowHeader);
}
If you want to select a specific row, you can do something like this:
Mouse.Click(YourUIMapTable.Rows[putIndexNumberHere].GetChildren().Single(child => child.ControlType == ControlType.RowHeader));
The sample code above is based on the program I wrote in my answer to this question:
How to get cell color information of a WinCell with codedui?

Adding an image to only one node within a Tree View

I'm currently working on modifying a Tree View control (Telerik MVC Extensions) for a customer request. Their request is a simple one: if an item within the tree has an Attachment, add a paperclip beside the node to identify it.
I have so far been able to do so but, found a small hiccup with this. I can add the image to certain nodes that have an Attachment, however, all nodes that don't should have no image (by that, I mean they should appear normal within the tree). Instead though, I find that the tree places a blank the size of the paperclip image.
Is there a way to dynamically turn off this blank (aka not add an Image Url if unnecessary)? Below is my code where I'm executing this process (is done on the expansion method of the tree due that only the bottom level shows the Attachments).
Navigation Controller
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult GetNextTreeViewLevel(TreeViewItem node)
{
...
//If bottom layer, then execute the following
var data = _TreeRepo.GetProcessesByParcel(int.Parse(values[1]), cntTreeList);
nodes = from item in data
select new TreeViewItem
{
Text = item.strProcess,
Value = "PR" + "," + item.cntProcess.ToString(),
LoadOnDemand = false,
Enabled = true,
Selected = SelectedSearchResult.ToString().Length > 0
&& SelectedSearchResult.ToString().Split('~').Length > 3
&& decimal.Parse(SelectedSearchResult.ToString()
.Split('~')
.Last()
.Substring(2)) == item.cntProcess
ImageUrl = item.ysnHasAttachment.HasValue && item.ysnHasAttachment.Value == 1
? #"/Content/NewImages/attachment.png"
: string.Empty
};
return new JsonResult { Data = nodes };
}
Screen shots of what it looks like without/with code for Image Url:
I at long last came up with a solution to this issue. The problem was how I was getting my data added to the nodes. The original logic was doing a Linq query after fetching the data to get an IEnumerable object.
Because of that, every node was trying to add an image (even if there was none). Hence the weird looking space. Below is how I reworked this logic to correctly get my data.
var processNodes = new List<TreeViewItem>();
var data = _TreeRepo.GetProcessesByParcel(int.Parse(values[1]), cntTreeList);
foreach (var item in data)
{
#region Process has at least one Attachment
if (item.ysnHasAttachment.HasValue && item.ysnHasAttachment.Value == 1)
processNodes.Add(new TreeViewItem
{
Text = item.strProcess,
Value = "PR" + "," + item.cntProcess.ToString(),
LoadOnDemand = false,
Enabled = true,
Selected = SelectedSearchResult.ToString().Length > 0
&& SelectedSearchResult.ToString().Split('~').Length > 3
&& decimal.Parse(SelectedSearchResult.ToString()
.Split('~')
.Last()
.Substring(2)) == item.cntProcess,
ImageUrl = "/Content/NewImages/smallAttachment.png"
});
#endregion
#region Process has no Attachments
else
processNodes.Add(new TreeViewItem
{
Text = item.strProcess,
Value = "PR" + "," + item.cntProcess.ToString(),
LoadOnDemand = false,
Enabled = true,
Selected = SelectedSearchResult.ToString().Length > 0
&& SelectedSearchResult.ToString().Split('~').Length > 3
&& decimal.Parse(SelectedSearchResult.ToString()
.Split('~')
.Last()
.Substring(2)) == item.cntProcess
}
#endregion
}
nodes = processNodes;
At this point, you can now return the nodes. Those that should have had an Attachment icon will, and those that shouldn't won't. Funny how 4 months later, you can come up with something off the cuff.

Conditional Formatting for items created in the last 5 minutes in SharePoint 2010

All,
I've been looking all day and have tried numerous solutions, but just can't get it to work. Our team projects a list that is constantly updated and we want to highlight only newly created items for 5 minutes. After 5 minutes, the row would return to normal. (FYI- the list is projected on a display and updated using AJAX asynchronous update every 15 seconds)
Basically, I want to set conditional formatting on list items created in the last 5 minutes. If the item was created in the last 5 minutes, the row will be highlighted. After the 5 minutes are up, the row would return to normal.
I tried SharePoint Designer conditional formatting by creating a calculated column in Date/Time format called "Created + 5" and tried to set an expression where the formatting is applied (row is highlighted) when "Created + 5" is greater than or equal to current date. So after 5 minutes, the row will no longer be highlighted (because the current date/time will exceed the "Created + 5" value)
Here is the expression from the SPD Advanced Condition Builder:
ddwrt:DateTimeTick(ddwrt:GenDisplayName(string($thisNode/#Created_x0020__x002b__x0020_5_x))) >=
ddwrt:DateTimeTick(ddwrt:GenDisplayName(string($Today)))
I think the problem is that the [Current Date] option ($Today in the expression builder) only accounts for date and not time. It looks like it just ends up highlighting everything that was created today, which is not very useful.
Any thoughts or help!? I have never messed with the advanced conditions because usually the basic stuff works fine for me! If anyone has any other ideas too like JavaScript or anything else that would work, I am open to that too as long as it will continuously update!
Thanks all!!!!
[Today] actually doesn't work properly in 2010, there are some workarounds though, e.g. https://abstractspaces.wordpress.com/2008/05/19/use-today-and-me-in-calculated-column/.
You can also use the approach with calculated column: https://blog.splibrarian.com/2012/06/06/using-calculated-columns-to-add-color-coding-to-your-sharepoint-lists/
Since you want this to update automatically without requiring someone to manually refresh the page, JavaScript is your best bet. You can have a function run repeatedly on a specified interval, checking the current date against the values in a date column.
Something like the following code would work, though you may need to tweak the CSS selectors specified in the calls to document.querySelector and querySelectorAll to match your particular HTML.
<script>
formatCell();
function formatCell(){
var frequencyToCheck = 2 /* num seconds between updates */
var minutes = 5; /* num minutes back to highlight */
var targetColumn = "Display name of the column you want to check";
var formatting = "background-color:darkred;color:red;font-weight:bold;";
var comparisonDate = new Date();
comparisonDate.setHours(comparisonDate.getHours() - minutes);
var tables = document.querySelectorAll("table.ms-listviewtable"); /* should get all list view web parts on the page */
var t_i = 0;
while(t_i < tables.length){
var headings = tables[t_i].rows[0].cells;
var columnIndex = null;
var h_i = 0;
while(h_i < headings.length){
var heading = headings[h_i].querySelector("div:first-child");
if(heading != null){
var displayName = heading.DisplayName ? heading.DisplayName : (heading.innerText ? heading.innerText : heading.textContent);
displayName = displayName.replace(/^\s+|\s+$/g,''); /* removes leading and trailing whitespace */
if(displayName === targetColumn){
columnIndex = h_i;
break;
}
}
h_i += 1;
}
if(columnIndex != null){ /* we found a matching heading */
var rows = tables[t_i].rows;
for(var i = (rows.length > 0 ? 1 : 0); i < rows.length; i++){
var cells = rows[i].children;
if(cells.length <= columnIndex){continue;}
var valueToEval = cells[columnIndex].innerText ? cells[columnIndex].innerText : cells[columnIndex].textContent;
if(typeof valueToEval == "undefined"){valueToEval = "";}
valueToEval = new Date(valueToEval);
if(valueToEval > comparisonDate){
cells[columnIndex].setAttribute("style",formatting);
}else{
cells[columnIndex].setAttribute("style","");
}
}
}
t_i +=1;
}
setTimeout(formatCell,frequencyToCheck * 1000);
}
</script>
One potential pitfall is that while this approach will "age" records appropriately based on their displayed values (causing them to stop being highlighted as they grow stale), it won't automatically pick up new changes to the list; you'd need to refresh the page (or at least refresh the view in the web part) whenever you want to see updated information.

Unique contstaint error when rejecting changes on a DataTable

I have a datatable problem when I reject changes on the table. I've created an example below which demonstrates the problem:
DataTable table = new DataTable();
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Last_Name", typeof(string));
table.Columns.Add("Male", typeof(Boolean));
foreach (DataColumn column in table.Columns)
{
if (column.ColumnName == "Name")
{
column.Unique = true;
}
}
DataRow row;
row = table.NewRow();
row["Name"] = String.Format("Steve");
row["Last_Name"] = String.Format("Smith");
row["Male"] = true;
table.Rows.Add(row);
table.AcceptChanges();
So at this stage I have a DataTable with a unique column constraint and 1 row in that table.
I now delete that row:
row.Delete();
This sets the rowstate to Deleted.
At this stage I realise that I've made a mistake and want to add the row again. So I create the new row again and add it to the DataTable:
row = table.NewRow();
row["Name"] = String.Format("Steve");
row["Last_Name"] = String.Format("Smith");
row["Male"] = true;
table.Rows.Add(row);
At this stage my DataTable contents are in the following state:
table.Rows[0].RowState is Deleted
table.Rows[1].RowState is Added
Now, I've changed my mind about the whole thing and want to get back to how I started so I call RejectChanges:
table.RejectChanges();
When I do this I receive the following error:
Column 'Name' is constrained to be unique. Value 'Steve' is already present.
I understand that there are 2 rows with the same values but I thought reject changes would have ingored this as the RowStates are different.
Any ideas how I can get round this?
In my live code I use this to move rows between to 2 grids (like allowing the user to selected what columns are visible)
I'm using C#4.0 in Visual Studio 2012
Thanks in advance

Resources