Using Rspec/Capybara/Selenium to interact with a canvas element - ruby-on-rails

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

Related

Ferrum mouse.up doesn't work for click & drag method

I'm writing a test which runs over Cuprite::Ferrum, where I need to click, drag and drop an element below another element on the page. Which works fine while I am doing it manually, but when i try to put it in a test, it almost work, but not quite.
I was unable to find he drag and drop API for Ferrum or Cuprite, so I created something like:
def click_and_drag(draggable, droppable, offset_x, offset_y)
x1, y1 = draggable.native.node.find_position
x2, y2 = droppable.native.node.find_position
mouse = page.driver.browser.mouse
mouse.move(x: x1, y: y1)
mouse.down
mouse.move(x: x2 + offset_x, y: y2 + offset_y)
mouse.up
end
Pretty simple and works fine until it get to the mouse.up part. The element that needs to be picked up is found by the draggable = page.find(element), and it needs to be dropped below the droppable = page.find(element).
Everything is going great until the method gets to the mouse.up part, where the dragged element should be dropped and put in it's new place, but it just goes back to it starting position.
I am referring to the Ferrum doc https://www.rubydoc.info/gems/ferrum/0.5/Ferrum/Mouse but cant seam to find the answer.
So, the method works and all is well, the problem was with offset_x and offset_y, if you somehow find this and want to use it, keep it in mid, and keep them small!

Simulate mouse movement with 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.

Cannot get Highcharts solidgauge stops to work in styled mode

I am converting all the charts in an application to Highcharts 5.x styled mode.
I cannot find how to make the solidgauge stops work in styled mode. When I inspect the SVG, I do not see any class for the colors.
I couldn't find any solidgauge stops example with styled mode.
Anyone can post a working example?
In a solid gauge series color is calculated dynamically based on stop values - currently, I do not think you can do the same with only css. The point fill atribute is calculated and set correctly but in this case css class takes precedence and the point's color has a fixed fill taken from the css file (highcharts-color-{n} class).
Keep stops in options and remove class from the point (or set colorIndex to a non existing number, e.g. 99)
.highcharts-color-0 {
fill: #7cb5ec; //remove fill attribute
stroke: #7cb5ec;
}
or:
data: [{y: 80, colorIndex: 99}], // the point's class will highcharts-color-99 now
example: http://jsfiddle.net/gj8zfw73/

jquery se resizable handle separates

I want to resize a textarea in IE in a manner similar to the built in resize in FF and Chrome. So I have applied the jquery ui resizable to the textarea using an se handle. All is good when expanding the textarea. But when reducing the size of the text area somehow the handle gets separated from the corner of the textarea. Like this:-
I am thinking that perhaps some combination of delay and distance could solve this. But the basic demos don't appear to employ these options and their handles don't get separated. So I am beginning to doubt if I am on the right line. Thus far my tinkering with the options has not been successful.
Any thoughts gratefully received.
This is probably NOT the correct answer but it works so I am good for now.
By restricting the expand to the vertical plane only I stopped this behaviour.
$("document").ready(function() {
if ($.browser.msie){
$("textarea").resizable({
handles: "se", maxWidth: 465, minWidth: 465, maxHeight: 350, minHeight: 22
});
}
});
Obviously it is possible to expand in any direction as given in the demos. When a little more time I may review this again.

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.

Resources