Robot Framework - Locating input element with accept attribute fails - selenium

I am writing an automation script for an avatar upload module with the following CSS locator:
input[accept="image/png,image/jpeg,image/gif,image/bmp"]
I am using Robot Framework's Wait Until Element Is Visible keyword to look for the locator above but is unsuccessful with the error:
Element 'css=input[accept="image/png,image/jpeg,image/gif,image/bmp"]' not visible after 30 seconds.
Increasing the timeout also doesn't work. Using the same in Chrome Dev Tools would successfully find the element. My guess is that the commas/slashes are messing with Robot's locator parsing. My question is: What is the correct way to write the locator?

Though present in the DOM, an element may not be visible/rendered. This is very often the case with file upload input elements - the UI renders something different, a button, div that had applied styling and fits in better with the overall design.
Thus a check is it visible will rightfully fail. Change your pre-usage approach to validate the input is in the HTML - this is actually the same as what you did in the browser's dev tools - with the Page Should Contain Element keyword, and proceed on success.

There is no problem with the CSS locator your are using. Maybe the element is in another iframe?

Related

Getting "Nosuch element Exception" in Selenium Though XPATH is correct. Not sure is this due to Shadow DOM. Please confirm

I am trying to automate Salesforce application Using Selenium and getting NoSuchelementException though XPATH is correct and valid for particular object. When i have searched the issue, it might be reason for Shadow DOM.
For EX:
So XAPTH i have written like,
driver.findElement(By.xpath("//input[#name='Name']")).sendKeys("Jams");
or
driver.findElement(By.xpath("//input[#id='input-299']")).sendKeys("Jams");
This XPATH is highlighting in Console as well. But while automating it throws nosuchelement error.
So while checking for ShadowDOM option, am getting option like this for Name Object.
#shadow-root(user-agent)
Shadowroot DIV
-- nothing mentioned in div. it just open and closed tags.
How to automate this?
You can check if there are any iframes in your Dom. Simply do //iframe in your page developer mode(F12)> elements tab > search (Ctrf+F) area. If there are any, you will get the number of iframes.
Now if your textbox is in any of iframe use below code to go inside particular iframe first
driver.switch_to.frame("<name or Id of frame>")
then come out to frame use below:
driver.switch_to.parent_frame()
Also, if the issue is not related to frames check below for shadow-root related issue:
you can check below for shadow-root element ( Question is for Java, but you can co-relate):
How to interact with the elements within #shadow-root (open) while Clearing Browsing Data of Chrome Browser using cssSelector
The website contents are mostly created now using javascript. You may have to wait for certain elements to load before doing anything to it.
https://seleniumbyexamples.github.io/wait

Finding xpath of shadow dom elements with robot framework

I'm writing automated UI tests using Robot Framework with python. I'm testing a Polymer application that uses the shadow dom Robot's standard libraries don't seem to be able to locate elements in the shadow dom using xpath.
I've been sorting through selenium's repo/overflow/internets and polymer's repo/overflow/internets and haven't found the intersection of a solution for using robot with python (the selenium workaround isn't that graceful either). I was hoping someone had run into this issue with this specific framework that might be willing to share a solution (or note that there's not one).
Test Case
Wait Until Page Contains Element xpath=(//html/body/some-root-shadow-dom-element/input)
This of course results in an error because the shadow dom is not put into the main document of the DOM tree.
Open the browser console and type this into the console:
dom:document.querySelector("apply-widget").shadowRoot.querySelectorAll("div)
Make sure to hit enter after so it will be ran.

Robot Framework- Loading Spinner selector

I have this problem where I have to validate if a loading spinner is present, it's present for about 1 second on the page, i have found the xpath selector of the loading spinner but selenium library could not find it is there another way to find out a selector of something that dissapears after a short while? Note: The xpath is definitely correct. There is no id on the loading spinner either.
This is the code i have tried
Validate Loading Spinner
Wait until page contains xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/svg
I have also tried Element should contain and Page should contain but that does not find the locator.
You should be using one of the keywords that is validating an element is present - Wait Until Element Is Visible, or Wait Until Page Contains Element - both of which support a timeout argument, for how much to wait.
Afterwards, you'd better use the opposite keyword - Wait Until Element Is Not Visible, to make sure the spinner disappears and you can continue with the test.
There is a problem with your locator - xpath has some issues if the element is svg, most of the times it can't address it directly. So instead of specifying it explicitly in the path, look for a node whose name happens to be "svg"; e.g.:
xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/*[local-name() = "svg"]
(^ changed the last element in the path)
Slightly offtopic - try to have less rigid locators - this one specifies an absolute path from the element with id "app" and down (a div child, then its first div child, then that one's third div child, and so on and so forth). If the element structure changes even slightly, the locator will stop working (say, in a bug fix, or re-positioning it, or just with using a HF of an JS library).
Try to find an element that's 1-2 levels higher than your target svg - by a solid class value, or structure that's unique, and use it as an anchor.
I reckon you used wrong keyword
Validate Loading Spinner
Wait until page contains ELEMENT xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/svg
Both work:
Validate Loading Spinner
wait until page contains element xpath=//*
[#id="app"]/div/div[1]/div[3]/div/div/div/div/*[local-name() = "svg"]
and
Wait until page contains ELEMENT xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/svg
I had a very similar issue

Robot Framework+Selenium: how to avoid "stale element" error (flaky test)?

I'm using Robot Framework and Selenium to test a website that has a language selector. I need to be able to select a language and then verify the page has actually changed to that language.
Since after choosing a new language the value in the lang attribute of the <html> tag changes, I decided I would use that to validate the language has been successfully changed. But I'm getting flaky results, as my test sometimes passes and sometimes doesn't.
This is the definition of the keyword I'm using:
CHANGE LANGUAGE
[Arguments] ${lang}
Select From List By Value ${LANGUAGE SWITCH} ?hl=${lang}
Wait Until Page Contains Element css=html
${doc lang} Get Element Attribute css=html#lang
Should Be True '${doc lang}'=='${lang}' timeout=15s
Since I have to execute this keyword quite a few times (one per each available language), I keep getting pretty often the dreaded "stale element" error: | FAIL | stale element reference: element is not attached to the page document.
I read through this article and a few other questions in here and understand this could happen if an element reference is updated after obtaining it. However, I'm not sure how exactly I should modify my keyword to avoid getting this error.
Using the information that everyone has so kindly provided, I may have found a potential fix (not sure if it's robust enough not to throw the exception anymore, but after a few test runs they have all passed): I added a "Wait Until Keyword Succeeds" and moved the language validation to a new keyword:
VALIDATE PAGE LANGUAGE
[Arguments] ${lang}
${doc lang} Get Element Attribute css=html#lang
Should Be True '${doc lang}'=='${lang}'
CHANGE LANGUAGE
[Arguments] ${lang}
Select From List By Value ${LANGUAGE SWITCH} ?hl=${lang}
Wait For Condition return document.readyState=="complete"
Wait Until Keyword Succeeds 5 5s VALIDATE PAGE LANGUAGE ${lang}
Then I call this "CHANGE LANGUAGE" keyword as many times as languages I need to test.
I added this as an answer instead of a comment so I could show the code in a more readable way.
In order to wait for a page to be ready to test after a user action (clicking a link or button, for example), the algorithm I've found that seems to be almost bulletproof is this:
get a reference to the html element
perform the action that will cause the page to change (eg: click a link or button)
wait for the html element to go stale - this signals that the refresh has started
wait for document.readyState to be "complete"
Step 4 may not be necessary, but it doesn't hurt.
This has worked extremely well for my team. This can still fail since you might have some async javascript that runs after document.readyState has been set, but there's simply no generic solution to that.
If your pages have a bunch of async javascript, you'll have to come up with your own scheme to know when the page is finally ready to be tested. For example, the last job to complete could set a flag, or you could wait until there are no pending async jobs, etc.
I'm not sure if you can do the above with robot keywords since it relies on the selenium staleness_of condition. It's pretty easy to implement in python, though.
The inspiration for this solution came from this blog post: How to get Selenium to wait for page load after a click
If you use my page object library for robot, this is built-in as a context manager.
As highlighted, a Stale Element error typically means that between the element retrieval and the corresponding action the element changed. Often this is due to a page refresh.
For this reason it is important to invest in a robust waiting approach. Not guessing that your page/application has completed loading, but instead knowing it has completed. This will not only prevent Stale Element errors but also speed up your tests as you're not unnecessarily waiting.
As the Get Element Attribute ${DOCUMENT}#lang is causing the stale element error and the Select From List By Value ${LANGUAGE SWITCH} ?hl=${lang} is causing the page refresh, then that leaves the Wait Until Page Contains Element html as your waiting approach.
As the <html> tag is always present and the first to be loaded in the DOM, this is not the best tag to wait for. I'd advise something unique for the loaded page or the last element of that page. Though I have to stress that this still constitutes to guessing the page has loaded.
It is better to invest in a robust waiting approach. Especially if your application is using a framework like Angular, React or jQuery then you have several Javascript markers to help you with this. For some frameworks there are even custom Robot Framework Libraries that support their specific markers.
Should your application not use a framework, then talk to your developers and have them develop this for you. Simplest would be a visible spinner, but a Javascript function that returns True will work just as well.
I have created a custom keyword when ever i want to click an element or perform and action i would call this custom keyword . This custom keyword uses the built-in keyword 'Wait Until Keyword Succeeds' which runs the specified keyword and retries if it fails. through this built-in keyword the number of retry's and the time to wait before trying to run the keyword again after the previous run has failed can be configured.
This custom keyword would call another custom keyword where three SeleniumLibrary keywords would be called. The first one would Waits until element locator is enabled keyword, which would wait until the element is not disabled nor read-only. Once the element is enabled then focus would be taken to the element where we are going to perform action. Finally perform the action. All these precautions has prevented me from Stale Element error.
HighLevelKeyword_Identify And Click Element
[Arguments] ${locator}
Wait Until Keyword Succeeds ${RETRY_ATTEMPTS} ${RETRY_AFTER} Identify And Click Element ${locator}
Identify And Click Element
[Arguments] ${locator}
Wait Until Element Is Enabled ${locator}
Set Focus To Element ${locator}
Click Element ${locator}

Finding clickon Element using Selenium. (JAVA)

I spend hours already trying to find the way to find the Element using Selenium WebDriver. I assume I need to use driver.findElement(By.xpath("")), but I am not quite sure how.
I somehow need to find and click on "clickon" element. The problem is that part of that element is changing (see screenshot) I need to pick up from the file and putted into the xpath.
I would appreciate any help.
We have been rigorously searching for automated functional testing solutions recently, and we began with Selenium. The entire reason we decided to search for other solutions was that our application also has dynamic IDs with no other obvious XPath mechanism to identify them. Selenium is unable to identify these elements on the page without some additional knowledge, just as you would be unable to identify these elements on the page if you didn't already know what they are.
If you are controlling the DOM creation, consider adding a unique ID or class to this element.
We recently came across eggPlant from testPlant, and it is an interesting approach to functional testing. It's essentially image based. Other viable solutions are Ranorex or HP's QTP or SmartBear's TestComplete.
You can use xpath. If the div class is constant, you can use something like:
driver.findElement(By.xpath("list-row field-item")).click();
To view the xpath, you can install firefox plugin called 'xpath checker' found here and right click on the dom element and click 'View Xpath' option to get the xpath of the element and then you can use that xpath in your code.
Or you can even use regex in the xpath which is suitable for the similar problems. Xpath with regex is really powerful.
It seems that you want to click the div that has the on click attribute that contains certain text that doesn't change, ignoring the part that does. In that case, use an xpath like this:
//div[contains(#onclick, '/challenge/index/rfp_id/')]
This will select the first div with an onclick attribute with a value containing /challenge/index/rfp_id.