How to use Ios UI Automation xpath in appium for ios - appium

I am using iosuiautomator for finding the xpath of element
(Note: In appium can't find the xpath). while running following error is displaying

When using iOSUIAutomation search strategy, you don't need localTarget().target.().etc. You can start from right after mainWindow(). I also noticed you put the tap action inside the quotes but is actually a function of the mobile element (and has 2 parameters) so what you'd want is:
driver.findElementByIosUIAutomation(".tableViews()[2].cells()[2]").tap(1, 250)

Related

Capybara, Selenium, Jupyter Notebook: filling code cell

I want to use Capybara to input text into a Jupyter Notebook cell. Clicking the element and using 'send_keys' does not work, although the cursor ends up in the right location: find(".input").click.send_keys("hello")
Is there a way to simulate pressing keys without selecting an element? find("body").send_keys("hello") also does not produce any text
Edit: I found out that the Jupyter Notebook uses CodeMirror. CodeMirror uses a hidden <textarea> field somehow, so that would explain why Selenium refused to find the input.
My current workaround is to find the first CodeMirror editor and use the setValue function on it: execute_script("var editor = $('.CodeMirror')[0].CodeMirror; editor.setValue('this is the input')")
I avoided the workaround by using Selenium's action builder. Find the desired element and get its native selenium representation:
el_native = first('.input').native
Then, use the action builder to click into the element and send keys:
page.driver.browser.action.click(el_native).send_keys("hello").perform

How can i remake XPath locators to UIAutomation locators?

How can i remake XPath locators to UIAutomation locators?
Example this xpath locator:
//UIAApplication[1]/UIAWindow[4]/UIAAlert[1]/UIAScrollView[1]/UIAStaticText[2]
Any ideas?
There are different ways to remake xpath value to UIautomation, methods are as follows.
[!Calculator app example]
http://i.stack.imgur.com/WQr3J.png
Before going to these points FYI class name is taken as reference for xpath.
XPath using class and text attribute :
In above image you can see that button 5 has text attribute with value = 5 which is unique. Class name is android.widget.Button which is same for all number buttons. So we can create XPath using text attribute value with class name as bellow.
xpath("//android.widget.Button[#text='5']")
XPath using class and resource-id :
Here resource-id for button 5 is com.android.calculator2:id/digit5. Trailing part (e.g digit5, digit4, digit7) of resource-id is changing for every number buttons so we can use contains function to get relative XPath of button 5 as bellow.
xpath("//android.widget.Button[contains(#resource-id,'digit5')]")
See more at: http://software-testing-tutorials-automation.blogspot.in/2015/10/ui-automator-viewer-get-android-app.html#sthash.08v6jFPe.dpuf
You can get UIAutomator from Instrument.(Xcode - Automation tool)
please find the below UIAutomator for ur code,
UIATarget.localTarget().frontMostApp().windows()[3].alerts()[0].scrollViews()[0].staticTexts()[1]
Note:
In Xpath index starts from 1.but in UIAutomator it starts from 0. Keep this in your mind.

Can't touch second element in array

I'm trying to touch a UITextField using Calabash. When I use query("UITextField")[x], where x is the number in the array of text fields that are on screen, I can correctly query for just one text field. However, when I use touch("UITextField")[x] it will always touch the first text field. This happens when using the console and when using cucumber to run the tests.
Here's relevant info about my setup:
xcode-select --print-path
/Applications/Xcode.app/Contents/Developer
xcodebuild -version
Xcode 7.2
Build version 7C68
calabash-ios version
0.16.4
Try
touch("UITextField index:x")
where x == your index.
Also, please update to calabash 0.17.0 :)
Explanation
The Calabash environment is composed of a client and a server. The server runs on the device/simulator as part of the app and receives commands/queries from the client. In this case, the client is the ruby interface through which you are interacting with the app.
The client is responsible for sending enough info to the server to select objects on which to perform the gestures. Once the gestures / queries have been performed, results are sent back to the client as json / hashes, which is what you see in the console. The distinction is important: the server performs the queries, the client does not.
By the time you are seeing the results of a query / gesture in the irb console, it has already been performed: the json that is returned simply represents the state of the views, not the actual views themselves.
So when you are running
touch("UITextField")[index]
This is actually equivalent to
touch_results = touch("UITextField")
touch_results[index]
In the first line, touch_results is receiving the json representation of the elements affected by performing touch on the results of querying for "UITextField", meaning that the touch event has already completed by the time you try to access the results with touch_results[index].
Another way to think about it is this: Given res = touch(query), the query is the part used to specify the actual views, and res is just json that represents the state of those views / results of a query or gesture.
In conclusion
When you need more specificity on a query, the specifiers need to go inside the query. E.g.,
touch("all UIScrollView UITextField marked:'some text' index:2")
(this will search for all UIScrollViews , find any UITextFields inside of them which contain text matching 'some text', and return the 3rd of such results).
For a full explanation of query language syntax, see the docs.

Understanding basics of iOS uiautomation selector strategy for Appium

I am writing UI automation tests for an iOS native app using Appium and gradually realizing how most of the element locating strategies don't reliably work for iOS. Apart from XPath which randomly works, other options that I have are:
Accessibility ID (did not work for me)
name (not every element will have value for 'name' attribute)
class (makes sense when you are working with a list of elements)
iOS UiAutomation predicates (steep learning curve for beginners)
I have been trying to understand how to use iOS UiAutomation locator strategy and find elements using it but it's not working on Appium Inspector. I have referred to these documentations (Appium iOS Predicate reference, Apple UIAutomation reference) but I feel they cater to an advanced Appium user audience who have some knowledge on iOS development, not for beginners.
Currently the element hierarchy that I am trying to find element in is something like this:
My current automation setup is:
XCode 6.3.2
Appium 1.4.8
iOS 8.3
Appium Java Client 3.1.0
What will be the locator I can use to locate the highlighted element using UiAutomation predicate strategy? I have been trying a few options on the Appium Inspector like:
applications()[0].windows()[0].navigationBars()[0].textFields().withPredicate("value == 'Search eBay'")
.textFields().withPredicate("value == 'Search eBay'")
These did not work. What am I doing wrong here? Are there any other documentations which clearly explain iOS UiAutomation locators from ground-up? It will really help if someone can explain these basics.
I have never worked with Appium before but I have worked with UIAutomation in javascript.
You can probably find the element using:
....textFields().firstWithName("Search eBay")
Note that UIAuatomation uses UIAccessibility protocol. The value for UITextField is its accessibilityValue and that one will be equal to the searched text, not the placeholder. Once you type something to the field, you will be able to use value.
Of course, in your case grabbing the first text field would work too, as there is only one in the navigation bar.
Just use this .navigationsBars()["EBUH_whateverstring"].textfields()["Search eBay"].textfields()["Search eBay"].
Better way is to ask dev to add accessibility id in case the code is in Obj-C or accessibility identifier if the app code is in Swift. Otherwise if the passed on element value is dynamic then the test will fail in asserting or doing action upon this element.
Another failsafe method is using array values.
.navigationsBars()[0].textfields()[0].textfields()[0] --> Check the array values of your element is [0] or any other. U can use this appium app to get the array value from where it shows xpath value for the element. Or you can use XCode Instruments if you have access to the code to find the exact value as UIAutomation interprets it.
If you are trying to find elements in Appium you will have to write code to do so. Assuming you are using Java, which is what I am using for code, the way you locate these elements is through the driver, tables, and rows.
What do I mean by this? Each element has an XPath associated with it, so one way of doing this is saying
driver.findElementByXPath("xpath_string_here");
This can be very useful when trying to run assertions, for example. using the above code, let us say we want to assert that its name is valid. we can say:
AssertEquals(driver.findElementByXPath("xpath_string_here").getAttribute("name"), 'Practice Example");
When I mention tables and rows, I mean doing something like this:
MobileElement table = (MobileElement) driver.findElementByXPath("string here");
List<WebElement> rows = driver.findElementByClassName("Class name here");
What does this code do? it creates a variable of type MobileElement which will go through the xPath you want, and then the rows value will find elements of that class name present inside of that table view. So in the above image, I would stop at the XPath for the UIAWindow, and then tell my rows to find the elements using class name of "UIAButton" for example.
At this point it is a matter of a simple loop if you want to run some actions on them such as .click(); using their indexes using the .get(int i) method. So for example: rows.get(i).click();
Does this help you with your question?

Rails3 Google Maps testing with selenium

I'm trying to test a google maps app with Rails3. I'm using cucumber with capybara and selenium for JavaScript testing.
I have a map where I wait for google maps to be loaded, and then send an ajax request to my server, where I get locations that I'm inserting into the map.
I'm wondering if it's possible with selenium to wait until google maps is loaded, the ajax call to my server is finished and the marker are placed inside the map. The other issue is, how to select this marker within google maps. Are there any selectors?
Or should I go the other way, and use a JS testing framework like Jasmine to test if my classes are loaded and so on. I don't have any experience with Jasmine, so is it possible to test a google maps?
Maybe someone knows a solution, or a hint if it's not possible, or a workaround or... ;)
[UPDATE 1]
I've found out how to select markers in google maps. If you look at googles selenium tests you can check out what they are doing. For example selecting a marker:
waitForElementPresent xpath=//img[contains(#src,'marker')]
But here comes the next problem. How do I select a specific marker? Is there a way inside the javascript google maps API to assign an ID to it, so that I can use #marker_1, #marker_2...?
And another strange thing is, that function like wait_for_element or wait_for_condition aren't available inside my cucumber step definitions. Are the google selenium tests using own function like that waitForElementPresent? Or are this standard selenium functions? I've found a lots of posts, where they always use something like
selenium.wait_for_condition
selenium.wait_for_element
or
#selenium.wait_for_condition
...
Inside my step definitions the selenium and the #selenium var a nil. How can I access this methods? I've also found this post, but it is from Oct. '08, so I think there must be a better solution (btw. this solution works on the first sight).
Like on this page, they give an overview of a few selenium methods how to wait for a condition or element. Is this still present? How can I use this functions?
[UPDATE 2]
Damn it, I've found out, that the selenium tests I mentioned above are for V2 of google maps, not for V3. I have tried it with
wait_until { page.has_xpath?("//img[contains(#src,'marker')]") }
But it doesn't work. The marker is visible on the map, but I get a timeout error, because with this XPath selector it is not found. I'm wondering if it is generally possible to select a marker out of the DOM.
I also tried to assign an additional attribute to the marker when I create it:
// marker is the marker returned by google maps after adding it to the map
$(marker).attr('id', "marker_1");
But when I try to access it with the jQuery selector $("#marker_1"), it doesn't find it. So, still no solution, yet.
What I do with mine is to execute the calls in your step definitions like so:
page.execute_script("launchmap()")
then check for their existence in the page..then do your normal ajax check in capybara. the marker will be contained in a div right? then if you call launchmap and create the markers, capybara SHOULD be able find your markers
UPDATE
found out about this plugin: http://vigetlabs.github.com/jmapping/examples/
it gives you semantic markup for your google maps(for graceful degradation) allowing you to actually check if a marker exists using capybara. hope it helps(dont have time to test it but it looks promising)
I found a way to Integration test my Google map with RSpec and Capybara. I wanted to write a test to assert that the content I got from an internal JSON-feed ended up in form of markers and info windows on my map (Google Maps API V3) in a Rails 4 app.
The problem:
Even when I ran the tests with Selenium Webdriver that supports JS, I didn't find a way to select the markers with Capybara to check for their content.
My solution:
1. I added a div with ID test-box to my HTML markup
2. I wrote three helper methods into my JS that had access to my maps markers and added the results to the test-box.
3. In Capybara I executed the helper methods and expected to find the expected content or values in the box.
The code:
HTML:
<div id="map-canvas"></div>
<div id="info-box"></div>
JS-helpers:
in app/assets/javascripts/events.js
// Test helper methods
testInfo = function(){
document.getElementById("info-box").innerHTML = markers[0].title;
};
testInfoCount = function(){
document.getElementById("info-box").innerHTML = markers.length;
};
testInfoWindow = function(){
document.getElementById("info-box").innerHTML = markers[0].title + ", " + markers[0].time;
};
"markers" in my code is an array I push in every marker after I have added it to the map. I can be sure that the content actually is on the map if it's in the markers array.
Test:
spec/features/map_feature_spec.rb:
require "rails_helper"
describe "Map", js: true do
let!(:john){create(:user)}
let!(:event1){create(:event, user: john)}
let!(:event2){create(:event)}
it "shows a marker for a geocoded event on front page" do
visit '/'
find('#main-map-canvas')
page.execute_script('testInfo()')
expect(page.find("div#info-box").text).to eq(event1.title)
end
it "shows a marker for each geocoded event on front page" do
visit '/'
find('#main-map-canvas')
page.execute_script('testInfoCount()')
expect(page.find("div#info-box").text).to eq("2")
end
it "shows a marker for an event on event's page" do
visit "/events/#{event1.id}"
expect(page).to have_css("#single-map-canvas")
page.execute_script('testInfo()')
expect(page.find("div#info-box").text).to eq(event1.title)
end
context "Tooltips" do
let!(:event1){create(:event)}
let!(:event2){create(:event)}
it "shows title and date on frontpage" do
visit "/"
find('#main-map-canvas')
page.execute_script('testInfoWindow()')
expect(page.find("div#info-box")).to have_content("Pauls Birthday Party, #{event1.nice_date}")
end
end
end
To run the javascripts Selenium webdriver and Firefox need to be installed (''gem "selenium-webdriver"'' in your Gemfile)
I'm creating the test content (let!...) using Factory Girl.
Running the tests you will actually see the markers on the map and their content appears in the test-box.
To your first question - use waitForCondition with a script that tests for the presense of the markers.
waitForCondition ( script,timeout ) Runs the specified JavaScript snippet repeatedly until it evaluates to "true". The snippet may have multiple lines, but only the result of the last line will be considered. Note that, by default, the snippet will be run in the runner's test window, not in the window of your application. To get the window of your application, you can use the JavaScript snippet selenium.browserbot.getCurrentWindow(), and then run your JavaScript in there
Arguments:
script - the JavaScript snippet to run timeout - a timeout in milliseconds, after which this command will return with an error
Be sure to enable the url capybara is using to run the test server into google console for your app.
You can check this URL (and the error message while loading google maps) by setting config.debug= true within Capybara driver config loading block.

Resources