Extract information from XCUIElement - xcode7

If I'm trying to write a generic test that isn't dependent on labels or other value-specific elements, how do I get that information? Like if I were to tap a tableview cell and need some information from there later. Like to identify which cell was tapped. How could I grab a label from it using an XCUIElement?

The information you can extract from XCUIElement is limited to those in the XCUIElementAttributes protocol. The most notable of these are, identifier, value, and title.
You can set the identifier via -accessibilityIdentifier in your production code. The value property can be set from a couple of different paths, but it's usually the the active state of a control. For example, a picker's selected element.
You can try using the Accessibility Inspector to see what's already set on your element and then using a query to find that element.

You can extract some states for example, accessibilityIdentifier, isHitable, value or whatever but, unfortunately you cannot set/change any of these. So apparently you cannot detect if an XCUIElement is already tapped or not. Thats a big limitation in ui test fw.

Joe was sorta on to the right answer but he left out how to actually get the values for the properties he specified.
Lets assume I want to get the string that gets printed for the nav bar of my app
What I did was I created a XCUIElement for my nav bar:
XCUIApplication *app = [[XCUIApplication alloc] init];
XCUIElement *navBarTitle = [app.navigationBars elementBoundByIndex:0];
I then put a breakpoint after the creation of the navBarTitle object and used the debug console to print out the details of the navBarTitle object:
You see in the print out of the debug console that there is a key called identifier.
To extract that string from that object, I created an NSString object using the following method:
NSString *nameofuser = [navBarTitle valueForKey:#"identifier"];
I used the XCUIElement navBarTitle and then used the method valueForKey. valueForKey extracts the string value for the key identifier.
You can read up about this method here:
NSKeyValueCoding
valueForKey is the KEY to unlocking the answer to this question....pun intended :)

Related

Sikulix : Compare a image and a screen of website

I use sikulix and I want to check if a region of a website is red or green.
So I have taken a picture of the part of the website when is red (negatif.png)
A another region for the check of the color. But it doesn't work.
img_negatif = "negatif.png"
profit = Region(1342,212,175,21)
if profit == img_negatif:
click(Location(3406,1420))
else:
click(Location(23,1420))
Everytime sikulix take the else.
You cannot compare regions strictly by color. You can see my answer here (this is from years back but I think it's still relevant).
Sikuli compares the regions with pixel to pixel precision (you can set a similarity level if the images slightly differ but that's not the case). So having selected an area with just color and no other pattern will not work.
Wait for 3 second for negatif and if appear ...
if exists(img_negatif, 3):
click(Location(3406,1420))
else:
click(Location(23,1420))
You can search a region for color with Brobot, an open-source automation framework for Java that wraps SikuliX functions. Brobot references OpenCV for its color functionality. The Brobot documentation gives more detailed information on the framework. Additionally, there is a page in the documentation on color searches. For a summary of Brobot's color functionality, you can read this StackOverflow answer.
Finding the Red Region
public Matches find() {
ActionOptions actionOptions = new ActionOptions.Builder()
.setAction(FIND)
.setFind(COLOR)
.build();
return action.perform(actionOptions, redRegionState.getRedArea());
}
Elements of this code block:
Matches, the return value, holds information about the individual matches and the action.
ActionOptions is used to configure the action. Here, we tell it we want a FIND operation and we want to find by COLOR.
The Action class is the Brobot class that performs actions. The result of an action is always a Matches object. The function action.perform requires as parameters (1) the action configuration and (2) the object(s) to act on. Here, we pass in our actionOptions variable and our image.
The image “negatif.png” is stored in a Brobot variable called redArea, located in the state RedRegionState, and called with redRegionState.getRedArea().
The average pixel color of all pixels in “negatif.png” is calculated and this color is searched for on-screen.
The classes Action and RedRegionState are passed to this class with dependency injection.
The Red Image
You could also declare the Brobot variable containing “negatif.png” locally but one of the main benefits of Brobot is its ability to simulate the environment and test code with mock runs. This requires creating states that group associated images. Inside the state, the image definition would look like this:
#Component
#Getter
public class RedRegionState {
…
private StateImageObject redArea = new StateImageObject.Builder()
.withImage("negatif.png")
.withSearchRegion(1342,212,175,21)
.build();
…
}
Including a search region in the image variable means that the image will be searched for in this region on-screen unless a search region is added to the action configuration (the ActionOptions variable).
Clicking after Searching
public void click() {
int x = find().isSuccess() ? 3406 : 23;
action.perform(CLICK, new Location(x, 1420).asObjectCollection());
}
Elements of this code block:
Each action (FIND, CLICK, DEFINE, etc.) has its own success condition, and the result is stored in the Matches variable. It can be called with the boolean function .isSuccess().
As above, action.perform takes as parameters the action configuration and the object(s) to act on.
Usually an ActionOptions variable is required for the first parameter. However, an enum representing the action (here, CLICK) can be passed directly if you wish to use the action's default options.
The second parameter usually takes an ObjectCollection variable. In some cases, as with the image redArea, the object can be passed directly. Here, the object acted on, a Location, is converted to a singleton ObjectCollection and passed as the second parameter.
When building a more complex automation application, it would make sense to include the Location variables as well in states. Most likely, the Location at (3406, 23) would be in RedRegionState, as this Location has a special meaning when redArea is visible.
Disclaimer: I'm the developer of Brobot. It's free and open source.

Chrome displays different object contents on expand

Why does Chrome display two differing datasets depending on if you have the object view expanded?
In contracted view, my object has two properties:
In expanded view, my object has three properties:
The object you see in the console is a snapshot of the object at a particular point in time - the time when you logged it. When you expand the object, it will evaluate the properties again.
In the example below, I have created an object with two array properties. I logged it the console, and then I added a third property, c to it.
Only the first two properties are showing still, even though I just added a third property. After expanding the object in the console, I can see the third one. It is the latest state of the object.
If you hover over the little blue i icon, it explains what it has done:
Value below was evaluated just now.
#Gideon Pyzer is right. the properties were caculated and added after expanding the object in the console.
Just add one line code above your debug code and reopen the chrome dev tool, you will see the differences.
obj = Object.freeze(obj); //add this line before your console.log
console.log(obj);
Before:
After:
one similar question of mine:
Why can't I access the attr of the javascript object shown in chrome dev tool
You can clone your object to prevent re-evaluate.
console.log(Object.assign({}, obj));
You can get a real hard copy object by using this module. It will give you the snapshot of the object at moment when you call it.
https://www.npmjs.com/package/nest-object-deep-copy
const nestedHardCopy = require('nest-object-deep-copy');
console.log(nestedHardCopy(obj));

How to handle testing an HTML control that lacks sufficiently unique attributes?

I'm using Coded UI Test to test a web application.
I have a class Locator that I use to stash the specifics needed for CUIT to find a control. To operate on a control, a page object specifies the locator, not the control, and lower-level functions find the control and perform the operation.
Right now, my class has:
Locator name.
One or more attrName/attrValue pairs that can locate the HTML element for the control.
An operator (Contains or EqualTo) that specifies the matching needed.
The problem: Some of the controls I need to operate on don't have enough unique attributes to allow them to be found. (Yes, I know the developers should improve their HTML, but I don't control that.) I have been using a locator to find a nearby element, then "walking" in the DOM to get to the element I want. I hate having this DOM-walking code in my page object, even factored into a function.
A possible solution: I'm considering enhancing class Locator so that it can have either the attrName/attrValue pairs or a reference to a function that has the DOM-walking code. One advantage of this is that the page objects would always use a locator object. Another is that when the HTML is improved, the locator could change from DOM-walking code to attrName/attrValue pairs, which would be transparent to the page object.
Still, I think this may be over-complicated.
Is there a better solution to this problem?
Not sure specifically how your locator works, but could you find the closest parent to that object, let's say an HTML Div with an id of "parent", and then count the tag instances underneath? For example:
HtmlDiv id="parent">
HtmlHyperlink>text1</
HtmlHyperlink>text2</
Would require the following code:
public HtmlHyperlink text2Link
{
get
{
HtmlDiv parentDiv = new HtmlDiv(browser);
parentDiv.SearchProperties["id"] = "parent";
HtmlHyperlink target = new HtmlHyperlink(parentDiv);
target.SearchProperties["TagInstance"] = "2";
}
}
This would find the 2nd hyperlink under the parent object. (Tag instances are not zero based).
Then, you'd just interact with your object as needed:
Mouse.Click(text2Link);
for example.

What is the best design pattern to distribute a property change to subviews?

Suppose I have a setting in NSuserdefaults that should affect a property for a lot (but not all) UIView objects, for example the font size.
The setting can also be changed from a 'main' viewcontroller and should be 'distributed' to UILabel objects that live in a UIView in a UITableviewcell inside a UITableView inside a UINavigationController inside a UISplitviewController and so on...
If I create this property on all levels of the controller and view hierarchy, and set the property when the property in the parent is set, this costs a lot of code.
Apple seems to prefer this pattern to manage the managedObjectContext by handing it to the child controller along the chain.
But this seems like overkill. Lot of code is just for passing around the value of the property, while nothing is done with it. I do however use this pattern to set properties in all subviews of a view at once (by recursively walking through all subviews).
Delegation seems to be just as bad, except maybe not if the delegate would be top level parent view controller. But then I would be passing the delegate around to all child view controllers.
Should I go with Notifications instead? I already have a controller listening to (all) changes in the NSUserDefaults via the NSUserDefaultsDidChangeNotification. Should that controller post a specific notification when my setting is changed? In that case, who should listen to it? Should it be the view controller that is responsible for the views involved?
After some more reading, I found advise in the book Cocoa Design Patterns from Buck / Yacktman, as they state:
As a general rule, use notifications when there are potentially many objects that may observe the notification. Use delegates when exactly one object is given an opportunity to influence or react to changes as they are happening.
So notifications is the answer.

Retrieving all address information along Google Maps route

I am developing an Windows Forms application using VB.NET that offers the user to lookup addresses on Google Maps through a Web Browser. I can also successfully show the directions between two points to the user, as well as allow the user to drag the route as he/she pleases. My question now is - is it possible for me to get the lattitude/longitude information of the route, i.e. the overview_polyline array of encoded lattitude/longitude points and save it to e.g. a text file on my computer? Or is it possible to get a list of all the addresses located both sides of the route over the entire length of the route, and then save the data to a file on my computer? I'm using HTML files to access and display the Google Maps data in the Web Browser item.
Thank you
This is actually pretty simple if your just looking for the screen coordinates.
// this probably should be in your form initialization
this.MouseClick += new MouseEventHandler(MouseClickEvent);
void MouseClickEvent(object sender, MouseEventArgs e)
{
// do whatever you need with e.Location
}
if your strictly looking for the point in the browser, you need to consider the functions
browser.PointToClient();
browser.PointToScreen();
So, this method is usable if you know exactly where your form is (easy to get its coords) and where you webbrowser control is (easy to get coords of this as well since it's just a control in your form) and then, as long as you know how many pixels from the left or right, and from the top or bottom the image will be displayed, once you get the global mouse click coords (which is easy) you can predict where it was clicked on the image.
Alternatively, there are some scarier or uglier ways to do it here...
You can use the ObjectForScripting property to embed code to do this in the webbrowser. It's ugly to say the least. MSDN has some documentation on the process here: http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.objectforscripting.aspx
Because its really ugly, maybe a better solution is to use AxWebBrowser - it's ugly too but not so scary.
In addition, I found this post of someone wanting to do it on a pdf document, and a MSFT person saying its not possible, but really what he is trying to say is that it isn't built in, even with a pdf document its still possible to predict with high to certain accuracy where it was clicked if you use the first method i described. Here is the post anyway: http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/2c41b74a-d140-4533-9009-9fcb382dcb60
However, it is possible, and there are a few ways to do it, so don't get scared from that last link I gave ya.
Also, this post may help if you want to do it in javascript:
http://www.devx.com/tips/Tip/29285
Basically, you can add an attribute on the image through methods available in the webbrowser control, you can add something like onclick="GetCoords();" so when it is clicked, the JavaScript function will get the coords, and then you can use javascript to place the values in a hidden input field (input type="hidden") which you can add through the webbrowser control, or if there is one already on the page, you can use that. So, once you place the coords using javacript into that input field, you can easily grab the value in that using the webbrowser control, eg:
webbrowser1.document.getElementById("myHiddenInputField").value
That will get the value in that field, which you've set through JavaScript. Also, the "GetCoords()" function i mentioned is called SetValues() in the javascript method link i provided above (in the devx.com site) but I named it GetCoords because it makes more sense and didn't want to confuse you with the actual name they used, you can change this to any name you want of course. Here is the javascript they were using, this only gets the coords into a variable, doesn't put it into a hidden input field, we will need to do that in addition (at the end of the javascript SetValues/GetCoords function).
function SetValues()
{
var s = 'X=' + window.event.clientX + ' Y=' + window.event.clientY ;
document.getElementById('divCoord').innerText = s;
}
These guys are just saving it inside a div element, which is visible to users, but you can make the div invisible if you want to use a div field, there is no advantage or disadvantage in doing that, you would just need to set the visible property to false using javascript or css, but still, it is easier to use a hidden input field so you don't need to mess with any of that.
Let me know how you get along.