Capybara with Selenium: Can't click on hidden element - ruby

I have a situation in my view where a clickable icon is only visible when it's containing div is hovered over (using Knockout JS, SCSS) . Something like this:
HTML
<div id="button_div">
<i id="icon" data-bind="click: dosomething"></i>
</div>
SCSS
i {
display: none;
}
#button_div:hover {
i {
display: block;
}
}
Everything works fine on the page, but I can't seem to figure out how to click the element in Capybara. I've tried adding the :visible symbol to the method, but with no luck:
find('#icon', visible: false).click
This gives me the a "Selenium::WebDriver::Error::ElementNotVisibleError" error.
Using:
Capybara.ignore_hidden_elements = false
Gives me the exact same error
I've also tried using a Selenium Action such as:
button_div_element = find('#button_div').native
button_element = find('#button', visible: false).native
page.driver.browser.action.move_to(button_div_element).click(button_element).perform
While this doesn't throw an error, it also doesn't click the button.
Does anyone have any idea what I might be doing wrong?

Capybara is designed to emulate a user so you can't click on a non-visible element because a user couldn't. You should, however, be able to replicate a users actions to make the element visible and then click it
find('#button_div').hover
find('#icon').click
if that doesn't raise an error but also doesn't appear to click the button try putting a short sleep between the two actions since you may have an animated appearance which can cause clicks to miss items

Try using .execute_script() as below :-
button_div_element = find('#button_div').native
button_element = find('#button', visible: false).native
page.driver.browser.action.move_to(button_div_element).perform
page.driver.browser.execute_script("arguments[0].click()", button_element)
Hope it will work...:)

After some painstaking trial and error, I managed to find a solution that worked
button_div = find("#button_div_id").native
icon = find("#icon_id").native
page.driver.browser.action.move_to(button_div, :right_by => -50).click.perform
icon.click
Not sure why I had to manually tell Capybara to go left by 50px, but that seems to have done the trick.
Also, I added the following line to my setup code:
page.driver.browser.manage.window.maximize
This makes sure the window is maximized before running the test. I'm not 100% sure, but this might have also had something to do with the fix.

Related

Need help on clicking an element (Element is not clickable at point (62, 459)) - Capybara Ruby Selenium Automation

I am having below error message in my console while trying to click on a button element:
unknown error: Element is not clickable at point (62, 459).
Other element would receive the click: <i class="foo foo-chase-lemon font-size-13"></i>
Here's my code below:
#object = Page.new
#object.wait_until_btn_element_visible
#object.btn_element.click
I have tried with retry 5 times to click on it using rescue but didn't help.
Below code also didn't work where i tried to move to that element before click.
Capybara.page.driver.move_to.(#object.btn_element).perform
Any solution will be greatly appreciated.
I tried increasing the resolution/ scrolling the window. None of them worked on this specific scenario. These solution might work for others.
However, I resolved the issue by clicking the button using javascript "execute_script" method in my automation script.

How can I call a div class under div in watir?

I am creating automated test scripts with Ruby and Watir.
I am trying to call a div class from these lines of codes:
<div class="slimScrollDiv" style="position: relative; overflow: hidden; width: auto; height: 500px;">
<div class="modal-body" style="overflow: hidden; width: auto; height: 500px;">
<form id="user-form" class="form-inline" enctype="multipart/form-data" method="POST" novalidate="novalidate">
<fieldset></fieldset>
</form>
</div>
My aim is to use this one
browser.div(:class => '').send_keys :space because I want to scroll the div, for me to be able to send_key "" in some other textfield hidden.
I even try to use browser.scroll.to :bottom, but still it doesn't work.
So I am making some guesses as to what you are really trying to accomplish here. I'll first address your question as originally stated, then address how to do what I think you are trying to accomplish.
Selecting elements inside other elements
The high level answer is that there is nothing special to doing this, in many (most) cases you don't even need to worry about how deeply nested an element is, as long as you have a unique way to identify it, such as a class, name, etc that is unique.. For example in the code you provided, to get the div with class modal-body you would just do
browser.div(:class => 'modal-body)
If there were a lot of divs on the page with that class, then you might want to locate the one you want by looking inside some other container element that is unique so you find the right one.. in the code above that would be something like
browser.div(:class => 'slimScrollDiv').div(:class => 'modal-body)
Usually you only do that sort of thing when it is difficult to find an easy way to identify an element because it has few or no attributes, or non-unique attributes.
Scrolling a custom control
This I think is your real issue. You appear to have a control with a non-standard scrollbox. That is to say that instead of being simple HTML that is defined so that the browser creates and controls a scroll box (which would normally work with the methods you have already tried, or even get scrolled into view auto_magically) you instead have a custom control where the scroll box is driven by javascript code such as jQuery or Bootstrap. Such code usually is event driven, looking for things like mousewheel movement when the mouse is over the control, or manually grabbing and dragging the element that is being rendered to look like a scrollbar. Often such controls do NOT respond to keypresses like space or arrows, EVEN if they have been selected, clicked on, have focus etc.
Still I would first suggest try using .location_once_scrolled_into_view on the sub element you want that is inside the scrollbox. (See example in other answer) If that does not work then try manipulating the controls of the sçroll area.
Based on class values in your code fragment, I think you may be dealing with a jQuery powered 'slimScroll' control similar to those shown on this page. If that is indeed the case, then you can scroll the control by using drag methods on the scrollbar element. In slimScroll the element you want will be inside the div with class 'slimScrollDiv' and is another div with the class 'slimScrollBar'.
As long as the scrollbar is visible, you should be able to do a .drag_and_drop_by on it to scroll the content in the scrollbox. If it is not visible (as can happen in the first example on the linked page) then it may be harder, you might have to try firing mouseover events, or invoking some JS code to change it's style to not be hidden. You will need to experiment to see how many pixels to drag it at a time to scroll the window a 'right' amount based on how much content is in there. (potentially you might be able to figure that out based on the .style 'height' values for the elements, but that would take experimentation with the actual page and only needed if the amount of content in the box is variable)
For the second example on the linked page, I was able to scroll things using the following code
scrollbar = browser.div(:class => 'slimScrollBar', :index => 1)
scrollbar.drag_and_drop_by 0,10
I'm not sure what is inside your scrollbox, but for psuedo-code purposes of we just call it 'thing_I_want' then you might be able to scroll it into view with code something like this
scrollbar = browser.div(:class => 'slimScrollBar')
until thing_I_want.present?
scrollbar.drag_and_drop_by 0,5
end
as I said you might have to play with the drag distance there to get a 'right' amount, but 5 (pixels) seemed a reasonable starting place.
hidden text_field or just not visible in page?
you could try focus:
browser.text_field(:id => 'myid').focus
or if you need to scrolldown until it is visible
unless browser.text_field(:id => 'myid').visible?
browser.div(:class => 'slimScrollDiv').send_keys :arrow_down
end
or if you need to scrolldown to the footer (end of page)
browser.div(:id => 'footer').wd.location_once_scrolled_into_view

Selenium webdriver can't find button

EDIT:
I have cleaned this up a bit.
I have a button that looks like this:
<input id="applyRuleButton" class="Button" name="filtersContainer:applyRuleButton"
value="Apply" onclick="wicketShow('applyRuleButton--ajax-indicator');var
wcall=wicketSubmitFormById('id256', '?wicket:interface=:23:form:filtersContainer:applyRuleButton:
:IActivePageBehaviorListener:0:&wicket:ignoreIfNotActive=true',
'filtersContainer:applyRuleButton' ,function() { ;wicketHide('applyRuleButton--
ajax-indicator');}.bind(this),function() { ;wicketHide('applyRuleButton--
ajax-indicator');}.bind(this), function() {return
Wicket.$$(this)&&Wicket.$$('id256')}.bind(this));;; return false;" type="submit">
Firebug:
<input id="applyRuleButton" class="Button" type="submit"
onclick="wicketShow('applyRuleButton--ajax-indicator');var
wcall=wicketSubmitFormById('id2ee',
'?wicket:interface=:29:form:filtersContainer:applyRuleButton::IActivePageBehaviorListener:0
:&wicket:ignoreIfNotActive=true', 'filtersContainer:applyRuleButton' ,function() {
;wicketHide('applyRuleButton--ajax-indicator');}.bind(this),function() {
;wicketHide('applyRuleButton--ajax-indicator');}.bind(this), function() {return
Wicket.$$(this)&&Wicket.$$('id2ee')}.bind(this));;; return false;" value="Apply"
name="filtersContainer:applyRuleButton">
I'm trying to click it and have tried pretty much everything for 2 days, webdriver does not find the element, IDE does find it:
//This was my first approach, it should work.
It works in IDE, but not Webdriver:
driver.findElement(By.id("applyRuleButton")).click();
//then perhaps this should do the trick, hint: It doesn't:
WebElement element3 = driver.findElement(By.id("applyRuleButton"));
JavascriptExecutor executor3 = (JavascriptExecutor)driver;
executor3.executeScript("arguments[0].click();", element3);
Ok, Id not working, I get it.
Then this should work at least:
driver.findElement(By.xpath("//table/tbody/tr/td/div/div/table/tbody/tr[6]/td/input[#id='applyRuleButton']")).click();
It feels like I am missing something obvious here, some help please?
Additional information:
I have added a 5 second wait, the page is completely loaded.
This button is located in a table:
The Xpath is
/html/body/div[4]/div[2]/form/div[3]/div/div/table/tbody/tr/td/div/div/table/tbody/tr[6]/td/input
Webdriver error, no matter what I throw at it, is: Unable to locate element
I have used both 'click' and 'submit', still no success.
I think in this case there are two possibilities :
Either there is another element having same id/xpath.
OR Element present in another iframe.
Is the button visible. Selenium click (latest firefox 26 and latest webdriver 2.39.0) does not sometimes implicitly scroll; Or it may not scroll it fully. So scroll it into view - Scroll Element into View with Selenium and then it should work.
Note Selenium Best Practise try to use By.Id,By.CSSSelector and if nothing gets use By.Xpath in the order of priority. ( Use the FireFinder, FireBug plugin to test XPath or CSS)
This might be a synchronization issue. Such issues can be solved using smart waits.
new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementExists((By.Id("applyRuleButton"))));
WebElement element3 = driver.findElement(By.id("applyRuleButton"));
And that should work perfectly fine.
There is absolutely nothing wrong with your selector. I just don't think you're invoking the click correctly.
Try:
driver.findElement(By.id("applyRuleButton")).click();
If this doesn't work, then you might have to invoke a WebDriverWait since you have this question marked as [ajax]
Could you post the entire html?
As a simple experiment, I took the html snippet that you posted and wrote a short python script that invokes selenium:
from selenium import webdriver
br = webdriver.Firefox()
br.get("put your path to snippet here")
button = br.find_element_by_id("applyRuleButton")
print button.get_attribute("name")
button.click()
br.close()
I can find the button and extract the attribute "name" which prints "filtersContainer:applyRuleButton". This is admittedly a very limited experiment, but it suggests that the issue is related to not being where you think you are on the page.
Try this:
driver.findElement(By.Name("filtersContainer:applyRuleButton"));
If this doesn't help, check whether this button is located in any other frame. If so, you may have to find and move your focus to that frame and then locate this button.
First try to identify the button by writting correct xpath using firebug, if you are able to identify button by that xpath then use that xpath while writing your script.
driver.findElement(By.xpath("//input[# type='submit' and # id='applyRuleButton'")).click();
This is ajax application use proper explicit/ webdriver wait till the button gets downloaded
I see that this thread is old, but I was looking at it today (Sept/2021) as I was having the same problem: I could see the name / id/ type of the button, but it would never be found.
I discovered that when I had clicked in a prior link, it opened a new tab in my browser, but Selenium did not change the focus to the new tab, so it couldn't find the ID of the button I was looking for.
I solved it with :
driver.find_element_by_id("export").click() #driver
time.sleep(2)
driver.switch_to.window(driver.window_handles[1]) # Change focus to the new tab
driver.find_element_by_id("0001btn").click() #click
driver.close() #close new tab
switching to a specific frame helped me to resolve the same issue. (python + selenium)
I installed the Selenium Recorder extension on chrome and recorded my steps, and found out that the recorder had a step to select a frame = 0, so adding
self.home_page.driver.switch_to.frame(0)
self.home_page.click_on_element_by_id("clickSubmit")
solved the problem.

Interacting with VB6 client using hidden control in embedded web browser control

I'm having difficulty trapping a programmatically triggered click event on a hidden button control from a ASP.NET MVC 4 web app inside a VB6 thick client (which is using a web browser control). I'm able to trap the click event itself using the following:
Private WithEvents WebDoc As HTMLDocument
Private Function WebDoc_onclick() As Boolean
Select Case WebDoc.activeElement.iD
Case "A"
Do something
Case "C"
Do something else
End Select
WebDoc_onclick = True
End Function
And this works just fine if the control is visible. But if the control is invisible:
<div class="HideBtnDiv">
<input id="C" name="NoItems" type="button" class="BtnDiv" style="display:none"/>
</div>
and I try to trigger a programmatic click via one of the following:
$("#C").('click');
$("#C").trigger('click');
$("#C").triggerhandler("click");
$("#C").focus();
$("#C").trigger('click');
I'm getting an empty string for the "id" attribute and as a result I can't distinguish which button was clicked. This button serves no purpose other than to indicate to the VB6 app that a certain criteria has been met and that's the reason why I need it to be hidden. Does anyone have any idea why the id is getting stripped? Or is there any other way to communicate back to the client?
I've also tried filtering by element style using
Select Case WebDoc.activeElement.Style
Case "display:none"
Do something else
End Select
but it came back as "[Object]" so no luck there either. Please let me know if there is a way around this.
Thanks,
Lijin
You seem to have tried several ways of dynamically triggering the click event, but did you try the most obvious way:
$("#C").click();
???
But here is what I would do:
1- Make all of your buttons visible, by removing "display:none" from their style
2- Wrap the buttons you want to hide in a new DIV
3- Set "display:none" style in the newly created DIV
4- You can then trigger the .click() event of any button even if not visible by calling $(id).click();
Thanks, Ahmad. Actually I meant .click() not .('click'). Sorry about that.
Anyway, I tried your suggestion and made the button visible and set the style of the wrapping div to display:none but the id attribute was still coming through as an empty string.
However, I did figure out another way to get this to work. If I keep the wrapping div and button as visible and then focus and click when the condition is met and then do a hide(), my problem is resolved!
$("#C").focus();
$("#C").trigger('click');
$("#C").hide();
The button doesn't get displayed and VB6 still passes the id on the click event. The weird thing is it requires the focus() call to still be made. Without it, I'm back to square one. Not sure if this is a bug.

How to create a Like button in a "display:none" context?

The Like button plugin doesn't appear, if one of its containers is display:none when the page loads, and made visible later with display:block.
Problem detected in Firefox (my version 15.0.1) only.
What can I do?
when you make the element visible, you should add your fb like plugin to dom
IE
<div id="showfb">mouseoverme</div>
<div style="display:none" id="facebutton"></div>
<script>
var fbbutton = document.getElementById("facebutton");
document.getElementById("showfb").onmouseover = function(){
// first visible
fbbutton.style.display='block';
// then add fb html5
fbbutton.innerHTML = '<div class="fb-like" ......... ></div>';
};
</script>
in alternative, try
width:0;height:0;overflow:hidden
instead of
display:none
and
width:auto;height:auto;overflow:visible
instead of
display:block
I don't know what is the reason of this bug (FB or FF), but I've solve that problem by show my element by default in FF only:
#-moz-document url-prefix() {#exe-article-social-tools { display: block; }}
https://developers.facebook.com/docs/reference/javascript/
The fb-root tag
The JavaScript SDK requires the fb-root element to be present in the page.
The fb-root element must not be hidden using display: none or visibility: hidden, or some parts of the SDK will not work properly in Internet Explorer.
It took me an entire day to figure it out, but being logged in on Facebook with a "test user" renders the like button invisible. In my case, I was always logged in with my test user on Firefox, while logged out / logged in with my regular Facebook user in Chrome (and I initially thought this was a browser issue).
However, the solution was as easy as loggin off the test user.
It is specified in the FB docs that not all features are enabled for test users (and the like button is one of those features), but I'd thought that it would at least get rendered.
Anyway, I hope this helps someone.
I had a number of different invisible divs on my page where fb-like buttons was hidden. When one of div shown, no fb-like button appears in it. Solution worked for me is to relaunch FB.init manually each time when invisible div reveals.
FB is a global function being added into your window object since you call for remote facebook api by url like http://connect.facebook.net/en_US/all.js. So since this remote script attached to your DOM you can run something like
FB.init({
appId : '346094915460000', // App ID
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
You can dynamically add like button html5 code to the DOM and then run the FB parser again to generate the like button:
fbbutton.innerHTML = '<div class="fb-like" ... ></div>';
FB.XFBML.parse();

Resources