I'm working on a Rails 3 application with Cucumber 1.1.1 and I'm trying to select multiple checkboxes in my cucumber scenarios.
Here is my multiple checkboxes in haml:
- for diocese in Diocese.all
= check_box_tag "clergy[diocese_ids][]", diocese.id, #clergy.dioceses.include?(diocese)
= f.label diocese.name
%br
Here is my cucumber step
When /^I check the (\d+)(st|nd|rd|th) of the "([^"]*)" checkboxes$/ do |index, junk, group|
page.all("input[id=\"clergy_diocese_ids_\"]")[index.to_i - 1].check('clergy_diocese_ids_')
end
Here is my cucumber test:
#wip
Scenario: New Clergy
Given I am on the clergies page
When I follow "New Clergy"
And I fill in "Surname" with "Wells"
And I fill in "Given names" with "Robin"
And I check the 1st of the "diocese" checkboxes
And I check the 2nd of the "diocese" checkboxes
And I press "Create Clergy"
Then I should see "Clergy was successfully created."
The error I get when running my test:
And I check the 1st of the "diocese" checkboxes # fea
tures/step_definitions/clergy_steps.rb:37
cannot check field, no checkbox with id, name, or label 'clergy_diocese_ids_' found (C
apybara::ElementNotFound)
./features/step_definitions/clergy_steps.rb:38:in `/^I check the (\d+)(st|nd|rd|th) of
the "([^"]*)" checkboxes$/'
features/clergy_new.feature:17:in `And I check the 1st of the "diocese" checkboxes'
I've tried playing around with the page.all selector but I cannot work it out.
As I understand it, its not the job of Cucumber to select checkboxes and interact with the UI. Cucumber parses the feature files and executes the corresponding step definitions that match. What you put in each step definition block is up to you.
Since your step definition code appears to be using Capybara, I suggest viewing this solution.
Related
I am working with Behave framework in Python, which i have not used before, and I am not sure how I can click on an element_by_id. There is a cookie popup that I need to get around before I can send login keys.
This is my .features file:
Feature:
Login Functionality
Scenario: I can login
When visit url "https://example.com"
When I click on the button "accept-cookie-notification"
When field with name "user_email_login" is given "#gmail.com"
When field with name "user_password" is given "password"
Then title becomes "Dashboard"
Here is my .py file:
Steps
#when('visit url "{url}"')
def step(context, url):
context.browser.get(url)
time.sleep(5)
#when('I click on the button "{selector}"')
def step(context, selector,):
elem = context.driver.find_element_by_id("selector")
elem.submit()
time.sleep(5)
#when('field with name "{selector}" is given "{value}"')
def step(context, selector, value):
elem = context.browser.find_element_by_id(selector)
elem.send_keys(value)
elem.submit()
time.sleep(5)
#then('title becomes "{title}"')
def step(context, title):
assert context.browser.title == title
Also I will need to do element_by_css and xpath later on.
Thank you in advance for any help.
Working with Selenium is very simple if you are using Behave. Just install behave-webdriver package https://pypi.org/project/behave-webdriver/ It's a step library with a wide set of already defined steps with given-when-then decorators like: I click on the element "{element}" and you can use both id,css and XPath as {element} parameter. You do not need to implement anything, just use predefined steps in your scenarios. Here are my code examples:
Scenario: A user can log in.
Given the base url is "http://my_site:3000"
And I open the site "/#/login"
And the element "#email" is visible
When I add "my#email.com" to the inputfield "#email"
And I add "1234567" to the inputfield "#password"
And I click on the button "#loginButton"
Then I wait on element "//nav-toolbar//span[contains(text(),'Myself')]" to be visible
And I expect that the attribute "label" from element "#loggedUser" is "Finally, we made it!"
And please do not forget to add handling context.behave_drive in your environment.py methods before_all() and after_all() as described in the HOWTO page above.
What you need is read some documentation about, try to take a look on something like taht where you have the most common commands
http://allselenium.info/python-selenium-commands-cheat-sheet-frequently-used/
I am writitng request spec for my rails app with capybara. In my code I have something like:
%table
%tbody
%tr{"on_click" => "location.href='some_link'"}
%td="Some attribute"
%td="Some attribute"
%td="Some attribute"
%td="Some attribute"
This way I make the entire row clickable. I want to write a request spec with capybara for this feature but I don't know how. Can anyone help me on this ?
Thank you
May be you should first get to know the testing in rails. Check this out! http://railscasts.com/episodes/275-how-i-test it is really helpful. You can give your tr a class (say) .tr and do
page.find(:css, ".tr").click()
I hope this works, worked in my case!
I found this works without requiring a class:
page.find(:xpath, "//table/tbody/tr").click
I believe your row-click requires JavaScript, so you'll need to add :js => true to your test's header. Setting up testing with JavaScript is a challenge. I found these resources helpful:
ASCIIcast #257 Request Specs and Capybara - see info on database-cleaner
Capybara readme - see “Transactions and Database Setup"
Here is a more complete test example:
# Note that opening page by clicking on row requires JavaScript
describe "when user clicks on first row", :js => true do
let(:first_account_listed) { Account.order(:name).first }
before { page.find(:xpath, "//table/tbody/tr").click }
it { should have_selector('title', text: 'Account Details') }
end
In Capybara 3+ you can go with a more elegant way by using the :table_row selector and match against a td value like:
page.find(:table_row, ["Some attribute"]).click
If you have table headers defined you can also pass a Hash instead of an Array that will match the cell against its corresponding table header like this:
page.find(:table_row, { "Header" => "Cell value" }).click
To dive into how this actually works, here's a link to the latest Capybara selector definition: https://github.com/teamcapybara/capybara/blob/master/lib/capybara/selector/definition/table_row.rb
I have a simple link_to_function in my view template
<%= link_to_function "add new category", "$('#category_name').focus()" %>
and I want to test this with capybara using request specs. Basically the spec should look something like this
it "focuses category form when I click 'add new category'" do
visit new_article_path
click_link "add new category"
# unfortunately there's nothing like 'has_focus?'
find_field("category_name").should have_focus
end
the problem is, I wasn't able to find anything, that would check if the element has focus.
The only thing I did find was this
page.evaluate_script('document.focus')[:id]
which however isn't supported by the capybara-wekbit driver, which I'm using to avoid opening browser for each test run.
I just used the following code (with phantomjs driver, but I believe that it works with webkit also):
page.evaluate_script("document.activeElement.id") == "some_id"
P.S. One year question without an answer. Should they give me a badge? :)
You should use the :focus selector, e.g:
page.should have_selector('#category_name:focus')
With the Selenium driver you can get the focused element:
page.driver.browser.switch_to.active_element
Then you can do what you like with it
page.driver.browser.switch_to.active_element.send_keys "some text"
Note that it returns a Selenium::WebDriver::Element whereas find returns a Capybara::Node::Element so be careful when comparing them
expect(page.driver.browser.switch_to.active_element).to eql(find('#some-element').native)
I'm tryting to write a cucumber/capybara test to reorder some items and then save them back. Any thoughts on how to best do this?
I have developed a JQuery plugin to solve this problem, check out jquery.simulate.drag-sortable.js which includes a plugin along with a suite of tests and examples.
Hope you find this useful! Feedback is welcome.
Matt
the drag_to method did not work for me. But I was able to cause the first element in my list to be dragged to the last position by including the following in my capybara selenium test using jquery.simulate.js :
page.execute_script %Q{
$.getScript("/javascripts/jquery.simulate.js", function(){
distance_between_elements = $('.task:nth-child(2)').offset().top - $('.task:nth-child(1)').offset().top;
height_of_elements = $('.task:nth-child(1)').height();
dy = (distance_between_elements * ( $('.task').size() - 1 )) + height_of_elements/2;
first = $('.task:first');
first.simulate('drag', {dx:0, dy:dy});
});
}
I'm using a web step like this and it works fine:
When /^I drag "([^"]*)" on top$/ do |name|
item = Item.find_by_name(name)
sleep 0.2
src = find("#item_id_#{item.id}")
dest = find("div.title")
src.drag_to(dest)
end
For me, #drag_to did work, however, its powers seem to be limited.
In order to move a UI-sortable table row down, I had to create a table with three rows, then run this Cucumber step:
# Super-primitive step
When /^I drag the first table row down$/ do
element = find('tbody tr:nth-child(1)')
# drag_to needs to drag the element beyond the actual target to really perform
# the reordering
target = find('tbody tr:nth-child(3)')
element.drag_to target
end
This would swap the first with the second row. My interpretation is that Capybara does not drag far enough, so I gave it a target beyond my actual target.
Note: I have configured UI-sortable with tolerance: 'pointer'.
I followed #codener's solution and it works! The only thing I changed in my code is configuring the UI-sortable with tolerance: 'pointer'.
The limitation described in #codener's answer is not gone, too. (I'm using capybara 2.18.0.) It doesn't need the third row to swap the first with the second row.
When /^I drag the first table row down$/ do
element = find('tbody tr:nth-child(1)')
target = find('tbody tr:nth-child(2)')
element.drag_to target
end
I'm using webrat with cucumber and I would like to test if a radio button is checked already when I am on a page.
How can I do that ? I didn't find any step in webrat which can do that.
expect(find_field("radio_button_name")).to be_checked
input("#my_box").should be_checked
There are cases when you cannot rely on checkboxes having ids or labels or where label text changes. In this case you can use the have_selector method from webrat.
From my working code (where I do not have ids on checkboxes).
response_body.should have_selector 'input[type=radio][checked=checked][value=information]'
Explanation: test will return true if body of document contains an radio button (input[type=radio]) which is checked and that has the value "information"
Just changed a web_step checkbox to radio button
Add the following step to web_steps.rb
Then /^the "([^"]*)" radio_button(?: within "([^"]*)")? should be checked$/ do |label, selector|
with_scope(selector) do
field_checked = find_field(label)['checked']
if field_checked.respond_to? :should
field_checked.should be_true
else
assert field_checked
end
end
end
And you can write the following to check whether the given raido button is checked or not
And the "Bacon" radio_button within "div.radio_container" should be checked
You can use the built-in checkbox matcher in web_steps.rb:
And the "Bacon" checkbox should be checked
However, you'll need to have a label on your checkbox that matches the ID of the corresponding checkbox input field. The f.label helper in Rails takes a string to use as the ID in the first argument. You may have to build a string that includes the field name and the checkbox name:
f.label "lunch_#{food_name}, food_name
f.radio_button :lunch, food_name
In any case, use this directive to see that you've got the HTML correct:
Then show me the page
Wrapped Jesper Rønn-Jensen his function + added name which is used by rails:
Then /^I should see that "([^"]*)" is checked from "([^"]*)"$/ do |value, name|
page.should have_selector "input[type='radio'][checked='checked'][value='#{value}'][name='#{name}']"
end
And the "Obvious choice" checkbox should be checked
Although it might be a radio button, but the code will work. It is just checking for a fields labelled with that text.
You can use method checked? on your field
expect(find_field("radio_button_id").checked?).to eq(true)