Automate Input Range Element in Selenium WebDriver
How to set values in the new HTML5 Range input type
The input range element is one of the “new” input types in HTML5. It consists of a slider with minimum and maximum values (and steps). Below is an example.
The default is the middle value, in this case, 3 out of the 1–5 range.
<input id="review-rating" name="review[rating]" type="range" min="1" max="5" step="1">
In test automation, we simulate the user dragging to set the desired value in automated test scripts. This article shows how it can be done in Selenium WebDriver (ruby). Here, I want to use the basic Selenium syntax, without JavaScript (i.e. driver.execute_script
).
Naive Approach: Change Value by sending the ‘RIGHT’ key
elem = driver.find_element(:id, "review-rating")
elem.send_keys(:right)
It works, the range is moved to 4.
By the same token, send_keys(:left)
works as well.
Refactor to Page Object Model
I have a habit of refactoring the raw automated test steps based on the Maintainable Test Design. The target test step will be:
review_modal_page.select_rating(5)
This means creating a function select_rating
in ReviewModalPage
:
def select_rating(the_rating)
elem = driver.find_element(:id, "review-rating")
if the_rating >= 3
(the_rating - 3).times do
puts("Move right ...")
driver.find_element(:id, "review-rating").send_keys(:right)
sleep 0.1
end
else
(3 - the_rating).times do
puts("Move left ...")
driver.find_element(:id, "review-rating").send_keys(:left)
sleep 0.1
end
end
end
Some basic coding is there to calculate how many LEFT and RIGHT keys to send to the range element. It worked.
Failed with Edit Rating
I used the same modal page for adding and editing review ratings. Naturally, I tried to reuse the ReviewModalPage
's select_review
method.
it "edit review" do
# find a course,
course_page.click_edit_review
review_modal_page = ReviewModalPage.new(driver)
review_modal_page.select_review(4)
# ...end
However, the test script fails. The reason: the calculation of sending ‘LEFT’ and ‘RIGHT’ keys is based on one assumption: the base position is 3 (the middle value). If an existing rating exists, this may not be the case.
Alternate Approach: Manually reset the slider
Reset the rating to 1 before setting the rating to the desired value.
def select_rating(the_rating)
5.times { elem.send_keys(:left) }
(the_rating - 1).times do
driver.find_element(:id, "review-rating").send_keys(:right)
end
end
It works but might be a little slower (~0.5 seconds to set 5 rating), and visually does not look natural (moving left, then moving right).
Alternate Approach: Reset the slider
Use clear
to reset the value for the slider to default (the middle value).
elem.clear
Then we could send LEFT or RIGHT keys as shown earlier.
Faster Approach: Selenium Advanced User Interactions
The problem with sending LEFT and RIGHT keys is that it is slow. Consider a rating element with many steps.
For example, it took 3.5 seconds to set a top value in the 100-step range (moved 50 steps, after clear
)
A faster is to use Selenium’s Advanced User Interactions.
elem = driver.find_element(:id, "review-rating")
elem.clear
driver.action.click_and_hold(elem).move_by(300,0).release.perform()
This version took 1.1 seconds.
This is faster, however, I don’t recommend this approach unless absolutely necessary. The value of the moving offset (in this case, 300
pixels) depends on the browser window size.
If the browser window size changes, you could see an error like below:
Selenium::WebDriver::Error::MoveTargetOutOfBoundsError:
move target out of bounds
(Session info: chrome=106.0.5249.119)