Simulate mouse movement with Capybara - capybara

I would like to demonstrate onscreen mouse movements when running Capybara tests. I have had a request to make the mouse movements a user would make visible, in addition to running through data points etc. Is there a way of doing this?

This isn't directly supported in any Capybara drivers I know of, however you can fake the mouse pointer with some JS as shown at Visualize / Show mouse cursor position in selenium 2 tests (for example PHPUnit Webdriver)
Basically it boils down to creating an image and then moving its location every time a mousemove event occurs
// Create mouse following image.
var seleniumFollowerImg = document.createElement("img");
// Set image properties.
seleniumFollowerImg.setAttribute('src', 'data:image/png;base64,'
+ 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAQAAACGG/bgAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAA'
+ 'HsYAAB7GAZEt8iwAAAAHdElNRQfgAwgMIwdxU/i7AAABZklEQVQ4y43TsU4UURSH8W+XmYwkS2I0'
+ '9CRKpKGhsvIJjG9giQmliHFZlkUIGnEF7KTiCagpsYHWhoTQaiUUxLixYZb5KAAZZhbunu7O/PKf'
+ 'e+fcA+/pqwb4DuximEqXhT4iI8dMpBWEsWsuGYdpZFttiLSSgTvhZ1W/SvfO1CvYdV1kPghV68a3'
+ '0zzUWZH5pBqEui7dnqlFmLoq0gxC1XfGZdoLal2kea8ahLoqKXNAJQBT2yJzwUTVt0bS6ANqy1ga'
+ 'VCEq/oVTtjji4hQVhhnlYBH4WIJV9vlkXLm+10R8oJb79Jl1j9UdazJRGpkrmNkSF9SOz2T71s7M'
+ 'SIfD2lmmfjGSRz3hK8l4w1P+bah/HJLN0sys2JSMZQB+jKo6KSc8vLlLn5ikzF4268Wg2+pPOWW6'
+ 'ONcpr3PrXy9VfS473M/D7H+TLmrqsXtOGctvxvMv2oVNP+Av0uHbzbxyJaywyUjx8TlnPY2YxqkD'
+ 'dAAAAABJRU5ErkJggg==');
seleniumFollowerImg.setAttribute('id', 'selenium_mouse_follower');
seleniumFollowerImg.setAttribute('style', 'position: absolute; z-index: 99999999999; pointer-events: none;');
// Add mouse follower to the web page.
document.body.appendChild(seleniumFollowerImg);
document.addEventListener('mousemove', function(e) {
const mousePointer = document.getElementById('selenium_mouse_follower');
mousePointer.style.left = e.pageX + 'px';
mousePointer.style.top = e.pageY + 'px';
});
You would then need to make sure that JS gets executed after every page change (visit, click that navigates, etc). There are many ways you do that, with the simplest being either conditionally add the code to your app in test mode or calling it manually with a helper method calling page.execute_js whenever you want the mouse position to be shown for the next actions.

Related

trying to create a bounding box by click and drag in a web component

I am dealing with event handlers, and getting the start and end position of a mouse.
That way i can create a selection box.
I start by on mousedown, i store the current position: new Point(event.target.clientLeft, event.target.clientTop); which seems to work for that location when i set the selection div accordingly.
The next step is where everything seems wrong. While in the mousemove event, I am trying to get the coordinates of the mouse do i can use the difference to define the Height and Width of the bounding box. It seems that everything is off by the coordinates of the web component i had created.
How should I go about this?
I have been dabbling with the event more, trying to get the position of the mouse, but i think what happens is that my start point is in reference to the webcomponent I created, and not the absolute position.
Has anyone else figured out how to do this correctly, because I have been setting things as absolute, but not correctly rendering.
As a side note, if i could subtract the absolute position of the webcomponent this is in, i think it should render the height and width correctly.
You might have an easier time using global position information rather than target-relative position. You can get the global position point from a MouseEvent directly with event.screen.
since a PolymerElement will use HtmlElements, you will have access to a full suite of functions built into the application. For example:
var top = selectedHtml.getBoundingClientRect().top - getBoundingClientRect().top + selectedHtml.clientHeight;
var left = selectedHtml.getBoundingClientRect().left - getBoundingClientRect().left + selectedHtml.clientWidth;
Point coord = new Point(left,top);
then you can just determine the distance from that point to get your width/height:
var top = selectedHtml.getBoundingClientRect().top - getBoundingClientRect().top + selectedHtml.clientHeight;
var left = selectedHtml.getBoundingClientRect().left - getBoundingClientRect().left + selectedHtml.clientWidth;
var h = top - coord.y;
var w = left - coord.x;
and then apply it to your Div.
_item.style.top = top;
_item.style.left = left;
_item.style.width = w;
_item.style.height = h;

How to tell if series is in upper chart or lower chart in tooltip (using highstock)?

I'm using highstock to plot two panes at once.
My data are several series, each series contains two different metrics, metric A goes to upper and metric B goes to lower. Different colors are different series. I also use crosshair to connect upper/lower charts together.
When using custom HTML tooltip, I set shared to true so in tooltip I could access this.points for all currently visible series, and showing different info in tooltip based on it's metric A or B.
The problem is series visibility could be toggled by clicking on the legend, but in this.points, I don't know how to distinguish point = this.points[i] is in upper chart or lower chart.
Each point = this.points[0] has a series.chart property, but I don't know which property could be used to distinguish them. The series.chart.yAxis doesn't look like what I want.
Any help?
I used d.series.yAxis.userOptions.index to specify the index of the pane the point is on:
if(d.series.yAxis.userOptions.index == 0)
html += '<h4 style="color:red"> Volume(' + d.series.name + '): </h4><h5>' + d.point.y + '</h5><br />';
else if(d.series.yAxis.userOptions.index == 1)
html += '<h4 style="color:blue"> OHLC(' + d.series.name + '): </h4><h5>' + d.point.y + '</h5><br />';
You can also use other properties in d.series.yAxis to specify the difference between the panes: DEMO

Using Rspec/Capybara/Selenium to interact with a canvas element

I have an HTML5 canvas element that triggers different actions depending on where it is clicked.
Is there any way I can simulate this behavior in my test specs using Capybara
Had a look at the click code on Capybara & noticed you can pass x & y co-ordinates to where you want to click: https://github.com/teamcapybara/capybara/blob/8f86f46d2c486aa27045f853ff7696f5aa34dcf4/lib/capybara/node/element.rb#L157-L174
This is working for me on capybara:
page.find('#canvas-id').click([], { x: 50, y: 80 })
Looking at this: http://selenium.googlecode.com/svn/trunk/docs/api/rb/Selenium/WebDriver/ActionBuilder.html
You can use ActionBuilder to do what you need.
move_to will put the cursor in the middle of the element, you'll need to change the offsets based on that.
driver.action.move_to(element, xOffset, yOffset).
click().
perform

How to make css3 scaled elements draggable

I've noticed that the CSS3 scale attribute does really bad things to jquery ui, specifically to sortable. The problem is that the mouse still needs to move as much as if the elements were not scaled. Check out this jsfiddle example.
Does anybody have thoughts on how to fix this? Is it possible to change the speed that the mouse moves? I'm going to look into the html5 native drag and drop next, and try to write my own sortable function.
UPDATE:
Jquery ui draggable works ok with CSS3 scaled elements, here is a fiddle for it.
It turns out the real answer does not require writing special move functions. Jquery ui sortable can be used as long as the items being sorted have been wrapped in a div of the appropriate size with overflow hidden. Check this jsfiddle for an example.
The problem was that I had forced the scaled divs to be close to one another using a negative margin. Then when I started to drag an item it was taking up the wrong amount of space. With the scaled item wrapped in a non-scaled div everything works as expected.
I don't have a solution for working with jquery ui but I do have a solution for working with Raphael and by extension other svg objects.
First, using chrome or firefox, go drag the dots around in this jsfiddle. Be sure to drag both dots and to use the slider at the bottom to change the scale of the box. The slider has a default scale range of .4 to 1.2. In Chrome the slider is actually a slider but in Firefox it shows up as a textbox. If you are using firefox enter values that are 100 x the scale, i.e. 70 => 0.7.
What you should have just experienced is that the black dot tracks with the mouse regardless of the scale and the red dot only tracks when the scale is 1.0.
The reason for this is the two dots are using different 'onMove' functions. The black dot moves according to 1/scale while the red dot moves normally.
var moveCorrected = function (dx, dy) {
// move will be called with dx and dy
this.attr({
cx: this.ox + (1/scale)*dx,
cy: this.oy + (1/scale)*dy
});
}
var move = function (dx, dy) {
// move will be called with dx and dy
this.attr({
cx: this.ox + dx,
cy: this.oy + dy
});
}
So, in answer to my original question. You can't (and shouldn't) be able to change how the mouse moves, that is clearly user defined behavior, but you can change the move function of the object being moved to track with the mouse.

jquery.position() isn't working correctly

I'm working on a menu system where I want a ul to show as a dropdown when the users does a mouseOver on li in another ul. I thought I'd use position to set the position of the dropdown (so it actually looks like a menu). What I want is the dropdown's top left corner to start at the same place as the bottom left corner of the wrapping listitem.
Unfortunately the positioning fails in several different ways:
In Firefox it seems like the dropdown's are offset with approximately -100 25 pixels
the first item in the list has a different offset on the left side compared to the other items
The offset in IE is not the same as in FF
Doing the positioning repeatedly in explorer results in different positions each time.
I've created a test page where you can see the effects:
http://test.evju.biz/test/test_position.html
We've solved it by not using the jquery.ui.position. Here is the code we ended up using:
$(this).find("ul.subnav").first().css({
left: $(this).position().left + 'px',
top: ($(this).position().top + $(this).height()) + 'px'
});

Resources