Find element by partial string using AccessibilityId - java

I am writing automated tests for mobile application in Java using Appium. I talked with developers to create AccessibilityIds for elements and in Android it works as intended with set String but in iOS AccessibilityId contains additional characters. For example, I have TextField Name - in Android AccessibilityId is txtName, but in iOS it is Name txtName.
That is why I think I need to use contains. With XPath I would write
driver.findElement(By.xpath("//*[contains(#name, 'txtName')]"));
But XPath is relatively slow. How can I do that using AccessibilityId? Rough example of what I'm looking for
driver.findElementByAccessibilityId(/*HERE 'CONTAINS' W\ 'txtName'*/);
It is really important for me to use same solution that works on both Android and iOS. I prefer AccessibilityId because code is easier to understand and fast

Any condition to check contain value for accessibility id?
Code snippet:
WebElement getpremiumbtn = new WebDriverWait(driver, 30).until(ExpectedConditions.refreshed(ExpectedConditions
.presenceOfElementLocated(ByAccessibilityId.AccessibilityId("get premium button"))));
Assert.assertTrue(getpremiumbtn != null && getpremiumbtn.isDisplayed(), "Get premium is not displayed");

Related

How to replace MobileBy.IosUIAutomation because it was deprecated in previous versions?

I'm working on an automation project, I need to find an element depending on the text it contains inside an IOS app, but MobileBy.IosUIAutomation no longer works with iOS 10 and higher, how can I replace this piece of code to make it do the same functionality.
`
listItem = element.findElement(MobileBy.IosUIAutomation(
"new UiScrollable(new UiSelector()).scrollIntoView(" + "new UiSelector().text(\"" + itemText + "\"));
`
Does anyone know of a replacement for MobileBy.IosUIAutomation or how it could perform the same functionality?
You can use XCUITest driver now for Automating iOS application.
So instead of iOSUiAutomation locator strategy, you can now use NS predicate string or iOS Class chain locator strategies.
Check out my blog on different locator strategies in Appium where you can get more details about the above mentioned locator strategies.
In your example, if you use NS predicate string, the locator will be,
listItem = element.findElement (MobileBy.iOSNsPredicateString ("label == \"" + itemText + "\"));
Note:
In iOS, you now don't need to do scrollIntoView because with XCUITest driver, it is able to find all the elements on the screen, even those which are not visible on the viewport.

I am coding in Android Studio, and I need to fetch and display a specific line of data from a specific webpage

I am very new to coding in Java/Android Studio. I have everything setup that I have been able to figure out thus far. I have a button, and I need to put code inside of the button click event that will fetch information from a website, convert it to a string and display it. I figured I would have to use the html source code in order to do this, so I have installed Jsoup html parser. All of the help with Jsoup I have found only leads me up to getting the HTML into a "Document". And I am not sure if that is the best way to accomplish what I need. Can anyone tell me what code to use to fetch the html code from the website, and then do a search through the html looking for a specific match, and convert that match to a string. Or can anyone tell me if there is a better way to do this. I only need to grab one piece of information and display it.
Here is the piece of html code that contains the value I want:
writeBidRow('Wheat',-60,false,false,false,0.5,'01/15/2015','02/26/2015','All',' ',' ',60,'even','c=2246&l=3519&d=G15',quotes['KEH15'], 0-0);
I need to grab and display whatever value represents the quotes['KEH15'], in that html code.
Thank you in advance for your help.
Keith
Grabbing raw HTML is an extremely tedious way to access information from the web, bad practice, and difficult to maintain in the case that wherever you are fetching the info from changes their HTML.
I don't know your specific situation and what the data is that you are fetching, but if there is another way for you to fetch that data via an API, use that instead.
Since you say you are pretty new to Android and Java, let me explain something I wish had been explained to me very early on (although I am mostly self taught).
The way people access information across the Internet is traditionally through HTML and JavaScript (which is interpreted by your browser like Chrome or Firefox to look pretty), which are transferred over the internet using the protocol called HTTP. This is a great way for humans to communicate with computers that are far away, and the average person probably doesn't realize that there is more to the internet than this--your browser and the websites you can go to.
Although there are multiple methods, for the purpose of what I think you're looking for, applications communicate over the internet a slightly different way:
When an android application asks a server for some information, rather than returning HTML and JavaScript which is intended for human consumption, the server will (traditionally) return what's called JSON (or sometimes XML, which is very similar). JSON is a very simple way to get information about an object, and put it into a form that is readable easily by both humans (developers) and computers, and can be transmitted over the internet easily. For example, let's say you ask a server for some kind of "Video" object for an app that plays video, it may give you something like this:
{
"name": "Gangnam Style",
"metadata": {
"url": "https://www.youtube.com/watch?v=9bZkp7q19f0",
"views": 2000000000,
"ageRestricted": false,
"likes": 43434
"dislikes":124
},
"comments": [
{
"username": "John",
"comment": "10/10 would watch again"
},
{
"username": "Jane",
"number": "12/10 with rice"
}
]
}
That is very readable by us humans, but also by computers! We know the name is "Gangnam Style", the link of the video, etc.
A super helpful way to interact with JSON in Java and Android is Google's GSON library, which lets you cast a Java object as JSON or parse a JSON object to a Java object.
To get this information in the first place, you have to make a network call to an API, Application Programming Interface. Just a fancy term for communication between a server and a client. One very cool, free, and easy to understand API that I will use for this example is the OMDB API, which just spits back information about movies from IMDB. So how do you talk to the API? Well luckily they've got some nice documentation, which says that to get information on a movie we need to use some parameters in the url, like perhaps
http://www.omdbapi.com/?t=Interstellar
They want a title with the parameter "t". We could put a year, or return type, but this should be good to understand the basics. If you go to that URL in your browser, it spits back lots of information about Interstellar in JSON form. That stuff we were talking about! So how would you get this information from your Android application?
Well, you could use Android's built in HttpUrlConnection classes and research for a few hours on why your calls aren't working. But doesn't essentially every app now use networking? Why reinvent the wheel when virtually every valuable app out there has probably done this work before? Perhaps we can find some code online to do this work for us.
Or even better, a library! In particular, an open source library developed by Square, retrofit. There are multiple libraries like it (go ahead and research that out, it's best to find the best fit for your project), but the idea is they do all the hard work for you like low level network programming. Following their guides, you can reduce a lot of code work into just a few lines. So for our OMDB API example, we can set up our network calls like this:
//OMDB API
public ApiClient{
//an instance of this client object
private static OmdbApiInterface sOmdbApiInterface;
//if the omdbApiInterface object has been instantiated, return it, but if not, build it then return it.
public static OmdbApiInterface getOmdbApiClient() {
if (sOmdbApiInterface == null) {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("http://www.omdbapi.com")
.build();
sOmdbApiInterface = restAdapter.create(OmdbApiInterface.class);
}
return sOmdbApiInterface;
}
public interface OmdbApiInterface {
#GET("/")
void getInfo(#Query("t") String title, Callback<JsonObject> callback);
}
}
After you have researched and understand what's going on up there using their documentation, we can now use this class that we have set up anywhere in your application to call the API:
//you could get a user input string and pass it in as movieName
ApiClient.getOmdbApiClient().getInfo(movieName, new Callback<List<MovieInfo>>() {
//the nice thing here is that RetroFit deals with the JSON for you, so you can just get information right here from the JSON object
#Override
public void success(JsonObject movies, Response response) {
Log.i("TAG","Movie name is " + movies.getString("Title");
}
#Override
public void failure(RetrofitError error) {
Log.e("TAG", error.getMessage());
}
});
Now you've made an API call to get info from across the web! Congratulations! Now do what you want with the data. In this case we used Omdb but you can use anything that has this method of communication. For your purposes, I don't know exactly what data you are trying to get, but if it's possible, try to find a public API or something where you can get it using a method similar to this.
Let me know if you've got any questions.
Cheers!
As #caleb-allen said, if an API is available to you, it's better to use that.
However, I'm assuming that the web page is all you have to work with.
There are many libraries that can be used on Android to get the content of a URL.
Choices range from using the bare-bones HTTPUrlConnection to slightly higher-level HTTPClient to using robust libraries like Retrofit. I personally recommend Retrofit. Whatever you do, make sure that your HTTP access is asynchronous, and not done on the UI thread. Retrofit will handle this for you by default.
For parsing the results, I've had good results in the past using the open-source HTMLCleaner library - see http://htmlcleaner.sourceforge.net
Similar to JSoup, it takes a possibly-badly-formed HTML document and creates a valid XML document from it.
Once you have a valid XML document, you can use HTMLCleaner's implementation of the XML DOM to parse the document to find what you need.
Here, for example, is a method that I use to parse the names of 'projects' from a <table> element on a web page where projects are links within the table:
private List<Project> parseProjects(String html) throws Exception {
List<Project> parsedProjects = new ArrayList<Project>();
HtmlCleaner pageParser = new HtmlCleaner();
TagNode node = pageParser.clean(html);
String xpath = "//table[#class='listtable']".toString();
Object[] tables = node.evaluateXPath(xpath);
TagNode tableNode;
if(tables.length > 1) {
tableNode = (TagNode) tables[0];
} else {
throw new Exception("projects table not found in html");
}
TagNode[] projectLinks = tableNode.getElementsByName("a", true);
for(int i = 0; i < projectLinks.length; i++) {
TagNode link = projectLinks[i];
String projectName = link.getText().toString();
String href = link.getAttributeByName("href");
String projectIdString = href.split("=")[1];
int projectId = Integer.parseInt(projectIdString);
Project project = new Project(projectId, projectName);
parsedProjects.add(project);
}
return parsedProjects;
}
If you have permission to edit the webpage to add hyper link to specified line of that page you can use this way
First add code for head of line that you want to go there in your page
head your text if wanna
Then in your apk app on control click code enter
This.mwebview.loadurl("https:#######.com.html#target")
in left side of # enter your address of webpage and then #target in this example that your id is target.
Excuse me if my english lang. isn't good

Appium sendKeys really slow on android

I'm currently testing an application using Appium on an android device (appium version: 1.2.4.1, java-client: 2.1.0). I'm using the following code to send some text in a textField:
driver.findElement(By.name("Name")).sendKeys("My Name");
and it works fine just it takes it too long to actually send the text on the textbox (usually 7 seconds). I was wondering does anybody know another way to send text on a textField that takes less?
Thanks!
I solved this issue by using adb to send text instead of appium!It is really fast!
try {
textElement.click();
new ProcessBuilder(new String[]{"adb", "-s", "YOURDEVICEUUID", "shell", "input", "text", "YOURTEXTASINPUT"})
.redirectErrorStream(true)
.start();
} catch (IOException e) {
e.printStackTrace();
}
Same way you may use this for Click,clear,install,uninstall etc.. there may be some need to sleep thread for sync issues but it is only 50ms which is too less than 5 seconds which appium takes!
You may use DDMLIB to make this adb call instead of ProcessBuilder!
Try :
driver.findElement(By.name("Name")).Click();
driver.Keyboard.SendKeys("My Name");
This should run faster then your method.
This capabilities helped me to reduce the time of inputs on Android
desiredCapabilities.setCapability("ignoreUnimportantViews", true);
desiredCapabilities.setCapability("disableAndroidWatchers", true);
You can find more here https://appium.io/docs/en/writing-running-appium/caps/#android-only
Experiencing slow automation on Appium is common because Appium is based on a client/server architecture. Network issues can influence the performance of a test (unless you are running your test in the same machine where Appium is installed).
I can tell you that I have also experienced problems with slow tests on Appium. It usually happens on simulators/emulators by the way.
Send keys as part of a UX scenario
If your test needs to send keys as part of a User Experience scenario, then SendKeys is your only option. This method does not simply set a value in a textbox, it actually behaves like a user pressing keys and sending keys to a textbox.
If this is what you need, then you need to understand what is happening a network level because this is what your problem is about. Also consider that this method can be slow on its own sometimes (this is my experience).
Setting a text is not important for the UX scenario being tested
In case the step of setting a textbox's value is not a core part of your automation for the specific test being considered, you an always do achieve this by means of ExecuteScript which lets you execute a Javascript code in your app. I am assuming you are automating the WebView context.
int result = driver.executeScript("
try {
var el = document.getElementById('<your-txtbox-id-here>');
el.value = '<your-text-here>';
return 0;
} catch {
return 1;
}
");
Java does not support multiline strings so the previous is a prettyprint of the following:
int result = driver.executeScript("try{var el = document.getElementById('<your-txtbox-id-here>');el.value = '<your-text-here>';return 0;}catch{return 1;}");
This method will return 0 in case the string was successfully set, otherwise 1. It should be faster because the driver will not send each key separately but execute the script in an anonymous function and get back its return value.
Try to add the following capabilities inorder to have appium keyboard(and not the physical keyboard)
capabilities.setCapability("resetKeyboard", true);
capabilities.setCapability("unicodeKeyboard", true);
Replace sendKeys with the setValue method available in later versions of appium:
driver.findElement(By.name("Name")).setValue("My Name");
It is much faster in my experience.
For new commer, in the Appium version 1.9~, both method executeJavaScript() & setValue() works so good, and you can consider to use it.
// use js
executeJavaScript("$('#" + fieldId + "').val(testData);
// use setValue
$(By.id(fieldId)).setValue(testData);
I improved the speed of my test (written in Python) using:
driver.set_value(myElement, "My Name")
instead of:
webElement.send_keys("My Name")
If you are using Java, it will be something similar to:
driver.setValue(driver.findElement(By.name("Name")), "My Name")
Another approach could be with adb... (This is the fastest one but you have to use another thing besides appium)
//1st - Click at your WebElement
driver.click(driver.findElement(By.name("Name")))
//2nd - Using adb send your text
//adb shell input text "My Name"
adb shell input keyboard text "My Name"

Url working in Google chrome inaccessible by Java w/Jsoup?

I'm having quite a confusing problem. I have literally only been doing networking for a day, so please forgive me and I apologize if I am making a dumb error. My issue is that I cannot access a URL in a programmatic fashion which I can access through copy-pasting into chrome.
I am using a library called jsoup (http://jsoup.org/apidocs/) which parses text out of raw html from a website. My goal in general is to use a base url to which I can attach a string, and get a webpage from it. I am using the code (edit for those who asked for more code, I know this is still sparse but this is the only code preceding the error)
String url = "https://www.google.com/search?q=definition+of+";
url += search; //search is the passed in string
Document doc = Jsoup.connect(url).get(); //url is the String in question
to get the webpage. My ultimate goal is to use this method to get the text of the box at the top of chrome searches when you search for the definition of a word. I.e the box at the top here: https://www.google.com/search?q=definition+of+apple
However, I come to an issue when I attempt to use the above link as my url, for I get a org.jsoup.HttpStatusException, so I think it is a networking problem. What causes this url to work when typed into chrome, but not in Java? (I would also not be adverse to different ways to get the information in that box, since my current method feels a bit roundabout)
The full error message (edited in)
Exception in thread "main" org.jsoup.HttpStatusException: HTTP error fetching URL. Status=403, URL=https://www.google.com/search?q=definition+of+apple
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:435)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:410)
at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:164)
at org.jsoup.helper.HttpConnection.get(HttpConnection.java:153)
at test.Test.parseDef(Test.java:68)
at test.Test.main(Test.java:112)
To whomever answers, thank you for spending your time to help a networking newbie!
Most likely, Google is accurately identifying your program as a "robot" and acting accordingly. Google encourages robots to use the Google Custom Search API and discourages them from using the human-oriented search interface.
In fact, all web spiders are supposed to check robots.txt, right? Here is Google's: http://www.google.com/robots.txt. Note that /search is disallowed.
Please see this question for further information. It's basically the python version of your question. Why does Google Search return HTTP Error 403?
If you use Jsoup you have to replace spaces with %20 and not with +.
Try this url :
https://www.google.com/search?q=definition%20of%20apple
String url = "https://www.google.com/search?q=definition%20of%20";
url += search; //search is the passed in string
Document doc = Jsoup.connect(url).get();
public static void main(String[] args) {
Document doc = Jsoup.connect(link)
.data("query", "Java")
.userAgent("Mozilla")
.cookie("auth", "token")
.timeout(1000)
.post();
}

Same Jsoup code behaving differently on Android and desktop

I've got 5-line, simple Jsoup code parsing some strings, it smoothly runs and returns an array list with values that i want, however on android emulator and phone, it just returns nothing without even giving an error.
Thats the whole code :
Document doc = Jsoup.connect(myURL).get();
Elements els = doc.select("div font a");
for (int i = 3; i < els.size(); i++) {
latestNews.add(els.get(i).text());
}
On desktop, it adds elements into array list, however on device, nothing occurs. Could anyone help about it ?
Are you sure you are receiving the same HTML from the site? you should debug and check your doc variable to make sure it contains the same HTML as you'd expect on the site. Possible case of grabbing the mobile site when you are parsing the full site? (not sure if Jsoup prevents getting the mobile site or not). You likely need to set the user agent so that you receive the full desktop variant of the website.
ex.
Document doc = Jsoup.connect(myURL).userAgent("Mozilla").get();

Categories

Resources