RSpec: how to write tests with accents? - testing

I'm new in cucumber and rspec, and I'm trying to test a button whose text is "Regístrate" (look at the accent "í").
In my app, I have a lot of controls written in spanish, with accents á é í ó ú. But I get an error because of these vowels with accents. I'm sure there is an easy solution but I don't achieve to find a solution.
I could change the tests descriptions, but not the words in the user application... any suggestion?
describe "signup" do
before { visit signup_path }
let(:submit) { "Regístrate" }
describe "con información válida" do
it "no debería crear el usuario" do
expect { click_button submit }.not_to change(User, :count)
end
end
describe "con información válida" do
before do
fill_in "Nombre", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmación", with: "foobar"
end
it "debería crear el usuario" do
expect { click_button submit }.to change(User, :count).by(1)
end
end
end
error:
user_signup_steps.rb:3: syntax error, unexpected $end, expecting keyword_end
"Regístrate"
^ (SyntaxError)

Looks like an encoding error. Try adding this line to the top of the spec file:
# encoding: utf-8

Related

Test lengthy form without re-writing all the fill_ins everytime

I have a long form, and for 3 of the fields, I need to test whether those were filled out right or wrong individually, because errors lead to very different actions. But it's very tedious and not DRY to write integration tests like this:
# Test 1
describe "test where field3 fails" do
before do
fill_in "field1", with: "passing info"
fill_in "field2", with: "passing info"
fill_in "field3", with: "not passing info"
...
end
it "should lead to an error specific to field3" do
...
end
end
# Test 2
describe "test where field2 fails" do
before do
fill_in "field1", with: "passing info"
fill_in "field2", with: "not passing info"
fill_in "field3", with: "passing info"
...
end
it "should lead to an error specific to field2" do
...
end
end
# Test 3
describe "test where field1 fails" do
before do
fill_in "field1", with: "not passing info"
fill_in "field2", with: "passing info"
fill_in "field3", with: "passing info"
...
end
it "should lead to an error specific to field1" do
...
end
end
In that case ,I would suggest to write data driven tests like below
describe "test all form fields" do |data|
before do
fill_in "field1", with: data[0]
fill_in "field2", with: data[1]
fill_in "field3", with: data[2]
...
end
it "should lead to an error message" do |CorrespondingErrorMsg|
...
end
This way all the combinations will be defined inside test data ,not in the code so in future if no. of validations even increase or decrease you don't have to touch the code.Only the data.
I hope it makes sense to make the solution dry.

nested feature in capybara 2.0+

i want to do something like this:
feature "sign-up" do
before {visit signup_path}
let(:submit) {"Create my account"}
feature "with invalid information" do
scenario "should not create a user" do
expect {click_button submit}.not_to change(User, :count)
end
end
feature "with valid information" do
scenario "should create a user" do
fill_in "Name", with: "test name"
fill_in "Email", with: "test#test.com"
fill_in "Password", with: "password"
fill_in "Confirmation", with: "password"
expect {click_button submit}.to change(User, :count).by(1)
end
end
end
but when i run rspec i get
in `block in <top (required)>': undefined method `feature' for #<Class:0x000000039e0018> (NoMethodError)
if i change it a bit to look like this it works:
feature "with invalid information" do
before {visit signup_path}
let(:submit) {"Create my account"}
scenario "should not create a user" do
expect {click_button submit}.not_to change(User, :count)
end
end
feature "with valid information" do
before {visit signup_path}
let(:submit) {"Create my account"}
scenario "should create a user" do
fill_in "Name", with: "test name"
fill_in "Email", with: "test#test.com"
fill_in "Password", with: "nirnir"
fill_in "Confirmation", with: "nirnir"
expect {click_button submit}.to change(User, :count).by(1)
end
end
EDIT:
plus, the following code works(describe nested inside feature) - but is it wrong in any way?
feature "sign-up" do
background {visit signup_path}
given(:submit) {"Create my account"}
scenario "with invalid information" do
expect {click_button submit}.not_to change(User, :count)
end
describe "with valid information" do
background do
fill_in "Name", with: "test name"
fill_in "Email", with: "test#test.com"
fill_in "Password", with: "password"
fill_in "Confirmation", with: "password"
end
scenario { expect {click_button submit}.to change(User, :count).by(1) }
scenario "after submission" do
click_button submit
page.html.should have_content("Registration successful")
end
end
end
EDIT (23/01/2014): Nested features are available since version 2.2.1. See here
EDIT (24/07/2013): Nested features will be allowed in Capybara > 2.1.0. See here
You can't. This is what the mantainer of the gem says about it
I guess you could call this a limitation. feature can not be nested.
You can use either context or describe instead, but I would
suggest not going wild with these, it tends to make tests pretty
unreadable.
In some other cases the convenience of this might be argued but in this specific one you should use scenario instead of the nested feature.
Also if you want to consistent and use the new DSL everywhere, use background instead of before and given instead of let. Like this:
feature "sign-up" do
background {visit signup_path}
given(:submit) {"Create my account"}
scenario "with invalid information" do
expect {click_button submit}.not_to change(User, :count)
end
scenario "with valid information" do
fill_in "Name", with: "test name"
fill_in "Email", with: "test#test.com"
fill_in "Password", with: "password"
fill_in "Confirmation", with: "password"
expect {click_button submit}.to change(User, :count).by(1)
end
end
You have to remove the it because scenario is just an alias for it and you cannot nest it either.
Or you can always switch back to the old DSL if you find it more readable. In that case I would do something like this:
describe "sign-up" do
before {visit signup_path}
let(:submit) {"Create my account"}
context "with invalid information" do
it "does not create a user" do
expect {click_button submit}.not_to change(User, :count)
end
end
context "with valid information" do
before
fill_in "Name", with: "test name"
fill_in "Email", with: "test#test.com"
fill_in "Password", with: "password"
fill_in "Confirmation", with: "password"
end
it "creates a user" do
expect {click_button submit}.to change(User, :count).by(1)
end
end
end
But as long as the spec checks what it has to check, you should be fine anyways. The rest is all a matter of style, readability and good practices, which are important but more open to discussion and disagrement. In this case the author of the gem didn't allow nested feature's. Maybe for readability or maybe didn't feel it was needed or maybe didn't think about it... If you really want to nest features you can always try to implement it and pull request it.

Unable to find field "Name" (Capybara::ElementNotFound)

I'm trying to use capybara+rspec and get this error: Unable to find field "Name" (Capybara::ElementNotFound)
Here is my form:
%h2 Sign up
= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => {:class => 'form-vertical' }) do |f|
= f.error_notification
= display_base_errors resource
= f.input :name, :autofocus => true
= f.button :submit, 'Sign up', :class => 'btn-primary'
= render "devise/shared/links"
Here is my user_steps.rb
When /^I sign up with valid user data$/ do
create_visitor
sign_up
end
def create_visitor
#visitor ||= { :name => "Test visitor"}
end
def sign_up
visit '/users/sign_up'
fill_in "Name", :with => #visitor[:name]
click_button "Sign up"
end
What's wrong????
I encountered this issue and realized that Capybara filtered out hidden fields--my element belonged to a non-active tab (hidden) in a multi-tab page. I just passed the :visible arg and set it to false, and voila! the element was found.
fill_in "content", with: 'foo bar', visible: false
or
find('#item_content', visible: false).set 'foo bar'
It looks like to me that you are looking for a field label Name, but your name field does not have a label, so you probably need to use the ID of the field or the name which is probably:
"#{resource_name}[name]"
Also, as #nmott said in his comment, you should try using save_and_open_page so that you can actually look at the page, However, be aware you need the launchy gem to use this method.
Furthermore, what you might discover is you're not even on the right page. My usual problem when testing pages OTHER than the sign up page is that I've been redirected and didn't know it. So after using visit, you should also use assert_template to make sure you're on the right page.
I have the same problem myself and I had to stop using fill_in all together.
What I did was replacing all occurrences of fill_in with the following code :
element = page.find("Name")
element.set(#visitor[:name])
I guess you can encapsulate this into a method in order to make your tests more smooth
Try to narrow down your scope from within the form as such
within("form#whatever_form_id") do
fill_in "Name", :with => #visitor[:name]
click_button "Sign up"
end
Ok guys I found it out having the same issue , its very simple :
In capybara or rspec they need you to but "Name" and in your form or label field you need to write "name" in small....there you go works for me.
For me it was the next line of the spec that was causing the problem not the fill_in "name" line. It didn't matter whether or not name was "Name" or "name".
The next click_button line for me had click_button "Wrong Name" which was the wrong name for the button, and this did not give the expected error of "can't click on button "Wrong Name" but instead gave can't find field "name".
A bit verbose for my first even post on stack overflow. Bottom line. Consider the line below the line given in the capybara error message.

undefined method `change'

I'm doing the ruby on rails tutorial, I specifically adding listing 8.21 to spec/requests/users_spec.rb
require 'spec_helper'
describe "Users" do
describe "signup" do
describe "signup failure" do
lambda do
it "should not make a new user" do
visit signup_path
fill_in "Name", :with => ""
fill_in "Email", :with => ""
fill_in "Password", :with => ""
fill_in "Password confirmation", :with => ""
click_button
response.should render_template('users/new')
response.should have_selector("div#error_explanation")
end
end.should_not change(User, :count)
end
end
end
as far as I can tell, this is exactly like the listing in 8.21; however, when I run
rspec spec/requests/users_spec.rb -e "Users"
I got the following error ...
#> rspec spec/requests/users_spec.rb -e "Users" No DRb server is running. Running in local process instead ... /Users/bryanjamieson/rails_projects/sample_app/spec/requests/users_spec.rb:17:in `block (3 levels) in ': undefined method `change' for
# (NoMethodError)
any help would be appreciated.
I'd use User.count
end.should_not change(User.count)
Depending on which rails version and rspec version you're using (assuming Rails 3.1, Rspec2) the tutorial may be a little of out date

Can't find field when using symbol reference

I'm playing around with RoR for the first time and hit a weird error. I have the following test code for my navigation links:
describe "when logged in" do
before(:each) do
#user = Factory(:user)
visit login_path
#the line below is the weird one
fill_in "session[user_name]", :with => #user.user_name
fill_in :password, :with => #user.password
click_button
end
it "should have navigation links" do
response.should have_selector("nav")
end
it "should have link to log out" do
response.should have_selector("a", :href => logout_path, :content => "Log out")
end
end
the code above works just fine, but if I would change the line
fill_in "session[user_name]", :with => #user.user_name
to
fill_in :user_name, :with => #user.user_name
it won't work and I can't figure out why. The error I get is
Failure/Error: fill_in :user_name, :with => #user.user_name
Webrat::NotFoundError:
Could not find field: :user_name
The relevant generated html is:
<label for="session_user_name">User name</label><br/>
<input id="session_user_name" name="session[user_name]" size="30" type="text" />
<label for="session_password">Password</label><br/>
<input id="session_password" name="session[password]" size="30" type="password" />
If you look at the code you see I do exactly that for the password, and that works just fine. I would like to use the syntax which is causing the error so am I doing something wrong?
Try this:
fill_in "user name", :with => #user.user_name
I think webrat is being nice, and its able to find your label 'Password' because it is case insensitive and its turning :password into 'Password'.
You could also use the HTML id attribute, i.e.
fill_in :session_user_name, :with => #user.user_name
One gotcha here is if you are thinking of switching to use Capybara rather than Webrat: Capybara is case-sensitive, so it would fail on fill_in "user name".
I'm not sure what the best practice is here, but I have switched to using the HTML id and name attributes rather than the label text in my own code. The reason for this is that it is less brittle because people change the customer-facing text on the site more than they change the semantic elements and names.