I'm currently trying to help automate some coded UI tests using C# for a web application. A frequent problem I'm encountering is that it can be extremely difficult to determine if a UITestControl object exists on the page or not. Unfortunately, Microsoft's documentation on their MSDN website for anything regarding coded UI tests is practically non-existant (see here their page for UITestControl).
Basically what I'm asking is:
What is the best way to determine if a UITestControl exists on the page or not?
How does the UITestControl.Exists property work?
What does the UITestControl.Find() method do?
How does the UITestControl.TryFind() method work?
How I've tried to handle it:
As I mentioned earlier, the documentation on all of these classes and methods is mostly blank. The most you can get to describe any of the methods and properties is a 1 line description in Intellisense, so I've been experimenting with the methods that are listed.
First I tried checking if the UITestControl.Exists property was true, but over time and consulting others' experience with it, it became apparent that it always returns true, even if the browser isn't open. Since the option that seemed most obvious wasn't working, I tried using the UITestControl.Find() method, but since it takes no arguments and returns nothing I couldn't figure out what it did. I tried using the UITestControl.TryFind() method, and occasionally it worked, but I found that it only seemed to return false when I wasn't on the correct page; it always returned true otherwise. Clearly I had no idea how it worked, and shouldn't use it as a test.
I figured if I couldn't get the provided methods to do their job, I'd have to try to make my own tools. I most recently tried using Mouse.Hover(UITestControl) in a try/catch block to determine if the control exists like so:
public bool DoesExist(UITestControl control){
if(control == null)
return false;
try{ Mouse.Hover(control); }
catch (UITestException)
{
return false;
}
return true;
}
It works sometimes, but in certain situations it seems to return false positives for reasons I don't understand. I'm still flying blind, and I'm nearly out of ideas.
I am using Visual Studio 2012, and Microsoft .NET Framework version 4.5.50709.
Partial answer about the Find() and TryFind() methods.
After setting the various search properties in the class instance for the control the Find() method does the actual searching for a control to match. The SearchProperties are used to try and find a control. If no controls are found then the search fails - forget exactly what happens then, possibly an exception is thrown but the documentation does not state that. If one control is found that the Find() completes. If two or more are found then the search continues by using FilterProperties to reduce the number of controls found to one.
The Coded UI recorder generates code of the style UIControl aControl = this.UIMap.uione.uitwo.uithree; which leads to the question of how does uione get a value referring to a control such that uitwo can be evauated? The only answer I have found is in the Description part of http://blogs.msdn.com/b/balagans/archive/2009/12/28/9941582.aspx which says "the search for the control starts ( explicit by Find() or implicit by any usage of the control in actions or property validations )".
So Find() performs the search for a control and it can be called explicitly or implicitly.
TryFind() is basically the same as Find() except that it returns a boolean indicating whether the control was found. Again, the documentation is poor but I believe that TryFind() returns true if exactly one control is found, false otherwise.
Another useful find method is FindMatchingControls which returns a (possibly empty) collection of all controls that match the search criteria.
As per yonitdm's answer, using the BoundingRectangle can help when there are multiple items that match but most are not on display. The values of Top and Left can also be used. Doing a FindMatchingControls and screening the results to ignore anything with negative Top or Left may work.
When developing tests the DrawHighlight method is useful, it draws a rectangle around a control. The same sort of rectangle that is drawn when recording assertions with the cross-hairs tool.
The Coded UI content index has lots of good information. The link to "How does UI Test Framework find (search) for a control" may be particularly helpful for you.
Instead of using obj.Exists() we have coded our own exists method that uses a combination approach of EnsureClickable() and BoundingRectangle.Width>0 to make sure that the control has a screen point.
ETA- oops, sorry left off an important part. Updated to add .Width to make sure it's greater than 0, you may need to use length if you width is somehow not working.
I am using tryfind() .. it is working fine.
if (obj_webor.GenLink.TryFind())
{
logdata.WriteLine(obj_webor.GenInnerText + " Exist !");
}
else
{
logdata.WriteLine(obj_webor.GenInnerText + " Does Not Exist");
}
Earlier i was using obj_webor.GenLink.exist().. but is was giving error if it was control not existing and exception occurs. tryfind is ok
Related
I want to get the text "Running" which is under the property Value.Value. However, this is not part of the properties listed in the available fields of the AutomationElement Class.
The managed UI Automation API is a bit strange and tricky to use (aside: TBH, it’s quite terrible as an API and needs to be overhauled, using it for any amount of time and you’ll find yourself wrapping it with your own methods that make it easier to use, maybe someone has done this a put it in a nice library, IDK).
To retrieve property values (or call available methods) you first need to get the ‘pattern’ for the AutomationElement. The pattern we are interested in is the ValuePattern
element.GetCurrentPattern(ValuePattern.Pattern);
This method annoyingly returns a plain object that we need to cast, so we can get the Value. Using C#7 syntax this is slightly less painful:
if(element.GetCurrentPattern(ValuePattern.Pattern) is ValuePattern valuePattern)
{
Console.WriteLine(valuePattern.Current.Value);
}
I apologize in advance... I'm new to C# and am trying to teach myself (badly)!
I've been set a number of tasks to decipher some code and explain what it's doing, but on these three pieces I'm really struggling - I only have the code detailed - nothing else to put it onto context... otherwise I think I'd be fine.
if (HasMark && !MarkReference.Entity.IsValidOn(DateSignedUp.Value)) {
LogError(PersonMessages.MarkNotValidOnDateSignedUp(DateSignedUp));
My thought:
If HasMark variable is true and the DateSignedUp value is false, then call the PersonMessages error and specify the DateSigned up value.
if (From.HasValue && From.Value<Session.Current.VirtualNow) logError(PersonNonMessages.PastHoliday);
My thought: If From is true and From equals (whatever) "Session.Current.VirtualNow" is, through up the PersonNonMessages.PastHoliday error.
if (pastAuditLogs != null) pastAuditLogs.ForEach(x => x.AuditLogs = auditLogs);
My thought: If pastAuditLogs isn't null, for each entry in the pastAuditLog, loop through and find the latest entry for each.
Could anyone please advise on if any of my assumptions above are correct, or if I'm even close to understanding the code?
Apologies it's so vague - if there was any other supporting code or background scenario it'd be 10x easier to understand!
Many thanks
You're using Visual Studio, correct?
You can right click on any symbol (like HasMark) and then choose Show Definition. Then, you can see a white arrow in a blue circle at the upper left of your pane, that takes you back to where you were. This is an incredibly handy feature for code archaelogy.
Also, if you hover your cursor over code you often get a bit of explanation in a tooltop.
Let's tear apart this hunk of code bit by bit...
if (HasMark && !MarkReference.Entity.IsValidOn(DateSignedUp.Value)) {
LogError(PersonMessages.MarkNotValidOnDateSignedUp(DateSignedUp));
}
It means...
If HasMark is true....
Call the boolean-valued function MarkReference.Entity.IsValidOn() ...
Passing the value DateSignedUp.Value
If that function returns false (!) ...
Call the function PersonMessages.MarkNotValidOnDateSignedUp() ...
Passing the value DateSignedUp ...
and pass the returned value to the function LogError().
The && operator won't perform step 2 above if HasMark is false.
The order I've shown here is important. In this bit of code, the second line seems to have the side effect of marking something not valid. But maybe that MarkNotValidOnDateSignedUp() method just looks up some message to toss into LogError().
To know exactly what all this stuff means isn't possible without having your code base present. That's what you use Show Definition to do.
<CTRL><SHIFT><F> activates a Find All function. That's handy too.
Can you run this stuff in the debugger? If so, step through it with Step Into and see what it does.
Pro tip: There's an addon package to Visual Studio called Resharper. It helps with this kind of code archaelogy. They have a free evaluation and sell personal copies for short money.
The request:
I'd like to be able to write an analyzer that can provide a proxy value for a certain expression and trigger a re-parsing of the document.
The motivation:
Our code is littered with ABTests that can be either in a deployed or active state with a control and variant group.
Determining a test's state is done through a database lookup.
For the tests that are deployed with the control group, any statement of the following form will evaluate to false:
if(ExperimentService.IsInVariant(ABTest.Test1))
{
}
I'm trying to provide tooling to make this easier to deal with at develop time by greying it out in this scenario.
As it is, this is fairly limited and not robust because I basically have to play parser myself.
What if the actual code is
if(!ExperimentService.IsInVariant(ABTest.Test1))
or
if(ExperimentService.IsInVariant(ABTest.Test1) || true)
or
var val = ..... && (ExperimentService.IsInVariant(ABTest.Test1);
if(val){
// val is always going to be false if we deployed control.
}
A possible approach I could see provided is by allowing us to write analyzers that are fired once and rewrite the tree before the actual IDE parsing happens (or, well, just parse it a second time).
These should only fire once and allow us to replace a certain expression with another. This would allow me to swap all of these experiment calls for true and false literals.
As a result, these sections could benefit from all the other IDE features such as code greying for unreachable code but also more intricate ones like a variable that will never have a different value
Obviously this is just an example and I'm not sure how feasible it is. Any suggestions for a proper feature or something that already exists are more than welcome.
I don't think there's an approach that doesn't have a compromise.
ReSharper doesn't support rewriting the AST before analysis - that would just rewrite the text in the file.
You could write an analyser that greys out the code, by applying a "dead code" highlight to the contents of the if block, but as you say, you'd need to parse the code and analyse control flow in order to get it correct, and I think that would be very difficult (ReSharper does provide a control flow graph, so you could walk it, but it would be up to you to A. find the return value of IsInVariant and B. trace that value through whatever conditions, && or || statements until you find an appropriate if block).
Alternatively, you could mark the IsInVariant method with the ContractAnnotation attribute, something like:
[ContractAnnotation("=> false")]
public bool IsInVariant(string identifier)
{
// whatever...
}
This will tell ReSharper's analysis that this method always returns false (you can also say it will return true/false/null/not null based on specific input). Because it always returns false, ReSharper will grey out the code in the if statement, or the else branch if you do if (!IsInVariant(…)).
The downside here is that ReSharper will also add a warning to the if statement to tell you that the expression always returns false. So, it's a compromise, but you could change the severity of that warning to Hint, so it's not so intrusive.
This is not enough to really warrant the bounty, but one solution that might apply from the developer documentation is to create a custom language and extend the basic rules.
You said
I'm trying to provide tooling to make this easier to deal with at develop time by greying it out in this scenario.
Greying out the corresponding parts might just be done by altering syntax highlighting rules.
See this example for .tt files.
I'm writing a Dashboard Application in C#, using DevExpress components. I am trying to dynamically create a circular gauge, and update the gauges value using a callback function. In the DevExpress sample here:
http://demos.devexpress.com/ASPxGaugesDemos/Gauges/CircularGauge.aspx
They show how to update a gauge that has already been added to the form at design time. One of the calls in their sample has var gague = window[gaugeName]
When I make the call to this function the value comes back undefiend:
function PerformCallbackCore(gaugeName) {
var gauge = window[gaugeName];
m_isDirty = gauge.InCallback();
if (!m_isDirty)
gauge.PerformCallback();
}
Does anyone possibly know why I cannot retrieve the gauge value?
Thanks - Larry
It is due to bad code in the gauge demo. Yes, I use (and pay for) DX; I can say that.
The code uses setTimeout with a string (enough ick here!) and passes in the "name" of window property assigned to the control with ClientInstanceName (the code won't work if the name used and this don't match up). The demo code is further confusing/ugly by having a different "proxy" function for Gauge1 ... GaugeN.
Now, I suspect that the ClientInstanceName wasn't used or the correct name wasn't passed somewhere, so window[aPropertyName] evaluates to undefined, however ..
.. a better way to write it would be to use/pass the object directly instead of relying on the artificial "client name" / window property. See
ASPxClientGaugeControl (and follow links to the appropriate handler) and consider this:
<ClientSideEvents EndCallback="onEndGaugeCallback" />
With a single unified callback (and distinct lack of "client names" and useless proxy methods):
function onEndGaugeCallback (s, e) {
// "s" is for Sender; it evaluates to the appropriate [Gauge] control
// or rename it to "gauge" or whatever :-)
}
Happy coding!
I am trying to track down a very elusive bug in an application that manipulates a FlowDocument. I have shown below three consecutive lines of debugging code, together with their output:
Debug.Assert(ReferenceEquals(document1, document2));
Debug.WriteLine(document1.Blocks.Count); // 1
Debug.WriteLine(document2.Blocks.Count); // 3
Can anyone help me to understand how two references to the same object can have different values for a given property? Or am I missing something about the way ReferenceEquals works?
Thanks,
Tim
Edit:
If I change the assertion to an if block, the debugging code never runs ...
if (ReferenceEquals(document1, document2))
{
Debug.WriteLine(document1.Blocks.Count);
Debug.WriteLine(document2.Blocks.Count);
}
... which makes me feel utterly stupid, because the ReferenceEquals test is clearly working, but I don't understand why the assertion is not working.
Two things that might be happening from the top of my mind:
Accessing Blocks or Blocks.Count might mutate state (it shouldn't, but it is possible).
The object might be changed on another thread between the two calls. Do you use multi-threading in the application ?
Also, if the references are of different types (ie. document2 is of an inherited type), the property might be overloaded to return something different. You could check to see whether document1.GetType() == document2.GetType().
Edit in response to your update
Debug.Assert will only ever run, if the assembly is compiled in Debug mode. If you are running Release, it will not be run. This is because Debug.Assert is decorated with the [Conditional("DEBUG")] attribute.
It seems that the issue is the fact that you indeed have 2 different objects.
If a property has side effects it can yield different results each time you call it. E.g. DateTime.Now does not always equal DateTime.Now.
Without knowing anything more about the code, that would be my guess.
EDIT: Using Reflector on FlowDocument shows that Blocks return a new instance each time it is called. Additionally, the Count property BlockCollection is rather elaborate, so I would take a closer look at that. Unfortunately I don't know the involved types very well, so I can't immediately tell you what is wrong.
Possibilities (some of which you have already discounted in the comments):
Some external process, say something that is loading Blocks into FlowDocument, is altering the value between writes.
Heisenberg: reading the Blocks property affects it. This happens sometimes when reading rows from a data source. I'm not familiar with FlowDocument so I'm not sure how feasible this is.
If the instances were declared as different types, their references would still be equal, but the value of Blocks (or Blocks.Count) could be overridden, resulting in different return values since different code might be called - like Object.ToString() vs Int.ToString().
You're somehow calling this debug code in the middle of a loop. This could happen if you're running it in the command window or some attached debugger instead of within the application.
You have dead pixels on your screen that make the first "3" look like a "1".
You live next to a nuclear reactor.
Some things to try:
Run your .Assert code in a loop and see if the values stabilize.
Set a read/write breakpoint on the Blocks value. (I know you can do this in C, but haven't tried it in C#)
Update
Regarding your additional question about .Assert() not working as expected:
Just looked at this note on MSDN regarding Debug.Assert().
By default, the Debug.Assert method works only in debug builds. Use the Trace.Assert method if you want to do assertions in release builds. For more information, see Assertions in Managed Code.
Are you running a debug build or a release build?
Are you certain that the Blocks object reference points to the same object? Try a
Debug.Assert(ReferenceEquals(document1.Blocks, document2.Blocks));
and see if that succeeds.