grey_accessibilityLabel("Login") doesn't match element that exists in UI hierarchy with the same accessibility label - xctest

I am using this code to click on the login button:
[[EarlGrey selectElementWithMatcher:grey_accessibilityLabel("Login")] performAction:grey_tap()];
However, it fails with the following error:
No elements found
The relevant element in the UI hierarchy dumped on failure looks like:
<UIButton:0x7fcb01d963d0; AX=N; AX.label='Login'; AX.frame={{16, 64}, {124, 64}}; AX.activationPoint={78, 96}; AX.traits='UIAccessibilityTraitLink'; AX.focused='N'>
What's the right way of clicking on the login button?

I added AX=N matching to the EarlGrey FAQ.
How do I match elements that are denoted with "AX=N" in the view hierarchy?
EarlGrey's view hierarchy identifies non-accessible elements with
AX=N. Accessibility IDs can be added to both accessible and
non-accessible elements. When searching for AX=N elements, the
following accessibility matchers won't work:
grey_accessibilityLabel
grey_accessibilityValue
grey_accessibilityTrait
grey_accessibilityHint
If the AX=N element can't be matched by grey_accessibilityID, then
you'll have to use non-accessibility matchers to locate the element.
I'd fix the button so that it's accessible, then the label matcher will work.

Related

Click on first element contained in a div

I have a div that contains a set of dynamic elements. I want to click on the first search result.
I want to click on the first element contains in
I tried using creating a custom xPath like so but it didn't work. Any ideas here?
//div[1][contains(text(), 'listing')]
First of all It would've helped if you had provided more information.
best will be using pseudo-child like div.firstChild or if the elements are generated dynamically you can add a class and use document.querySelectorAll(".class") which will give you an array of elements that had the class.
You can use array[0] to use click on the first element.
For anyone coming across this thread here is the solution
const listings = await page.$x('//*[contains(#id,"listing_")]')

How to write cypress locator for this dynamic button specific to the span element "Agile Fundamentals"

I am new to cypress automation. I tried to use the following locator to click on the specific dynamic button.
cy.contains('span', 'Agile Fundamentals').next().find('button').click()
but it did not work.
.next() won't work in this case because the next element would be the text label with the date.
Instead, we can to use .parent() and .siblings() to move over to the other div and grab that button.
cy.contains('span', 'Agile Fundamentals')
.parent() // moves us to the div around the span
.siblings('div') // moves us to the sibling div
// could use `.next()` above instead
.find('button') // moves us to the button
// If you want to save this for ease of use, you can assign it an alias
.as('dynamicButton')
// and reference it like...
cy.get('#dynamicButton')...
There is another way, change the target of .contains() to the card itself (the top level of that group of elements).
Starting from that element, .find() will get the button regardless of the nesting structure within the card.
cy.contains('div.MuiCardHeader-root', 'Agile Fundamentals')
.find('button')
.click()
Another approach to finding the button would be using the aria-label of the button. This will ONLY work if your DOM does not have another element with the same aria-label value.
cy.get('[aria-label=settings]')
.click()
If you there are other elements in the DOM that have matching attribute, then you can limit your search to the specific card
cy.contains('.your-card-selector', /agile fundamentals/i)
.find('[aria-label=settings]')
.click()

locate displayed element with webdriverio

When developing in the Ionic framework, the generated html sometimes will contain duplicate DOM elements, where all but one tree of elements is hidden with a class="ion-page-hidden" at the top level.
When using webdriverio to try and locate an element inside this tree, it find duplicated elements. Since the ion-page-hidden class is at the top of the tree, and not on the element itself, how can we use Xpath to locate only the displayed element.
I couldn't figure out any way to modify the XPath selector with a second condition since the elements are exactly the same!
So instead I have tried to use the webdriverio isDisplayed() function:
get openHamburgerMenu() { return Utils.visibleElement($$("//ion-button[#name='button-open-menu']")); }
where the Utils function is:
async visibleElement(elementArray) {
let returnElement;
elementArray.forEach(element => {
if (element.isDisplayed()) {
returnElement = element;
}
});
return returnElement;
}
but no elements are passed into the function. In the chrome browser, I can see two that match the xpath //ion-button[#name='button-open-menu']. I need the one not in the ion-page-hidden block!
tree
The tree looks like this:
app-for-homes[1]/ion-header/ion-toolbar/ion-buttons[1]/ion-button
app-for-homes[2]/ion-header/ion-toolbar/ion-buttons[1]/ion-button
where app-for-homes[2] happens to have the ion-page-hidden class.
I think it should be possible to use ancestors to identify which of the two elements, matching the xpath, does not have a 4th level ancestor with that class? But I'm way out of my depth on day one of working with xpaths...
Quick and Dirty
The desired outcome can be achieved using this Xpath:
//app-for-homes[1]/ion-header/ion-toolbar/ion-buttons/ion-button[#name='button-open-menu']
However, this only works where the order in which the elements appears is known.
Better Answer
When you have exactly 1 element that is not hidden, Xpaths allow you to look at an elements ancestors as far back as you want to identify the presence / or absence of the hidden class. In this case, we start by finding the ancestor app-for-homes which does not include the ion-page-hidden class:
//app-for-homes[not(contains(#class,'ion-page-hidden'))]
and then simply append the remainder of the path to the desired element. Full answer =
//app-for-homes[not(contains(#class,'ion-page-hidden'))]/ion-header/ion-toolbar/ion-buttons/ion-button[#name='button-open-menu']

selenium python how to find and click element that change everytime

im trying to find an element with dinamic values , for example <span class="ms-Button-label label-175" id="id__177">Save</span> in inspect element, the id and class values tend to change for every refresh, how can i in this case find the element in selenium? i tried troguht xpath but seems doesnt work because can not find the path, i was thinking to find "Save" world torught always find by xpath but actually i dont know if im doing well : driver.find_element_by_xpath(//span(#.... but then? how can insert element if it changes everytime? thanks!
Something like this may work:
driver.find_element_by_xpath('//span[text()="Save"]')
But this will fail, if there is more than one button with text "Save" on the page.
In that case you may try to find some specific outer element (div, form, etc.) which does not change and contains the button. Then find the button inside of it.
With few requests with driver:
specific_div = driver.find_element_by_id("my_specific_div")
button = specific_div.find_element_by_tag_name("span") # e.g. there is only one span in that div
Or with more specific xpath:
button = driver.find_element_by_xpath('//div[#class="some-specific-class"]/span[text()="Save"]')
If needed, search for more nested elements before the button, so you can get more narrow search field.
More examples in the docs.

How can I focus to a specific item which is in the bottom of the page in IDE

I am trying to select a specific item in a page which is at the bottom of the page. I want to verify that element is present and the same time I want to focus to that specific item.
How can I do this in the Selenium IDE?
I tried storeEval, but its specific co-ordinated which I don't want. I am looking for some dynamic command. I tried using css:.groupTile:contains("Concentrated") but the focus is not going to that particular item (Concentrated).
Can someone help me with Command, Target and value please?
CSS Selectors have many formats
i) Using id. Put this in Target: css=tag#id
tag = the HTML tag of the element being accessed,
id = the ID of the element being accessed
ii) Using class. Put this in Target: css=tag.class
tag = the HTML tag of the element being accessed,
class = the class of the element being accessed
In value you enter name of the item.