Expected condition: wait until one element clickable while other- dissapeared - python

I face the following issue: there is a page (unfortunately it's not public) with a Register request and a Approve request button. Clicking on a button leads to opening a transparent div with a pop-up.
Algorithm is as following:
1) Click Register;
2) Fill form in raised pop-up;
3) Click Submit to confirm registration (to close pop-up);
4) Click Approve
So I use the following code:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//button[#id="RegisterButton"]'))).click()
# ...Filling Register form...
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//button[#id="SubmitButton"]'))).click()
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//button[#id="ApproveButton"]'))).click()
But despite using EC.element_to_be_clickable() I get the following error:
WebDriverException: Message: unknown error:
Element is not clickable at point (338, 167).
Other element would receive the click: <div class="modal fade" id="confirmWindow" style="display: block;">...</div>
Seems that the driver considers Approve being already clickable and tries to click on it while the transparent div is still displayed.
So I need an Expected Conditions statement to catch the state when the div is already selected and Approve if the button is clickable
P.S. I'm using time.sleep() to do this, but seems to be a rough approach
UPDATED
I try to use JavaScript:
driver.execute_script('document.getElementById("ApproveButton").click();')
and so far it works... I wonder if it really a better way to click on button or there could be some obstacles also?

Understandably using a time.sleep() is something you want to avoid. Since it clicks on the modal I am assuming the button is considered clickable even though the modal isn't fully disappeared yet. In this case I would add another wait that waits till the modal is no longer visible.
wait = WebDriverWait(driver, 10)
wait.until(EC.element_to_be_clickable((By.XPATH, '//button[#id="RegisterButton"]'))).click()
# ...Filling Register form...
wait.until(EC.element_to_be_clickable((By.XPATH, '//button[#id="SubmitButton"]'))).click()
# Wait till the modal is no longer visible
wait.until_not(EC.visibility_of_element_located((By.ID, 'confirmWindow')))
wait.until(EC.element_to_be_clickable((By.XPATH, '//button[#id="ApproveButton"]'))).click()
Note: I've also created a single instance of WebDriverWait instead of making a new one for each wait like you did in your example. There is no need to create a new instance all the time.

Related

Python Selenium not clicking the correct button in a popup modal using CssSelector

I am using the selenium webdriver in Python to process through a website, but I am running into an issue with clicking a specific button that shows up in a popup modal. Currently, the behavior seems as though the click is being performed, but appears to be clicking the "No" button instead of "Yes."
Here is the snippet of code I am currently using. The first click will hit an "Apply" button, which then opens a popup confirmation modal that requires the user to select No or Yes to continue with applying the request.
driver.find_element(By.CSS_SELECTOR, xpaths['planRangeApply']).click()
time.sleep(2)
WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, 'div.modal-footer:nth-child(3) > jv-button:nth-child(2)'))).click()
For comparison, here is the CSS_SELECTOR for the "No" button:
div.modal-footer:nth-child(3) > jv-button:nth-child(1)
From what I have researched so far, I am properly waiting for the modal to appear and the proceed to find the Yes button element. Am I misunderstanding this process or is my CSS_SELECTOR path simply incorrect? I have tried utilizing XPATH instead of CSS_SELECTOR, but I get the exact same result.
Here is a screenshot of the page inspector with the correct button highlighted:
The CSS_SELECTOR is slightly off.
The parent tag is <div class="modal-footer">
The desired element is the second <jv-button> child of it's parent.
Solution
The effective CSS_SELECTOR would be:
div.modal-footer jv-button:nth-child(2)

Can't click on webpage element using python selenium when used with mobile user-agent

I am trying to automate clicking on the play button of an embedded iframe music player on a webpage, I am coding using python 3 and Selenium to select the element to click.
When the user-agent is changed to replicate a mobile device, a wrapper layer then obscures the button that I can normally click, it asks if I want to listen on the main site or in the browser. I want to listen in the browser, but so far everything I have tried to click the correct element to achieve that, has failed.
I believe I am clicking on the wrong part but cannot find a way to access the correct part.
The inspect window of the browser shows the below for the part of the wrapper I need to click on:
<a class="mobilePrestitial__link sc-font-light" href="#">
Listen in browser
</a>
::before
"
Listen in browser
"
/a>
When I hover over the ::before part it highlights the part in the browser that I believe I need to click, but using right-click to inspect ::before just says 'scroll in view' so I cannot copy whatever the element represents.
My current code is this:
driver.switch_to.default_content()
driver.switch_to.frame(driver.find_element_by_partial_link_text('Listen in browser'))
element = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, '//a[#class="mobilePrestitial__link"]'))
)
element.click()
But it errors without a message, I suspect I need to be clicking on the element presented by ::before but cannot figure how to do that.
I found a workaround and solved this by hiding the wrapper overlay using Selenium in python script to make a Javascript call
driver.execute_script('document.getElementsByClassName("mobilePrestitial")[0].style.display=\"none\"')
once the overlay is hidden with the above code, the original button is accessible in the browser

Handle exception of Pop Up displayed during a Selenium-Python script

I was coding a script written in Py and Selenium that slides some slide and clicks a button of each slide, but sometimes, when the button is clicked, a popup is displayed, and other times the script should go regularly.
Can anybody explain me how to handle the ‘exception’ and How can write correctly the Code?
I'm sure to use Try and Exception, but I don't know how to recognize the Popup, so every attempt I tried failed.
try:
element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, “x”)))
element.click() #Click Slider Button
element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, “y”)))
element.click() #Click arrow to go to next slide
exception that, if popup is displayed, do this code
except driver.find_element_by_class_name(“z”).is_displayed():
element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, “f”)))#click to close popup
element.click()
element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, “y”)))
element.click() #click arrow to go to next slide
Try using some popups blocker extensions. If you use a chrome based navigator than this extension works perfectly and will block all possible popups.
Download the extension with this service and follow this question if you don't know how to use extensions with selenium.
This is not exactly the solution you want but it works.

Locate "file upload" button with Selenium

I have the button shown below (image and HTML) and am trying to click it.
Selenium is unable to locate it - I have tried locating by both xpath and by ID.
<input id="wsUpload1" type="file" name="file">
XPATH:
element = driver.find_element_by_xpath('//input[#id="wsUpload1"]')
element.click()
Where am I going wrong?
EDIT: Here is the exception thrown by Selenium:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//input[#id="wsUpload1"]"}
Possibilities
Duplicate web element with same id in the page.
Element may be in frame. You need to switch to frame
Trying to access the web element before page is loading.Give some wait time.
Not sure why your button wasn't found, maybe it's because of quotes (although it should show you error in that case), try with driver.find_element_by_xpath(".//input[#id='wsUpload1']") and see if it works. I'm not sure is your button already rendered on the page or you trigger it somehow so it's not there yet?
NoSuchElementException is thrown because your targeted element couldn't be found on that page, it could be that you are on the wrong page, element is not rendered yet so you should wait for it to appear, element could be in some iframe etc etc, it's hard to say when I don't know how your page works.
But if you are trying to upload something you should perform sendKeys() on that button (with path of file which are you trying to upload), not click() on it. This is how selenium upload works.
I have solved it - the driver opens a tab on a side panel and the button is in the tab. There seems to be a few ms delay between clicking the tab and the button appearing so I added a wait until element is clickable and that seems to work.
wait.until(EC.element_to_be_clickable((By.XPATH, "//input[#id='wsUpload1']"))).click()

Selenium-Python-How to submit the button only after it is enabled?

I have web page, where the user needs to upload a list of documents and only after which the Submit button is enabled.
I am using python selenium for this automation. My program is able to upload the documents but is unable to click on the Submit button after it is enabled.
I tried this:
element = WebDriverWait(driver, 10000).until(EC.element_to_be_clickable("(//button[#type='submit'][2]"))
element.click()
but it is not working, as the jobs are not submitted in the front end
Change code to be:
element = WebDriverWait(driver, 100).until(
EC.element_to_be_clickable((By.XPATH, "//input[contains(#ng-click,'SubmitJob')]")))
element.click()
So we now are waiting for up to 100 seconds (instead of 3 hours), and we are passing a tuple argument (By.XPATH, "//input[contains(#ng-click,'SubmitJob')]") to EC.element_to_be_clickable, which is what it expects.
Cannot comment on the correctness of the xpath though, but please check it as well.
Edit: changed the xpath based on comment. There are many ways to express that xpath. I would prefer ng-click over class attribute, since classes may change; action, however, will likely stay the same. But if you choose using classes, I still suggest going with something like
//input[contains(#class,'btn') and contains(#class,'form-control')]
because you never know if the order of classes will change.

Categories