How to write xpath if element has no unique 'accessibility id' in Appium IOS Xcuit Test - appium-ios

How to handle elements which does not have unique accessibility id's
Please find the below link for screenshot

First, you should avoid using XPath with Appium on iOS: it's not natively supported by XCUTest and because of it, significantly affects performance of elements search.
Second, it would be nice to set accessibility label even it will be a group of elements with the same one:
Here is a Java sample how you can search and select one of the elements with same id:
List<WebElement> elsWithSameId = driver.findElements(MobileBy.AccessibilityId("your id"));
WebElement specificElement = elsWithSameId.stream()
.filter(element -> element.getText() == "My Favorite element")
.findFirst()
.get();
specificElement.click();
If you still want to use XPath, just try to find more/less unique class for the elements you want to interact with, then build iOS predicates (similar mechanism to XPath, but its native to XCUITest)

Related

How to uniquely identify elements with selenium for below Expedia site example

Lets say I go to - https://www.expedia.co.uk/
I go to Trains Tab and do a search for any date with 1 passenger selected.
You'll be on next page where to select trains from a list, now if I want to click on any ShowFares button its not being recognized uniquely by CSS= .btn-secondary.btn-action (its returning more than one matching node. So couldn't use it.
while using xpath -
.//*[#id='ember968']/div/div[1]/div[2]/div[2]/div/button
I see its recording #id with some emberxxx which again is not unique as its getting changed for every other search list..
Similarly when I clicked on ShowFare then unable to pick a train or fare as same above problem occurring as CSS is returning several nodes and xpath has this emberxxx which is not unique.
As with the same attributes, we have more than one element we are not able to pick right one. I tried with jquery selector .btn-secondary.btn-action:eq(1) and it is working. By using above selector you will pick first Show Fares button every time Let me know if you have any queries.
CSS Selector: .flex-1up.flex-listing.flex-theme-light li:nth-child(1) button
Use, for example, xpath-function starts-with:
(//*[starts-with(#id, 'ember')])[2]
This function find part of name. And then you can use filtr by [] to find needed element by index.
I see there are lot other elements having same xpath. Here is my suggestion if you want to click on first element.
//button[#class='btn-secondary btn-action']/span - push that to list, loop through list and use getText(). If matches 'Show Fares', click on that.
List<WebElement> buttonList = driver.findElements(By.xpath("//button[#class='btn-secondary btn-action']/span"));
for(int i=0; i<=buttonList.size() ; i++){
WebElement ele = buttonList.get(i);
if(ele.getText().contains("Show Fares"){
ele.click();
}
}

CSS selector to choose second item after a hyphen

The CSS selector [attr|=value] is designed to select items which are exactly "value" or which begin with "value-". This was originally intended to allow selection of all languages regardless of dialect, such as "en-au", "en-ca", "en-gb", "en-us".
What I'm looking for is a selector for an item which is exactly "value", which includes "-value-" or which ends with "-value". In my case, I am not concerned with language codes at all.
This page claims that there is a =\operator:
[data-value=|"foo"] {
/* Attribute value has this in a dash-separated list somewhere */
}
However I have been unable to get this to work. If I'm just interested in a controlled list of 2-item terms, then this will work for me:
[attr*=-value][attr$=value]
However, this would also return items like "xx-valuevalue", so the result is not perfect.
My question is: is there another way to write a CSS selector that will select all items that have a given string as one item in a hyphen-delimited list?
Here you go:
[attr*=-value-], [attr$=-value], [attr=value]
In pseudo code:
Get those containing -value-, those ending with -value, and those exactly equal to value.

:eq pseudo selector not working with Selenium WebDriver / Chrome

I'm trying to get the first two divs of a given class from a web site using css selectors in selenium. I'll use SO to demonstrate the problem. If I try the selector in the console chrome dev tools it works:
$('div.question-summary:eq(0)')
[<div class=​"question-summary narrow tagged-interesting" id=​"question-summary-27442616">​…​</div>​]
$('div.question-summary:eq(1)')
[<div class=​"question-summary narrow tagged-interesting" id=​"question-summary-27442177">​…​</div>​]
But if I do the following with selenlium webdriver I get an error:
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
driver.navigate.to('http://www.stackoverflow.com')
first_element = driver.find_element(:css, 'div.mainnav:eq(0)')
Selenium::WebDriver::Error::InvalidSelectorError: invalid selector: An invalid or illegal selector was specified
Is there another way to express this selector? Or a way to get selenium to respond to it?
Selenium uses the browser's native CSS selector engine. As a result, the find_element method will consider jQuery selectors, in this case the :eq(0), as being invalid.
If you want to use jQuery selectors, you will need to manually execute that script using the execute_script method. Note that when using this approach an array of Selenium::WebDriver::Element will be returned, which is why the .first is used (to get the first element of the Array).
first_element = driver.execute_script('return $("div.question-summary:eq(0)");').first
That said, if the only jQuery selector you are trying to use is :eq, you could get by with standard CSS selectors. The :eq selector returns a specific element within the matching set. You could do the same by using the find_elements and [] methods:
first_element = driver.find_elements(:css, 'div.question-summary')[0]
second_element = driver.find_elements(:css, 'div.question-summary')[1]
You can get a similar result with :nth-child:
first_element = driver.find_element(:css, 'div.question-summary:nth-child(0)')
Just be aware of the difference between :eq and :nth-child

using the chrome console to select out data

I'm looking to pull out all of the companies from this page (https://angel.co/finder#AL_claimed=true&AL_LocationTag=1849&render_tags=1) in plain text. I saw someone use the Chrome Developer Tools console to do this and was wondering if anyone could point me in the right direction?
TLDR; How do I use Chrome console to select and pull out some data from a URL?
Note: since jQuery is available on this page, I'll just go ahead and use it.
First of all, we need to select elements that we want, e.g. names of the companies. These are being kept on the list with ID startups_content, inside elements with class items in a field with class name. Therefore, selector for these can look like this:
$('#startups_content .items .name a')
As a result, we will get bunch of HTMLElements. Since we want a plain text we need to extract it from these HTMLElements by doing:
.map(function(idx, item){ return $(item).text(); }).toArray()
Which gives us an array of company names. However, lets make a single plain text list out of it:
.join('\n')
Connecting all the steps above we get:
$('#startups_content .items .name a').map(function(idx, item){ return $(item).text(); }).toArray().join('\n');
which should be executed in the DevTools console.
If you need some other data, e.g. company URLs, just follow the same steps as described above doing appropriate changes.

Alternative of contains in cssSelector ? Selenium WebDriver

I am using selenium 2 (WebDriver).
I am locating a button and clicking by the script:
driver.findElement(By.cssSelector("button:contains('Run Query')"));
or
driver.findElement(By.cssSelector("css=.gwt-Button:contains('Run Query')"))
whose html is like :
<button type="button" class="gwt-Button" id="ext-gen362">Run Query</
button>
As the id is dynamically generated, I can't make use of the ID.
Is there any way to use cssSelector with something like contains ? Is this possible?
You can't do this with CSS selectors, because there is no such thing as :contains() in CSS. It was a proposal that was abandoned years ago.
If you want to select by the element text, you'll have use an XPath selector. Something like
driver.findelement(By.xpath("//button[contains(., 'Run Query']"))
or
driver.findelement(By.xpath("//[contains(concat(' ', #class, ' '), ' .gwt-Button ') and contains(., 'Run Query']"))
Another option is using jQuery, if it's present on the page, something like:
var webElement = ((JavascriptExecutor)driver).executeScript("return jQuery('button:contains(Run Query)')");
CSS alone will not get you what you need; you cannot filter by the text. You could either use js to get the id of the element, or loop through all the buttons in your code until you find the one with the right text. If this were in python:
[btn for btn in browser.find_elements_by_css_selector('button')
if 'Run Query' in btn.text]
You could easily generalize this and make a helper function, too.
I'm in the same boat, currently using XPath selectors with "contains" to find elements with specific text content. Some are <td> and some are <td><a> deep within large tables (specific columns, but row unknown in advance). It's very slow (4 to 5 seconds just to find such a table entry with Firefox 20), so I was hoping to use CSS to be faster. Often the text will be by itself (complete) and other times it will be a filename at the end of a path I'd like to ignore. Does anyone have suggestions for the fastest XPath search pattern, given that it's a known column but unknown row, and may be a <td> or <td><a> (sometimes in the same table). Would an equality comparison be much faster than contains(), for the majority of cases where the text I'm looking for is complete (not at the end of other text)? I think there's a "starts with" lookup, but is there an "ends with" lookup? I know that using an "id" would be even faster, but unfortunately this HTML doesn't have any IDs here, and they can't be added. I'm looking to find the <tr> containing this text so I can locate another element in the same row and get its text or click on a link. It doesn't hurt to locate a small subset of the rows and check their text, but I'd like to avoid doing separate searches for <td> and <td><a> if that's possible.
You cannot use contains but use a wild card instead.
driver.findElement(By.cssSelector("button:(*'Run Query'*)"));
driver.findElement("#ext-gen362").Where(webElement => webElement.Text.Contains("Run Query"))

Resources