Handling Element is not clickable at point (x, y). Other element would receive the click: With Capybara, ruby, Webdriver - ruby

I am writing a UI test that goes to a list of articles and selects the load_more button until this is no longer available (because all articles have loaded). The problem is the button has been hidden at this point rather than removed and is returning this error
Selenium::WebDriver::Error::UnknownError: unknown error: Element <div
class="">...</div> is not clickable at point (x, y). Other element
would receive the click: <div class="" id="" data-module-name="">...
</div>
(Session info: chrome=65.0.3325.181)
(Driver info: chromedriver=2.36.540469
ruby-2.5.1/gems/selenium-webdriver
3.11.0/lib/selenium/webdriver/remote/response.rb:69:in `assert_ok'
I have tried a few loop types but for this, if we assume I'm using
while world.page.has_load_more?
world.page.load_more.click
break if world.page.has_load_more? == false
end
The question is how do I tell Selenium this is ok and not to error, so I can continue with the next step in my test case(cucumber). I realise that the choice of loop type may also be incorrect, so feel free to suggest changes there as well.

Firstly, as Rajagopalan has pointed out, the error that you're getting is not that your element is not visible (as in hidden by CSS) but that it is overlapped by another element. You can call save_and_open_screenshot to see what element is overlapping the button (possibly a fixed footer, etc?). Make sure you've set the window size large enough so you don't have elements unintentionally overlapping and make sure you're running the latest version of Capybara since it attempts to deal with overlapped elements in selenium by scrolling them into view if possible.
Secondly, the loop in your question doesn't make a lot of sense having both the while and break since they check the same thing. Also, assuming the "load more" button is loading and appending to the page via AJAX, you probably need to wait for the new elements to load before checking if the button exists (click does not wait for actions to complete since it has no idea what actions could/would be triggered). That would then become a structure something like
while page.has_button?('Load More')
# Get the current number of visible articles
article_count = page.all('div.article').count # Use whatever selector would match an article in the list
# click the button
page.click_button('Load More')
# ensure more articles have loaded
expect(page).to have_css('div.article', minimum: article_count + 1)
end
Note: You'll probably want to change that to use whatever page object methods you are using (has_load_more?, etc) but the general logic should be correct

Related

Capybara wait until button is enabled?

Surprised I actually haven't come across this, but I have a simple button that is disabled until a dropdown is selected. Sometimes the page isn't fast enough to "enable" the button to be clicked on after the previous dropdown is selected causing it to fail.
I could throw in a "sleep" of a second or two and fix this, but that seems like a lazy/poor way to do this.
Is there a way in capybara (or purely selenium) that I can make it wait until the button is actually enabled? I'd like to throw this is the page model method for this button (as im trying to avoid API specific methods/selenium/etc... in the actual test specs (Although I can if I need to).
FWIW this is specifically for Ruby's capybara framework but pure selenium is fine as well.
Assuming the button you're referring to is actually a button (<button> element, or <input> element with type submit, reset, image, or button) then Capybaras :button selector will (by default) wait for it to be non-disabled.
click_button('Something')
or
find_button('button_id').click
or
find(:button, 'button_value').click
If any of the finder or action methods aren't waiting long enough for a specific element you can always increase the maximum wait time for a specific finder/action by passing a :wait option
find(:button, 'Something', wait: 10).click
If you're not using selector types (if not, why not) and instead are just using raw CSS to locate the element then you can use the :enabled pseudo class along with your existing CSS and something like
find('#my_button:enabled', wait: 10).click
If the element you're calling a button isn't actually a button but some other type of element (<a> etc) styled to look like a button, then you'll need to explain exactly how you're disabling the "button".
In Python you can do something like this:
def wait_until_clickable(driver, xpath, timeout = 1):
while timeout > 0:
try:
element = driver.find_element_by_xpath(xpath)
element.click()
return element
except:
time.sleep(0.1)
timeout = timeout - 0.1
return False

Difficulties with Cypress scrollTo method

I am having a few issues testing a virtual scroll component with Cypress. I have a test that checks the li elements present in the DOM after scrolling to the bottom of a container.
When written like this the test passes:
cy.get('.virtual-scroll').scrollTo('bottom')
cy.wait(0)
cy.get('li').last().children('h4').contains('1999')
When written like this it doesn't:
cy.get('.virtual-scroll').scrollTo('bottom')
cy.get('li').last().children('h4').contains('1999')
This also fails:
cy.get('.virtual-scroll').scrollTo('bottom').get('li').last().children('h4').contains('1999')
In the second and third examples, get('li') is returning the li elements present before the scroll has completed, and therefore failing the test. I can fix this by adding .wait, but don't fully understand the behaviour and wonder if this is a bug.
Any ideas?
Make an assertion that will always pass when the DOM is rendered, such as using .get() for an element that gets added to the DOM
ex) if you had a <ul class="myloadedlist">.... :
cy.get('.virtual-scroll').scrollTo('bottom')
cy.get('ul.myloadedlist')
cy.get('li').last().children('h4').contains('1999')
That way, Cypress will continue with the test as soon as that element becomes visible.
Why?
I'm assuming the elements get added to the DOM in some sort of scroll eventListener. In that case this is correct behavior.
Essentially what you've tested is the race condition of a user scrolling very quickly to the bottom of the page, to see that the DOM has not yet finished rendering- a valid senario.
Since you targeted the last() li element, Cypress finds the last element of the page before the DOM gets updated, and expects it to contain 1999, which it does not, even after Cypress retries for 4 seconds.
This is actually a great feature of Cypress, because you can test on the state of the DOM at times that the User might only see for a split second.
In my case, adding a duration to the scroll option did the trick.
cy.get("#dialogContent").scrollTo("center", { duration: 500 });

Can't click an input type="button" that exists but it's not visible

First of all... I red everything I could and tried everything I found!!
With the following gems installed in WinXp:
Watir-webdriver 0.6.10 |
selenium-webdriver 2.42.0 |
Firefox 30
I have a type="button", inside an input tag element, which I'm sure it exists in the browser (returns true to exists?), but that it's not visible to watir (returns false to visible? or present?), despite being visible to the user.
I've tried the .hover, .fire_event "onmouseover", .click and fire_event("onclick") approaches and none solved the problem.
With the first I get a native event problem whether I disable native events in firefox, as suggested in watir webdriver website, or not.
b.div(:class, "buttons btnGuardarCancelar").button(:id, "guardar").hover
b.div(:class, "buttons btnGuardarCancelar").button(:id, "guardar").when_present.click
With the second I get a true answer, but nothing happens, even with a wait_until_present or when_present after that command.
b.div(:class, "buttons btnGuardarCancelar").button(:id, "guardar").fire_event("onmouseover")
b.div(:class, "buttons btnGuardarCancelar").button(:id, "guardar").when_present.click
With the third I get a timeout, saying the element is not visible.
b.div(:class, "buttons btnGuardarCancelar").button(:id, "guardar").when_present.click
And with the last one it fires some other onclick event, but not the one associated with the button I indicate.
b.div(:class, "buttons btnGuardarCancelar").button(:id, "guardar").fire_event("onclick")
Also tried xpath with the following:
b.element(:xpath, "//input[#id='guardar']").when_present.click
and
b.button(:xpath, "//input[#id='guardar']").when_present.click
the code is what follows:
<div class="buttons btnGuardarCancelar" name="">
<input id="cancelar" class="formButton margingleft" type="button" value="Cancelar" onclick="openUserServiceConfigMenu(1);" tabindex="12"></input>
<input id="guardar" class="formButton margingleft" type="button" value="Guardar" name="guardar" onclick="sendForm();" tabindex="12"></input>
</div>
The behaviour is the same for both buttons. I don't know what to do more, to get this working. Important to say that I have no control over the website.
add-ons:
1) it works when interacted directly by a human user.
2) it also doesn't work via irb.
3) i don't need the click any other buttons to access this button.
Edited:
Just tried:
b.element(:css, "div.buttons.btnGuardarCancelar > input[name=guardar]").click
Received the following error:
[remote server] file:///D:/DOCUME~1/p056988/LOCALS~1/Temp/webdriver-profile20140
708-5676-32980a/extensions/fxdriver#googlecode.com/components/command_processor.
js:8791:5:in `fxdriver.preconditions.visible': Element is not currently visible
and so may not be interacted with (Selenium::WebDriver::Error::ElementNotVisible
Error)...
Well, found my answer... tried to answer yesterday, but since my rep is still low I couldn't until 8 hours after I posted.
After digging deep in the website code, using the Firefox built-in inspector, I found the issue ...
It seems that there are some other buttons in the same page, with the same identifiers - html just like the one I was trying to address -, but they are hidden and so watir-webdriver tries to click the first it gets in the html page code and it gets a not visible error.
I managed to solve the problem by editing the button parents to be more specific, starting with the first "present?==true" element in the path.
b.td(:class, "tab_user_service_options").div.div.div.div(:class, "buttons btnGuardarCancelar").button(:id, "guardar").click
Thanks for all your kind answers.
Cheers.
Sometimes the .click doesn't work. There are many different factors that could cause this and that really depends on the implementation of your application. Utilize the OpenQA.Selenium.Interactions.Actions class to simulate the user movements instead of executing a click event on an element.
OpenQA.Selenium.Interactions.Actions actions = new OpenQA.Selenium.Interactions.Actions(driver);
actions.MoveToElement([IWebElementGoesHere]).Perform();
actions.click().Perform();
This will move the mouse to the desired location and then click it. Based on your previous comments you are able to find the web element so it should function to move the mouse and click there. There is also an actions.click([IWebElementGoesHere]).Perform(); which I have found also usually works, but if it doesn't then you can use the move and then click.
Depending on your application you might have to move your mouse and wait before clicking if there is some behind the scenes actions that take place...but that totally depends on the implementation of your application.
The element you are trying to 'click' is most likely being 'covered' by another element (possibly a 'span' element). The element will return 'exists?' but is not 'clickable', "because another element would receive the click"
On the site I'm currently testing the UI guy will use a 'span' to stylize the elements on the page. So where it looks like i'm clicking on a 'button' element, in actuality I'm clicking on the span that is on top of the button element.
I would suggest using Selenium IDE and recording the flow, it should give you some clues as to the element you can use in your script.
As per the documentation of Watir, it first check whether element exists(Returns whether this element actually exists), and which doesn't check element is visible or not. So before performing any action,it is necessary that element should be visible.
def click
assert_exists
assert_enabled
#element.click
run_checkers
end
I generally check for presence for element and then check whether element is preset or not. If not use, wait_until_present and then perform any desired action.
browser.element(:css => locator).wait_until_present
browser.element(:css => locator}").click
Try out this and revert if this works for you!

intercepting the onload event fired by the browser in watir

I have a unique situation over here. I have a button on a form which produces a popup if there are some errors in the form. [I know this is not good practice, but the developers of the product would not be changing that behavior!] The form navigates to a different page if all the required fields are correctly populated. Now, I need to write a script in order to click the "Submit" button on the form which either might produce a popup or navigate to the next page.
I have the used the click_no_wait on the "Submit" button and handled the popup using AutoIt as per Javascript Popups in Watir. Now, if all the information is valid and the form navigates to the next page, I use a delay in the script by following some of the techniques described in How to wait with Watir. I am using a Watir::wait_until() to wait in the script.
Now sometimes because of some network issues, it takes time to go to the next page (report-generation) page when the form is submitted and thus the script fails because of the timeout value specified in the wait_until.
I was wondering whether there is a way to intercept the onload event of the HTML page in Watir, since the onload event isn't fired until the entire page is loaded. By that way I could have an accurate estimate of the timeout value and not experiment with it. Thus, my script will pass 100% rather than say 98% right now.
Thanks for any help on this topic.
You could try setting up a rescue for the time out, then looping a reasonable amount of times (2 or 3?) if it encounters a timeout.
E.g.
# All your button clicking and autoit stuff here
i = 0
begin
b.wait_until{ # the thing you're waiting to happen }
rescue TheSpecificTimeOutException
# Sorry I can't remember it, the command prompt will tell you exactly
# which one
if i < 3
i += 1
retry
else
raise
end
end
I'm sure i'll have messed something up in the above, or there'll be more concise ways of doing it, but you get the idea. When it times out, give it another few tries before giving up.

Using Watir on Peoplesoft App: each text field reloads the page

I'm using Watir 1.6.7.
I'm working on developing some regression tests for a PeopleSoft App using Watir and Cucumber. I have run into a few issues with forms in the application.
First, when entering a value into a text_field, the page refreshes when the user clicks outside the text_field. Waiting for the next text_field element to exist is problematic because it may locate the element before the page reloads, or after the page reloads as expected. Increasing the wait time never feels like a good solution, even though it "works".
The second issue is that the page refresh is not triggered until the user clicks outside the current field. In this case, that happens when the script tries to access the next text_field to be populated. One solution here would be to send a or keystroke, but I can feel the script becoming more brittle with every addition like this.
Are there any other approaches that would be less brittle, and not require 2-3 extra commands in between each text_field action?
The play-by-play looks like:
Browser navigates to page that contains the form.
Browser fills in first form field. (fix: send keystroke to cause page refresh, wait_until second field is visible again)
Browser selects the second form field to be filled out. (again, keystroke & wait_until)
Page refreshes, script fails. (resolved)
Browser selects the third form field...
The application started exceeding the 5 second sleep duration, and I did not want to increase the wait time any longer. I wanted to see what would happen if I populated the text field faster using "element.value =" rather than character by character with "element.set ".
This change completely resolved all complications. The page no longer refreshes when entering text, and no long requires a send_keys statement to use TAB or ENTER to move to another field. The form is storing all of the data entered even though there are no refreshes or state saves between fields.
Previous method:
def enter_text(element, text)
element.set text
#browser.send_keys("+{TAB}")
sleep 5
Watir:Wait.until { element.exists? }
end
New method:
def enter_text(element, text)
element.value = text
end
Firstly, there are interesting Wait methods here: How do I use Watir::Waiter::wait_until to force Chrome to wait?
Overall, I don't quite understand your problem. As I understand it your script is working. If you could be a bit clearer about your desires compared to what you already have that would help, as would some sample source code.
If you're looking for ideas on custom waiting you could check for changes in the HTML of your page, form or text field. You could check that the text field is .visible?. You could try accessing the next text_field (clicking it, or setting the value for example), then catch the exception if it can't find the text_field and retry until it doesn't break, which would solve both your problems at once.
Why would clicking outside the current field be a bad solution? Do you absolutely need the next step to be a text_field access? I haven't gotten my head around how the next field only exists when you click outside the current field, but you cause this refresh by accessing the next field.
Edit: Most welcome, and thank you for clearing that up, I think I now understand better. If you allow Watir to invoke its page wait, or force it to, then it will wait for the refresh and you can then find the new text_field. Keystrokes do not invoke ie.wait, so if you send a single keystroke, then invoke a wait then the rest of your script will be responding to the post-refresh state.
I highly recommend the OpenQA page on waiting in Watir. If what you're doing to invoke the refresh does not appear on the list of things that invoke Watir page waits then you need to invoke your own page wait... but you need to do it before the page refreshes, so the cause of the refresh should end before the end of the refresh itself.
I don't know peoplesoft's app well enough to know this, but Does the app display anything for the user while it's processing.. like some kind of little 'loading' graphic or anything that you might be able to key off of to tell when it's done?
I've seen apps that do this, and the item is just an animated gif or png and it is displayed by altering the visibility attribute of the div that contains the graphic. In that instance you can tell if the app is still loading by using the .visible? method on that element and sleeping for a while if it's still there.
for the app I'm testing (which has one of those 'icons') I created a simple method I called sleepwhileloading. all it that is does is use a one second sleep wrapped in a while loop that looks to see if the loading icon is visible. works like a charm

Resources