How do I select elements inside an iframe with Xpath? - python

I want to create a Selenium test to test our extensions with AOL mail. I managed to login to AOL and compose an email, but I also need to select elements inside the editor, which is inside an iframe. I checked and even when the editor is open the following test fails:
self.assertEqual(first=1, second=len(self.driver.find_elements_by_xpath(xpath="//iframe[#name='editor_body']//body[#contenteditable='true']")))
I get the error AssertionError: 1 != 0. How do I select the body of the iframe and other elements by Xpath (or in any other way with Selenium)?

You cannot traverse through <iframe>'s until switching to them. Your xPath,
//iframe[#name='editor_body']//body[#contenteditable='true']
will not work because the <body> tag is within an iFrame, which is not in the current context. you need to switch to it first:
driver.switch_to.frame('editor_body')...

In case you are facing issues during Selenium automation testing here is some info that solved my problem:
Selenium by default has access to the parent browser driver. In order to access inside a frame, the driver's focus has to shift from the main browser window to the iframe(frame).
Therefore, if you happen to have to do assertions inside an iframe and then go back to the main window to do other interactions you will need to change the Driver's focus based on your target.
Read more at: https://www.tutorialspoint.com/how-do-i-select-elements-inside-an-iframe-with-xpath

Related

RobotFramework - Unable to click element using selenium library but Execute Javascript click works

I am using RobotFramework to automate one application. I am using the selenium library. For the whole application, selenium keywords "Click Button" and "Click Element" throw an error stating "ElementClickInterceptedException: Message: element click intercepted: Element **** is not clickable at point (376, 289). Other element would receive the click: ..."
I am able to identify the element using ID and it is not under any iframe or shadow-root element. but still I am not able to click on the element. I also tried with adding wait commands to see if it is sync issue but it is not. I tried to click using Action class, mouse move and click etc but did not work.
I tried to take the screenshot of the element using "Capture Element Screenshot" and it captures the screenshot of an empty place however, when I try to locate element in the browser dev tool, it locate it exactly
Only working solution I found is to run "Execute Javascript" keyword to click on the element such as
Execute Javascript $('#id').click();
Question:
Though I am able to make it work, I am curious to know what could be the issue in the application. I am not able to share the application dom code due to restriction. Sorry for that
This means that the element you trying to click is
Out of the visible screen (view port) so you need to scroll the page to make that element accessible or
It is covered by some other element - for example you should open a drop down menu etc or
You trying to click the element while it is still not fully rendered - in this case you need to add some delay to make the element fully rendered and be ready to accept clicks.
Selenium generally imitates human GUI actions. So, as a human user you can't click element inside drop-down without opening it. And you can't click element out of the visible screen. This is why Selenium .click() methods can't click such elements.
JavaScript click is more powerful tool, it can click invisible, covered etc. elements. It doesn't imitate human GUI actions.

Python Selenium in which iframe?

How am I able to check in which iFrame my driver is currently in? I got multiple functions entering in different iFrames - for a logic programme structure I'd like to implement a secure check in which iFrame the browser currently is focused / located, e.g. iFrame "banana" or "apple".
I selected those via:
wait.until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "example_xpath")))
Selection, etc. is perfectly working. For switching back to the "normal" default frame I'm using driver.switch_to.default_content(), though I don't always know in which I am, hence the question.

Selenium, how to find this element

I need to find the webelements like id="rcmrowgeneral".
A standard driver.find_element_by_id() is not working.
It's like they are inside another HTML page.
How can I find them with selenium to interact with them?
You can do this by following the selenium syntax which states if you want to find a specific tag inside an iframe you have to switch to that iframe first and then you can use selenium query to find it. Since you've not posted any code over here i assume you've background knowledge of handling automation processes. You can do this task by following this naming convention:
driver.switchTo().frame("id or name of the element")
driver.find_element_by_id("your id here")
Your element is inside of an iframe. First you need to switch to the iframe and then it is a good practice to wait for the element to be visible/clickable before interacting with it.
driver.switch_to().frame(driver.find_element_by_id("TiscaliWebmailFrame"))
WebDriverWait(driver, 20).until(expected_conditions.presence_of_element_located((By.ID, "rcmrowgeneral"))).click()

Selenium Python: Census ACS Data- unable to select Download button in window

I am attempting to scrape the Census website for ACS data. I have scripted the whole processes using Selenium except the very last click. I am using Python. I need to click a download button that is in a window that pops when the data is zipped and ready, but I can't seem to identify this button. It also seems that the button might change names based on when it was last run, for example, yui-gen2, yui-gen3, etc so I am thinking I might need to account for this someone. Although I normally only see yui-gen2.
Also, the tag seems to be in a "span" which might be adding to my difficulty honing in on the button I need to click.
Please help if you can shed any light on this for me.
code snippet:
#Refine search results to get tables
driver.find_element_by_id("prodautocomplete").send_keys("S0101")
time.sleep(2)
driver.find_element_by_id("prodsubmit").click()
driver.implicitly_wait(100)
time.sleep(2)
driver.find_element_by_id("check_all_btn_above").click()
driver.implicitly_wait(100)
time.sleep(2)
driver.find_element_by_id("dnld_btn_above").click()
driver.implicitly_wait(100)
driver.find_element_by_id("yui-gen0-button").click()
time.sleep(10)
driver.implicitly_wait(100)
driver.find_element_by_id("yui-gen2-button").click()
enter image description here
enter image description here
Instead of using the element id, which as you pointed out varies, you can use XPath as Nogoseke mentioned or CSS Selector. Be careful to not make the XPath/selector too specific or reliant on changing values, in this case the element id. Rather than using the id in XPath, try expressing the XPath in terms of the DOM structure (tags):
//*/div/div/div/span/span/span/button[contains(text(),'Download')]
TIL you can validate your XPath by using the search function, rather than by running it in Selenium. I right-clicked the webpage, "inspect element", ctrl+f, and typed in the above XPath to validate that it is the Download button.
For posterity, if the above XPath is too specific, i.e. it is reliant on too many levels of the DOM structure, you can do something shorter, like
//*button[contains(text(),'Download')]
although, this may not be specific enough and may require an additional field, since there may be multiple buttons on the page with the 'Download' text.
Given the HTML you provided, you should be able to use
driver.find_element_by_id("yui-gen2-button")
I know you said you tried it but you didn't say if it works at all or what error message you are getting. If that never works, you likely have an IFRAME that you need to switch to.
If it works sometimes but not consistently due to changing ID, you can use something like
driver.find_element_by_xpath("//button[.='Download']")
On the code inspection view on Chrome you can right click on the item you want to find and copy the xpath. You can they find your element by xpath on Selenium.

Hidden elements are visible while using xpath

Ive got an app wirten in angular and all xpath i make are visible in DOM but not on a page. So if I want to check if element is visible after some action I preform I cant do that, cause webdriver can see it even when test should fail.
f.e.
I want to test login form, after logging in i want to see if some element is visible. When i put invalid data, test should fail, but is still finds this element even since he is hidden.
I want selenium to find only visible elements, how can i do that?
you can form your xpath in way that it gives you only visible element. Following is the xpath for google search button on google.com
//input[#name='btnK' and not(ancestor::div[contains(#style,'display:none')]) and not(ancestor::div[contains(#style,'display: none')])]

Categories