How do I know which element has the focus? - ruby

How do I know which element has the focus, or how to determine whether the focus of a particular element?

I don't know of anyway to query for this kind of information directly. I suppose you could traverse the DOM and check for it manually. If that's the case you should look at this.
Perhaps what you are trying to do can be achieved by handling an event when specific elements of interest gain focus. Here is how you would do that in jQuery.
$('<selector>').focus(function() {
// Do something here
});
Just for giggles, here is one way you could use the focus method to track which element recieved it last. I highly recommend against using this code.
var gotDaFocus;
$('*').focus(function() {
gotDaFocus = this;
});

not yet implemented yet i'm afraid.
You could do something like this
Shoes.app do
#focused = para ""
stack do
#label1 = edit_line :text => 1
click do
#focused.replace #label1.text
end
end
stack do
#label2 = edit_line :text => 2
click do
#focused.replace #label2.text
end
end
end
But the problem in windows is that the controls steal all the event from Shoes.
In Green Shoes it would work. If you'r in windows you can still see the result if you click just to the right of the edit_line. Of course, this is only when you click with the mouse, you should check keypress tot get the keyboard events also.
Grtz

Related

ruby shoes: create modal window

Is there an attribute to create a modal window e.g. one that has complete focus.
we cannot use confirm/alert etc. and i'm assuming i create a window/dialog, but its asynchronous and exits after creation?
i.e. something like
dialog :title => '', :modal=>true do
googled, been through all ruby manuals and no reference to modal/focus?
checked out the source code and had a look for modal/keep focus type parameters - couldn't find anything?
i've come across suggests for Ruby/Tk (similar type of stuff) where people have to wait in a loop for close events and exit. this seems a bit cumbersome?
any thoughts out there?
thanks
Ben
Not entirely sure what you are trying to do here. Are you trying to launch another window alongside the main window? That is well supported:
Shoes.app do
para 'first app'
button "launch second" do
Shoes.app width: 180, height: 60 do
para 'I am a second app!'
end
end
end
Although that is an entirely new window, so it might not be what you want. If you want an all focus window that is essentially part of the app and greys out the main application, then no that is not possible :( Created an issue for modals though.

Separating single clicks from click and hold

I need to implement a behavior:
when element clicked - one thing happens
but when it's clicked and held for more than one second, something else happens (e.g element becomes draggable) and then the first event never fires
I think I know how to catch click&hold type of events, but how to distinguish between first and second?
Can you show me how to do that using this jsbin. I already made the "click, hold & drag" part, except that it is still firing the 'click' event after dragging the element and it shouldn't.
again: element clicked - one event, click and hold - element is draggable (even after mouse up) and when clicked again it's back to normal (undraggable) state.
I am not looking for a trivial solution, it has to be built using Rx.Observable or at least Bacon's streamEvent object
Thank you
I think you were pretty close with your solution, but probably it is not possible to elegantly achieve what you want while using the browser's built-in click event.
HERE is my attempt to tackle your problem.
The main idea is to define your own click streams like so:
var clicks = downs.flatMapLatest(function(){
return ups.takeUntil(Rx.Observable.timer(250));
});
var longDownsStart = downs.flatMapLatest(function(){
return Rx.Observable.timer(1000).takeUntil(ups);
});
In case of clicks we wait max 250 ms after a mouse down for a mouse-up; in case of the latter we generate the event only if there was no mouse-up within 1000 ms.
There might be some corner cases in which the code does not work as intended.
Here is my proposed solution (with Bacon.js).

selenium scroll element into (center of) view

When an element is out of view with selenium and one tries to interact with it, selenium will usually scroll the element into view first implicitly. This is great except that what is annoying is that it usually puts in the element just enough into view. What I mean is that if the element is below the window, it will scroll down enough just till when the element is just bordering the edge of the window.
Usually this is fine, but when working on a web site with borders around it, this will lead to numerous of these kinds of errors
Selenium::WebDriver::Error::UnknownError:
unknown error: Element is not clickable at point (438, 747). Other element would receive the click: <body>...</body>
Because usually the border of the web page is over it, but will try to click the element anyway. Is there anyway handle this? perhaps to automatically move elements to the center of the screen when out of view? I am thinking along the lines monkey-patching via ruby.
This should work in order to scroll element into center of view:
WebElement element = driver.findElement(By.xxx("xxxx"));
String scrollElementIntoMiddle = "var viewPortHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);"
+ "var elementTop = arguments[0].getBoundingClientRect().top;"
+ "window.scrollBy(0, elementTop-(viewPortHeight/2));";
((JavascriptExecutor) driver).executeScript(scrollElementIntoMiddle, element);
Yes, it is possible to automatically scroll the browser such that any element we interact with gets centered in the window. I have a working example below, written and tested in ruby using selenium-webdriver-2.41.0 and Firefox 28.
Full disclosure: You might have to edit parts of your code slightly to get this to work properly. Explanations follow.
Selenium::WebDriver::Mouse.class_eval do
# Since automatic centering of elements can be time-expensive, we disable
# this behavior by default and allow it to be enabled as-needed.
self.class_variable_set(:##keep_elements_centered, false)
def self.keep_elements_centered=(enable)
self.class_variable_set(:##keep_elements_centered, enable)
end
def self.keep_elements_centered
self.class_variable_get(:##keep_elements_centered)
end
# Uses javascript to attempt to scroll the desired element as close to the
# center of the window as possible. Does nothing if the element is already
# more-or-less centered.
def scroll_to_center(element)
element_scrolled_center_x = element.location_once_scrolled_into_view.x + element.size.width / 2
element_scrolled_center_y = element.location_once_scrolled_into_view.y + element.size.height / 2
window_pos = #bridge.getWindowPosition
window_size = #bridge.getWindowSize
window_center_x = window_pos[:x] + window_size[:width] / 2
window_center_y = window_pos[:y] + window_size[:height] / 2
scroll_x = element_scrolled_center_x - window_center_x
scroll_y = element_scrolled_center_y - window_center_y
return if scroll_x.abs < window_size[:width] / 4 && scroll_y.abs < window_size[:height] / 4
#bridge.executeScript("window.scrollBy(#{scroll_x}, #{scroll_y})", "");
sleep(0.5)
end
# Create a new reference to the existing function so we can re-use it.
alias_method :base_move_to, :move_to
# After Selenium does its own mouse motion and scrolling, do ours.
def move_to(element, right_by = nil, down_by = nil)
base_move_to(element, right_by, down_by)
scroll_to_center(element) if self.class.keep_elements_centered
end
end
Recommended usage:
Enable automatic centering at the start of any code segments where elements are commonly off-screen, then disable it afterward.
NOTE: This code does not seem to work with chained actions. Example:
driver.action.move_to(element).click.perform
The scrolling fix doesn't seem to update the click position. In the above example, it would click on the element's pre-scroll position, generating a mis-click.
Why move_to?
I chose move_to because most mouse-based actions make use of it, and Selenium's existing "scroll into view" behavior occurs during this step. This particular patch shouldn't work for any mouse interactions that don't call move_to at some level, nor do I expect it to work with any keyboard interactions, but a similar approach should work, in theory, if you wrap the right functions.
Why sleep?
I'm not actually sure why a sleep command is needed after scrolling via executeScript. With my particular setup, I am able to remove the sleep command and it still works. Similar examples from other developers across the 'net include sleep commands with delays ranging from 0.1 to 3 seconds. As a wild guess, I would say this is being done for cross-compatibility reasons.
What if I don't want to monkey-patch?
The ideal solution would be, as you suggested, to change Selenium's "scroll into view" behavior, but I believe this behavior is controlled by code outside of the selenium-webdriver gem. I traced the code all the way to the Bridge before the trail went cold.
For the monkey-patch averse, the scroll_to_center method works fine as a standalone method with a few substitutions, where driver is your Selenium::WebDriver::Driver instance:
driver.manage.window.position instead of
#bridge.getWindowPosition
driver.manage.window.size instead of
#bridge.getWindowSize
driver.execute_script instead of
#bridge.executeScript
The following code will scroll until the element is in view,
WebElement element = driver.findElement(By.id("id_of_element"));
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);
Thread.sleep(500);
//do anything you want with the element
You could use an explicit scroll action via javascript here. In that case you would find the element (this part works already if I understand your question correctly), then scroll the window to a specified position, and then interact with the element.
In java that would be:
WebElement element = driver.findElement(By.id("tabs")).findElement(By.className("youarehere"));
Point p = element.getLocation();
((JavascriptExecutor) driver).executeScript("window.scroll(" + p.getX() + "," + (p.getY() + 200) + ");");

How can I automate a slider using watir-webdriver and ruby?

I am trying to automate a Jquery UI slider using watir-webdriver and ruby but am having no luck. I want to be able to manipulate the slider to either increase or decrease the value. I have searched everywhere and asked a few of my colleagues but no one has an answer. I am attaching a piece of HTML code for the slider. Any help would be much appreciated.
URL link: http://www.whatcar.com/new-car-deals/ (price range slider)
I haven't done any coding for the slider as I have no idea how to go about it. If I could be set on the right path that would be fantastic. Also it seems the HTML code doesn't seem to be showing on the question I am asking.
it's a Jquery widget that appears (looking at the scripts) to respond to key presses once one of the handles has been clicked on. the handles are link objects, inside a pair of divs, the outer one has the ID value 'slider-range'
You should be able to address them via browser.div(:id => 'slider-range').link(:index => n) where n = 0 for the lefthand one and n=1 for the right hand one.
Try this manually first
Click on the left handle for the slider
Then press arrow keys on the keyboard.. it will move 1K(pounds) up or down with each right or left arrow keypress.
Once you have moved it right, click the Home key and it should reset to its min value
repeat above for the right handle but reset it to far right using the End key.
In theory you could fire a click event at the right slider to get focus, then fire off some keypress events to first set it far right (end) followed by enough left arrows to move it down to the top value you want.
Repeat for the left handle, setting it to the left end with the home key, and moving it with right arrow keypresses
I don't have the time right now to experiment further and develop an exact script, but I think you could probably create two little functions even that took an upper and lower range value and did the required number of keypresses to move the lower up from 5K to the right amount, and the upper down from 100k
Note that this thing is very very event driven, it responds (at least when watching the dev tools while playing with it) to being moused over, mousedown, mouseup, etc.. if using click does not work to 'get the attention' of the control so it will respond to keypresses, try using the onmousedown event instead.
Using the code from your answer, to move the left slider to 12K I'd try
browser.div(:id => 'slider-range').link(:index => 0).click #make sure it has focus
browser.div(:id => 'slider-range').link(:index => 0).send_keys :home #set to 5K
7.times do
browser.div(:id => 'slider-range').link(:index => 0).send_keys :arrow_right
end
Thank you very much Chuck. I got it working. Here is the script I used:
#browser.link(:xpath, "/html/body/div/div[3]/div[4]/div/div/div/a").send_keys :arrow_right
Still needs a bit of tweaking, but I should be ok now.
This worked great. We just added these sliders to our website and my first thought was "how are we going to automate that!?"
I wanted to add an example will full code that is available publicly for people to experiment with. The following interacts with an example on jqueryui.com.
require "watir-webdriver"
#browser = Watir::Browser.new :chrome
#browser.goto "http://jqueryui.com/slider/#default"
#browser.frame(:class => "demo-frame").span(:class =>"ui-slider-handle").click
#browser.frame(:class => "demo-frame").span(:class =>"ui-slider-handle").send_keys :home
puts "clicked home"
7.times do
#browser.frame(:class => "demo-frame").span(:class =>"ui-slider-handle").send_keys :arrow_right
end
To achieve this using Rspec and Watir-Webdriver with Page-Object gem I used:
div(:slider, id: "slider-range") #in page file
#then in spec file
browser.slider_element.input.send_keys :home
This answer comes from http://watir.com/guides/special-keys/

how to scroll with selenium

I have here a challenge that I spent some time addressing.
Selenium tells me that it cannot click a link that is not visible, so that means I need to scroll my canvas? I am using ubuntu 10, firefox 3, selenium 0.1, ruby 1.9.2, and selenium-webdriver 2.5.0
My code is
driver = Selenium::WebDriver.for :firefox;
driver.get login_url
wait = Selenium::WebDriver::Wait.new(:timeout => 2)
wait.until {
driver.find_element(:name => 'j_password')
}
driver.find_element(:name => 'j_username').send_keys(username)
driver.focus(:name => 'j_username')`
and it says that focus() is not defined. How should I modify my code to put the input element on screen?
Um, this is a hypothetical example, I really need to scroll so that some other element is on the screen, but for simplicity I would like to be able to scroll s.t. any element is on the screen, even
location_once_scrolled_into_view to scroll using ruby.
As per your question your element is not visible, so selenium web driver is unable to click on it.
Simple solution to this is:
Store the xpath of the element which is visible and nearby to your element.
Scroll till that visible element, to make your element visible.
Ensure your element is now visible, click on it
eg code:
element = dirver.find_element(:xpath, "xpath of nearby visible element")
element.location_once_scrolled_into_view
my_element = driver.find_element(:xpath, "xpath of your element")
my_element.click
I had an element at the bottom of the page with no other element close enough to select first. Finally got around it by tabbing from the last field in the form on the page.
element.send_keys(:tab)
When the documentation says "not visible" it's not refering the view port, but to the status of the element on the page. If something is hidden with CSS it cannot be clicked.
If you want to scroll on the firefox window using selenium webdriver, one of the way is to use javaScript in the java code, The javeScript code to scroll down is as follows:
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("window.scrollTo(0,Math.max(document.documentElement.scrollHeight," +
"document.body.scrollHeight,document.documentElement.clientHeight));");
I'm not aware of ruby but the above code can be used as a java Script which will scroll down the whole page.You can even define the area you want to scroll in the view window by simply hard- coding the window.scrollTo(200,350);

Resources