What would prevent capybara/selenium from hovering over a visible element? - ruby

I am writing automation tests for a webpage. I can't share any specific details, so all I'm looking for is some general brain-storming to help me figure out what is causing the problem. A long-shot, I know, but I've become obsessed with this problem.
There is an element with id="troublesome" on the webpage. On manual testing, hovering over #troublesome will cause it to disappear and something else pops up in its place (as it should). I'm trying to verify that the pop-up occurs on hover using automation testing (Capybara, selenium driver, ruby). However, no matter what technique I use, hovering doesn't work.
troublesome is visible upon visiting the page. It is not cut off by screen size. Capybara has no trouble finding it and reading its text and attributes. i.e. A regular ol' find("#troublesome").text will return the correct text.
However, I cannot use Capybara to click on #troublesome without executing javascript.
i.e. find("#troublesome").click won't do anything (it won't throw any errors either). I must use find("#troublesome").execute_script("this.click()") to click on it.
But I don't need to click it. I just need to hover over it.
Using Capybara:
find("#troublesome").hover --> will not work. No errors thrown either. Test just continues until it fails because it fails to find the expected result. Telling ruby to sleep(however_many_seconds) doesn't help.
Using Selenium:
page.driver.browser.action.move_to(find("#troublesome").native).perform --> this doesn't work either. Again, no errors thrown.
Using trigger:
find("#troublesome").trigger(:mouseover) --> doesn't work because selenium driver doesn't support trigger (and I don't want to use another driver).
Using jquery:
Won't work. Website doesn't use jquery
Attempting to use javascript to force :hover to be true on element doesn't work:
mouseHover = 'var x = document.createEvent("MouseEvent");
x.initMouseEvent("mouseover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
document.getElementById("troublesome").dispatchEvent(x);'
page.execute_script(mouseHover)
(I can change mouseOver to click, and it'll click though!)
Apparently, mouseover is not 'trusted' by browser (but click is), so kinda useless to have that as an option, isn't it?
I've tried all of the above by working within a within("#id") do... end block. Doesn't make a difference.
I've even tried unconventional means to get the mouse over #troublesome:
find("#troublesome").right_click --> the mouse will be DIRECTLY over #troublesome, right-click, and a menu will pop up RIGHT OVER the element!!!!!!
So CLEARLY, the mouse IS hovering over #troublesome during my automation test, yet it's not registering on the browser. The website is not bugged. Hovering works when I do it manually.
I can find other elements on the webpage and hover over them just fine. In fact, I've even tried putting the mouse over another element, then moving it from there to #troublesome like so:
page.driver.browser.action.move_to(find("#somethingElse").native, 1200, -50).perform
That doesn't work, but if I adjust the coordinates to a third element just below #somethingElse, this will trigger the third element's hover state, so clearly this strategy can work in principle and practice, yet not for #troublesome!
Note that #somethingElse and the 'third element' exist on a div that is at the same 'heirarchy' as the ancestor div of #troublesome.
There are iframes on the webpage, but #troublesome is not on the iframe.
There are random script tags inserted all over the body of the webpage. I don't know what those script tags are doing as I can't see the code.
#troublesome has become my Moby Dick.
This whale is driving me nuts. I've invested too much time into it already. I can't give up now or all those hours of toil would be for nothing.
Please help.
Thank you.
find("#troublesome").hover
page.driver.browser.action.move_to(find("#troublesome").native).perform
find("#troublesome").trigger(:mouseover)
mouseHover = 'var x = document.createEvent("MouseEvent");
x.initMouseEvent("mouseover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
document.getElementById("myDiv").dispatchEvent(x);'
page.execute_script(mouseHover)
page.driver.browser.action.move_to(find("#somethingElse").native, 1200, -50).perform
No error messages other than standard capybara/rspec failure log because it failed to find the element that was supposed to pop up upon hovering over #troublesome

The problem you're running into is because the '.hoverme' element in your example at https://jsfiddle.net/pwo7zuL2/1/ has a size of 0x0 px (this is also why you couldn't click it). The size is 0x0 because it only contains absolute positioned elements which don't technically count when calculating the auto size of the parent. If instead of attempting to hover over the .hoverme element you hover over the visible absolute positioned child (which actually has size) of the element the hover will work correctly (which is what you are actually doing when you do it manually in your example).
find('#next').hover

I now know the problem, and I have a solution (albeit a hacky one).
The problem is due to an iframe which covers the full screen. This blocks selenium from being able to hover over #troublesome even though #troublesome is not within the iframe and #troublesome's z-index is set to a high number (thereby forcing it to be at the top layer).
Manual hovering works, but hovering with selenium fails. I believe this is a bug, so I have reported it on selenium's github.
One solution that works is to use javascript to force the iframe to shrink, then hover (which should work now), then use javascript to return the iframe to full screen (so as to not affect other aspects of the test).
shrink_frame = 'document.getElementById("#frame").setAttribute("style", "width: 100px; height 100px");'
page.execute_script(shrink_frame)
This is not an ideal solution because it is obviously not how a real user would interact with the webpage, but it's acceptable given that this is due to a selenium bug and that manual testing works.

Related

Nightwatch - Meaning of WaitForElementVisible and WaitForElementPresent

Im using Nightwatch for e2e and Im finding these two command a little bit confusing given the name and explanation that comes with them.
.waitForElementVisible:
Waits a given time in milliseconds for an element to be visible in the page before performing any other commands or assertions.
What is the meaning of visible?
An element position in the footer, you need to scroll to see it, is it considered visible?
Does it mean visible in the DOM even if it is display:hidden, position:relative; left:20000px;, ...? Not actually visible for a user but dom is existing basically.
What is a modal view in on top of some content? Is it visible?
.waitForElementPresent:
Waits a given time in milliseconds for an element to be present in the page before performing any other commands or assertions.
What is the meaning of present?
Existing in the DOM without taking into account if it's visible or not?
Is there any relation/implication between these two command?
If an element return truth for .waitForElementVisible does it imply that .waitForElementPresent will return true?
A lot of questions but maybe an explanation about how they work would solve all of these small questions...
Sometimes Im just getting errors and Im thinking that it might be my bad understanding of these two commands.
What is problem with definition ? You already answer your question.
An element position in the footer, you need to scroll to see it, is it considered visible?
No,you dont need to scroll to check it visible or not.May be you do need with some command but not with these visible/present commands.
Does it mean visible in the DOM even if it is display:hidden, position:relative; left:20000px;, ...? Not actually visible for a user but dom is existing basically.
Yes,it exists(means present) in the DOM but for some reason it is not visible yet
(bad connection,attribute value,...).
If an element return truth for .waitForElementVisible does it imply
that .waitForElementPresent will return true?
yes it will, if an element is visible = > it is present.
For usage , you can check out my an example answer here,it might help .
Login timeout
Basically an element might be present (as in loaded in DOM) but not visible (e.g. out of view so you might need to scroll to see it, or it might be hidden).
If you want to perform an action like a click on an element then you want to be using 'visible'.

Firefox scrollbar resets incorrectly

I've come across a problem in Firefox browser. It's likely a bug, but maybe someone knows a workaround. The problem is demonstrated in the following JSFiddle: http://jsfiddle.net/F5tdB/ This has been tested on Firefox 12.0, 15.0.1, 16.0.1.
To explain it in words... You have to follow this sequence of events:
Get an element with overflow:auto and some overflowing contents, then scroll it a bit;
Hide the element (display: none);
Remove contents
Show the element (it's empty now)
Re-add the same contents (it's scrolled now, just as it was before)
Reset scrollTop/scrollLeft to 0 via Javascript.
As a result, the contents do get scrolled to the proper position, but the scrollbar stays as it was, which is clearly wrong.
Is there any workaround to this short of removing/re-adding the element instead of just hiding it?
In testing I discovered that if you set scrollTop to any value other than 0 (or its current value) then it updates the scrollbar correctly. You can then immediately set scrollTop to 0.
Particularly as you have a test case you should of course file a bug in Bugzilla.
Solution is add the animate method, so use:
function resetScroll(){
$(document).scrollTop(1); // removes the impression of animation
$('html,body').animate({scrollTop:0},'fast','linear');
}

Cluetip popup windows getting cutoff by browser

jQuery('area').cluetip({
sticky: true,
positionBy: 'auto',
width:370,
dropShadow:false,
closePosition: 'top',
closeText: '',
activation: 'click'
}
Straight to the point: when i click to activate popup windows, it's always at the right handside of where i click, even when there is not enough space. So for those it only shows some part to the cluetip as the rest is getting cutt off by browser window??
I am totally new to php and cluetip...
About the only thing that can be done, by the looks of things, is use the positionBy parameter. But it doesn't work really in determining if the tip is cutoff, I have tried many cases myself.
The options are auto, mouse, bottomTop, fixed, but none of them work really, they all get cut off.
The only solution I found myself was to use fixed and set top and left manually and always have it in the same place.
j('.areaH').cluetip({
positionBy: 'fixed',
topOffset: 200,
leftOffset: 100
});
Unfortunately though you are stuck at that place holder. I guess you could take the action and to each thing that calls a cluetip call a wait segment of 1 second then re-position the cluetip window using jQuery.
This would be in an onHover event set off by the thing that calls the cluetip separately. But that's about it. I have tested this myself on FF and Chrome and in both it cuts off.
http://plugins.learningjquery.com/cluetip/#features
In the onHover event you can always use another jQuery plugin that waits for an element to exist then re-position, what you can do is in each element have your own attr that has the new position, or just call the elements left and top position using jQuery and move the Cluetip window to that +20 in each direction.

Can the like button (with comments prompts) exist inside a carousel?

I have a sliding carousel of items, each of which includes its own like button. I want the like buttons to have comments; that is, when the user clicks Like, he should be presented with a prompt to leave a comment (http://developers.facebook.com/blog/post/397/). I'm starting to doubt that these goals are compatible and would like to hear if anyone has already achieved it.
The comments on the Like buttons are wider than the items in the carousel, and correctly overflow onto other carousel items. However, some of these items are outside the clipping box, since the carousel items are necessarily inside a div with overflow: hidden (otherwise we wouldn't achieve the effect of the items scrolling into existence upon paging). Because of this, if I click Like on the rightmost item currently visible, the comments prompt that appears will be partially outside the clipping box and thus partially visible.
It appears to me the only possible hope of allowing the comments prompt to overflow the carousel container is to place the prompt outside the container in the dom. This way, assuming we can visually position the prompt next to its Like button where it belongs, it's no longer constrained by the container. This seems within possible, since at the time of this writing the comment prompt is implemented as a separate iframe from the button itself; i.e., this XFBML:
<fb:like width="450"></fb:like>
yields (approximately) this HTML:
<iframe src="facebook.com/like_button.php"></iframe>
<iframe src="facebook.com/comments_widget.php"></iframe>
But if I try to move the comments iframe in the dom, it instantly and permanently becomes empty. Even if I could find a way to detach certain events and prevent this, it shows that an intricate solution is called for, and one which Facebook can break at any time in the future with changes to their implementation. Thus, I can't move the comments in the dom, and thus, the prompt is always in danger of being clipped. Facebook says this on the subject:
If the Like button is placed near the edge of an HTML element with the overflow property set to hidden, the flyout may be clipped or completely hidden when the button is clicked. This can be remedied by setting setting the overflow property to a value other than hidden, such as visible, scroll, or auto.
Clearly in the case of a carousel it's not possible to remove overflow: hidden. Has anyone found a way around this, or should I give up and spend my time elsewhere?
Thanks

jScrollPane in Firefox - Dragger fills entire bar and doesn't scroll

My jScrollPane (division) works well in IE and Chrome. It may be of some significance that I am also running JQuery MouseScroll and hoverintent. Again, these functions work fine in IE and Chrome.
The division is displayed properly in Firefox, as is the vertical scrollbar. There's about 50 lines to scroll down through.
In Firefox, the dragger fills the entire length of the vertical bar and doesn't move. The dragger and the arrows do respond to mouseover, but the functions don't work.
Perhaps the scrolling action is functional, just that there is no space to scroll, because the dragger fills the entire region. I am unsure whether my jScrollPane works or doesn't in Opera or Safari.
I checked Google and found little directly associated advice, just to:
"Ensure that the division has a height specified (it does) and to try refreshing (no luck) in case the content (only text) needs to pre-load."
I wonder whether anyone can suggest any checks for me to make from their previous experience before I post any code to wade through.
This is only the second question tagged with jScrollPane & Firefox, so perhaps no-one will be familiar with this 'bug'. In which case I will create and post some reduced code which generates this bug in Firefox but not IE or Chrome.
Update: I created a 'test' scrollbar webpage to see if the bug would be replicated, and that works fine - so no need to post that for error-checking.
The problem must lie somewhere within my code on the site I'm working on.
So far I have identified that all the JavaScripts work and my custom jScrollPane CSS is fine. So it's just a process of elimination through each of the stylesheets now. I have a feeling the source of the bug may be in my custom reset CSS.
I'm confident I'll fix the bug, and will let you folks know either way.
The bug was in the CSS reset as suspected. Specifically, with the rule for column-count.
I had defined them (moz-/wekbit-/column-count) as '1' instead of the defining as 'auto' / not defining it at all.
This was from when I was experimenting with (CSS3) multi-column text. Presumably jScrollPane requires multiple columns. Not enough support yet for multi-column text to be worth implementing yet IMO.

Resources