I'm new to automatization, Android, Selenium, Appium and xpath, too. I know it's suck a great beggining.
I write tests for Android devices, but the application I have to test have a lot of costum views. I found out the best way to interact with these custom items is to put an "android:contentDescription" field in the Views. My only question is how to get access to the element with have a specified contentDescription? This is az android specific question, I'm not even sure that the content-desc is the field I'm looking for.
I have the hierarchy provided by Android UI Animator Viewer:
http://i.imgur.com/NUGc56o.png
The ways i've tried:
xpath: //*[contains(#android:contentDescription,'example text')]
I was able to get access by finding them as an ImageView, but as I mentioned I need to work with custom Views
My code looks like somtihng like this:
driver.findElementByXPath("//*[constains(#content-desc,'Login')]").click();
Thanks for the help!
You could also try using Accessibility labels or the UIAutomator locator strategy.
Here's Appium's documentation on those.
Your xpath is incorrect. It should be: "//android.widget.ImageView[#content-desc='Login']"
Here's some pseudocode of what you should do:
login_image = driver.findElementByXPath("//android.widget.ImageView[#content-desc='Login']"); // Gets you the WebElement
print login_image.getClass(); // Just for debugging, make sure it's not nil/null
login_image.click(); // Click on it!
Related
Objective: To click on Access for all guest users.
I am unable to find this element.
uiautomatorviewer shows the following screenshot.
Content description is following copy/pasted
"Access for all guest users
Provider not listed? Stay tuned, we will be adding more TV providers shortly."
Notice: the line break after user. I believe this is why my xpath is not working.
My xpath is:
"//android.view.View[#content-desc ='Access for all guest usersProvider not listed? Stay tuned, we will be adding more TV providers shortly.']"
I cannot use index instead of content-desc because of the object in layers above have the same class and index.
Using tap to a specific might solve the problem but is not a good solution.
any ideas on how to handle that linebreak.
If you notice the XML hierarchy, you will notice that your element is inside a WebView (3rd node from top). So its not getting identified. You have to first switch to WebView and then use your code.
The way you mentioned the xpath should work, once you switch to WebView.
I'm using React Native to develop an app that requires end-to-end testing.
Coming from a Selenium WebDriver background, it seems to me that element finding in Appium can be very awkward compared to WebDriver, since native components only have ID and a single non-user-defined class.
Is there a way I can add some sort of metadata to elements to make them easy to find?
Say if I have a table with complex elements inside a cell, and I need to first find the right row, then the cell, and then find the right components to manipulate inside the cell.
Ideally I'd want to be able to enumerate rows by searching for something like "myTargetRows". That would give me a list of rows.
If I understand it correctly, no two components can have the same ID in native applications, so I can't use ID just like that, right? (I.e. use the same ID, "myTargetRows", for multiple row components).
If not, should I use numbered IDs like "myTargetRow0", "myTargetRow1", etc, and then use XPath to partially match the ID?
Isn't there a better way?
If I can do something like that, can I then just chain those findElement calls to find the right nested elements I want?
P.s.: I don't want to hardcode the exact component hierarchies in my locators to avoid invalidating them should I move anything around in my views, so those point-and-click solutions won't help.
P.s. 2: Solutions must work both on Android and iOS, even if I need to implement some sort of abstraction for it myself.
You should use accessibilityLabel props of View.
accessibilityLabel PropTypes.node
Overrides the text that's read by the screen reader when the user
interacts with the element. By default, the label is constructed by
traversing all the children and accumulating all the Text nodes
separated by space.
More info can be found here
For unique ids, lets say you have a listview and 100 rows. You can combine rowId and static text for accessibilityLabel.
eg: 0_MyCustomRow, 1_MyCustomRow
Since appium supports different search strategies which are also slightly different per platform I am using the following approach in one of my projects:
I have a helper which can be easily imported into each class which returns cross platform (iOS and Android) test ID props
export function getTestIdProps (id) {
return { accessible: true, accessibilityLabel: id, testID: id }
}
During Development we make sure that each to be tested component receives those test IDs similar to this:
return (
<ComponentToBeTested>
<View {...getTestIdProps('unique-test-id-goes-here')} moreProps>
</View>
</ComponentToBeTested>
)
Careful Make sure to check the react native docs to see which basic element supports theses props. Not all react native elements support the testID or accessibilityLabel. If they don't, these props will be ignored.
Finally, in your Appium Test (Example in Java) you can then identify the element easily by its accessibility ID, similar to this:
public static By byAccessibilityId(final String id) {
return MobileBy.AccessibilityId(id);
}
For further reading also see http://appium.io/docs/en/commands/element/find-elements/
Take a look at article in Sauce Labs blog, thats a good a example of dealing with RN apps.
There are scenarios in feature files wherein I've use the text "Foo" and on click its open a new page. this text sometime changes to "Foo1" or "Foo2" or to something else. to avoid line by line change in feature file for "Foo" to "Foo1" or "Foo2" is there any way that I can globally declare variable in top/bottom of the feature file where I can set the required text in variable on fly and I shall start executing my test instantly?
This change exist in many feature files and around 1000 lines in feature file. To get solution for this, I try on setting environment variables but I couldn't reach all the way till end this issue to solve. So can anyone help me on this?
Thanks in advance
What if you do the replacement in your step implementation instead? Then you could have the desired value in a separate file or pass it as arguments. That way you don't need to hard code the values.
Could scenario outlines help you in any way or is the value only changing depending on external changes?
My first thought was scenario outlines like #homaxto said.
Then I thought you might want to affect it by which system you are connected to. You can do this through configuration. I have done this with Fig_Newton.
You can either set an environment varaible or use one in the commandline. Or you can use #hook type tags. With a hook tag, you can have a tag at the top of a feature file that you can use to set a variable that affects how the steps operate (but it needs to be handled inside the step).
I have got id associated with the element, but when tried locating this using findElement(By.id()) it doesn't work.
Also, I had gone through few blogs with the same question as given here, but I saw the resource-id in there was prefixed with packagename and :id. In my case, these aren't associated. Screenshot for the element details is below :
I have used the below code to locate the element by id.
- driver.findElement(By.id("loginHome"));
- driver.findElement(By.id("com.packagename:id/loginHome"));
- driver.findElement(By.id("android:id/loginHome"));
- driver.findElement(By.xpath(//*[#id='loginHome']));
But none of the above code snippets worked. Can someone please help me get through with this. Thanks in Advance.
Not exactly answering your question, but providing an alternative method for you to complete the test.
I follow this link https://github.com/appium/appium-dot-app and it works.
You don't need to code everything. The application provides some easy ways to record your clicks and gestures.
For example, when I click something, it will print out the script automatically.
wd.find_element_by_xpath("//android.view.View[1]/android.widget.FrameLayout[2]/android.widget.LinearLayout[1]/android.widget.RelativeLayout[2]/android.widget.RelativeLayout[1]").click()
And you just need to choose your favorite programming language and save it after testing is done.
One thing that I have to point out is that the swipe function is corrupted. Use the following code to perform swipe gestures
wd.swipe(421, 424, 70, 424, 500)
You can try other options as well. Try this:
//add some wait command before the element
Thread.sleep(2000);
driver.findElementsByXPath("//*[#class='android.widget.Button' and #index='4']");
Try adding explicit sleep for page to load before clicking usind ID.
First try to wait for the particular element
MobileElement expelement=(MobileElement) (new WebDriverWait(driver, 15)).until(ExpectedConditions.presenceOfElementLocated(By.xpath("//android.widget.Button[#index='4']")));
Then try to do the click(or the activity you suppose to do)
driver.findElement(By.xpath("//android.widget.Button[#index='4']")).click();
Maybe this question has been ask already, but could not find any answer for almost 2hours of internet search.
There is a graphical UI designer wich is coming along with the last android SDK.
Looks pretty cool and well done.
Nevertheless I * cannot find how to attach an event to the control through the graphical editor.
Of course I can add it manually into the xml, but in that case, what's the purpose of having such tool without that function ?
I mean all the other SDK I had in other languages always include that function.
I've also not been able to find doc about how to use this tool. Quite sad...
Thanks
If you want to add a click event handler, select the button (widget) in the GUI that you want to listen for, and look for the property onClick. Enter the name of the method you want to call when the user clicks on that widget, like.. onMyButtonClick
Then add the method to your Activity
public void onMyButtonClick(View v) {
// I heard the button click
}
The GUI builder is getting there, and is not yet as easy to use as the one in XCode, but it's not hard when you get used to it.