How to avoid hard coding values in cucumber features? - ruby-on-rails

When writing my scenerios, is it possible to not have to hard code text in the steps?
Like say I am insert a username in a textbox field, and a password in the password field.
If I need to do this in many places, it would be a pain to fix.
Example:
Given I am the registered member "myusername"
And I am on the login page
When I fill in "email" with "email#example.com"
And I fill in "password" with "123"
And I press "Login"
Then I should see "Account Activity"
I don't want my username, email, and password hard-coded.

Okay, you're still using the older version of the cucumber-rails gem which comes with the training wheels installed by default. Read this post by Aslak Hellesøy "The training wheels came off".
The gist of the post is that using web_steps.rb, although it having been the "standard" for years is now terribly wrong and that we should feel bad for doing that.
The purpose of Cucumber is to use it to make readable / understandable features for all people.
Writing a scenario like this is long and boring:
And I am on the login page
When I fill in "email" with "email#example.com"
And I fill in "password" with "123"
And I press "Login"
Then I should see "Account Activity"
What you want to actually be testing is that you should be able to login and after that see something to do with being logged in. Whatever that something is shouldn't be written in the scenario.
So ideally, your Scenario (in a more exciting fashion) would look like this:
When I login successfully
Then I should see that I am logged in
Then the task of doing the legwork goes to some new step definitions. Those two steps aren't defined automatically for you, like web_steps.rb does, but rather need to have them written in a file within feature/step_definitions. What you call the file is up to you, but it'll contain content similar to this:
When /I login successfully/ do
visit root_path
click_link "Login"
fill_in "Email", :with => "you#example.com"
fill_in "Password", :with => "password"
end
Then /^I should see I am logged in$/ do
page.should have_content("Account Activity")
end
No more excessive web_steps.rb file and cleaner step definitions. Exactly what Cucumber should be.

Create a step to encapsulate the logging in behavior as described here
If this works for you, I would then suggest tweaking the Given /I am logged in/ step to capybara calls to get a slight boost to performance. Also, in the future it is recommended that you avoid using web_steps for reasons described here.

Ryan's example is a change from imperative steps to declarative. This is generally a better idea. It means that the implementation has been moved into step definitions which makes the feature more readable and focuses on the behavior instead of the details.
But if you need to be specific with your steps (imperative), you could try something like
Given I am a registered member
And I am on the login page
When I fill in the login form
And I submit the login form
Then I should see I am logged in
You could also combine those steps to make it even simpler. But still, Ryan's idea is probably better in most cases.
Edit: Ryan has written a book. It's quite good. Hi Ryan!

You can create csv file in framework under data folder,add your private values to csv file, then call it in your feature file

Related

Devise user creation fails during Capybara integration testing (and Selenium webdriver)

I'm trying to create a user during an integration test to use for some operations. I'm using devise with :confirmable. The code is the following:
user = User.create({username: "user1", password: "pass1234", password_confirmation: "pass1234", email: "test#email.com"})
user.confirm!
fill_in "Username", :with => user.username
fill_in "Password", :with => user.password
click_button "Sign in"
The problem is that the login fails every time I try it. There are no errors about the user creation, but for some reason the user doesn't seem to "be there" when I try to login. I just get 'Invalid username or password' when I try to sign in. This seems like something to do with the fact that maybe Capybara/Selenium webdriver isn't waiting properly for the database operation to take place before it tries to sign in. If that's the case, how could I test it or fix it?
Is it "wrong" to even be trying to insert into the database during an integration test?
I don't use devise myself so can't really comment on the specifics of the problem you're encountering, but this question caught my eye:
Is it "wrong" to even be trying to insert into the database during an integration test?
Yes, I would say it generally is.
Your integration tests should test your code from the point of view of the user:
Expectations should only depend on what the user can actually see.
Actions should correspond only to what the user can actually do.
Inserting something into the database goes beyond the range of actions that the user has at their disposal. It is something for a unit test perhaps, but not for an integration test.
That being said, you could argue that seeding database data is a bit of an exception to this rule, since you're setting up context for your test (see my comments below).

Add extra documentation to rspec output

So, while I like Cucumber for its readability for integration testing and its ability to give us documentation we can share with the client easily, I also find it cumbersome from the development and testing speed standpoints.
I got to thinking today that if I could just print out messages to the RSpec documentation format that documented the "steps", then I could easily replicate the business features of Gherkin but in the simplicity of RSpec. But I can't figure out a way to do this.
What I want is to take something like this:
describe "Login and Authorization Tests" do
before (:each) do
docs "Given I have a user"
#user = FactoryGirl.create(:user)
end
it "A user can belong to one or more user roles" do
docs "And the user has no roles assigned"
#user.roles.length.should eq 0
docs "When I add two roles"
#user.roles << FactoryGirl.create(:role)
#user.roles << FactoryGirl.create(:role)
#user.reload
docs "Then the user should have two roles assigned"
#user.roles.length.should eq 2
end
end
and get this in the documentation
User
Login and Authorization Tests
A user can belong to one or more user roles
Given I have a user
And the user has no roles assigned"
When I add two roles
Then the user should have two roles assigned
Note that the message from "before" shows up in the docs too, and would show up with that line in every test below it.
I'm thinking of forking to see if I can add something like this in, but before I did that, does anyone know if something like this is possible already?
I also contacted the RSpec dev team and someone there posted this add-on called rspec-longrun that could be repurposed for this. I haven't had a chance to try it yet, but it looks very promising. And as a bonus, it includes timing information.
rspec-longrun: https://github.com/mdub/rspec-longrun
Thread on rspec-dev: https://github.com/rspec/rspec-dev/issues/34
You can try Steak, but the difference is not that big.
Or you can try Cucumber with RSpec matchers. In last case, you can fork RSpec and add a new formatter

select box in cucumber + webrat

I use this code to submit a form using cucumber
When I fill in "Email" with "example#example.com"
And I fill in "Name" with "user name"
Now I want to fill value in a select box.How can I do that?
That's not code, those are cucumber feature statements. Cucumber will translate those into step definitions, which in turn can contain code that will let you test the thing being described.
You probably have something like web_steps.rb that provides a set of pre-built statements like this, but you should not use them. You should be describing the business behavior of the application you are building, not the low-level UI details. Instead you should write something like this
Given I am on the registration page
When I sign up
Then I should be logged in automatically
And I should see a message stating "Thank you for signing up!"
This gives you an example of what you want to happen when someone signs up (They are logged in automatically and they are thanked for signing up). They way you have it now, you will have to change your specification to match the UI whenever you want to change the name of a field, and the specification should never change unless you are changing your business needs.
So to answer your more technical question, the step definition would look something like this, based on webrat's documentation
fill_in 'email', :with => '123#example.com'
fill_in 'name', :with => 'username'
select 'free account'
click_button 'Signup'

Creating a path with an object id to map with cucumber scenario

I'm trying to create a cucumber scenario that checks to see if elements are loaded for an 'edit posting' page. My trouble, however, is that I don't know how to create a path that will direct it to the page.
The general path is something like: /posting/id/edit
i.e. /posting/11/edit
Here is my posting.feature scenario
# Editing existing post
Scenario: Saving the edits to an existing post
Given I am logged in
Given there is a posting
Given I am on the edit posting page
When I fill in "posting_title" with "blah"
And I fill in "posting_location" with "blegh"
When I press "Update posting"
Then I should see "Posting was successfully updated."
I dabbled around with some Factory Girl stuff, but I don't have the knowledge to use it appropriately (if it offers a solution), and wasn't able to find a relevant example.
I've also seen a lot of suggestions with regards to 'Pickle', but if possible I'd like to avoid that route to keep things simple seeing as I have very limited experience. Thanks!
Is there a link on your website that would take someone to the edit page? Then you could do something like:
Given I am on the homepage
And I follow "Posts"
And I follow "Edit"
This assumes that there is a link on your homepage whose text is Posts, and then another one in the resulting page called Edit. This is the best way to accomplish this, because there should be a direct route to whatever page you are testing. Those steps are also provided in web_steps.rb
You could also make a custom step like you did there with Given I am on the edit posting page and the code would be something like:
Given /^I am on the edit posting page$/ do
visit("/posting/11/edit")
end
Which you of course could also generalize like I am on the edit posting page for posting 11. But in general, cucumber tests are acceptance tests, which means not bypassing things like this. You should have a link to the edit page that can be clicked.
I came up with a solution, but I am not sure of its validity in terms of how clean it is. I ended up using Factory Girl (installed the gem).
I kept my scenario the same.
Under features/step_definitions I created posting_steps.rb
Given /^there is a posting$/ do
Factory(:posting)
end
Under features/support I created a file factories.rb with the following inside:
Factory.define :posting do |f|
f.association :user
f.title 'blah'
f.location 'Some place'
end
In my paths.rb I used
when /the edit posting page/
edit_posting_path(Posting.first)
How it works (or at least how I think it works) is that as
Given there is a posting
is executed, the posting_step.rb is invoked (Factory(:posting) is basically Factory.create(:posting)), which in turn uses the factory definition I created in factories.rb. This leads to an instance of a posting being created.
Then in my paths.rb
when /the edit posting page/
edit_posting_path(Posting.first)
gets passed the id from the instance, to ultimately get a path that could resemble /posting/1/edit , and the test continues on its way!
If there are any corrections to be made, please let me know as I am just learning the ropes.
Hopefully this will help other newbies out there!

RoR testing controllers

I use RoR 3 and i guess something changed in controller's tests.
There is no
def test_should_create_post
but
test "should create user" do
...
end
Is there any decription how is that mapping etc? Because i dont get it.
And second thing. How to program (what assertion) use to test login?
so the test "something here" style is rails way of helping us out. It is fundamentally the same as def test_as_you_want but they helped us out by taking away those nasty '_(underscores)' and wrapping the actual test wording in a string. This change came back, phew... maybe 2.3.x. that fact has to be checked but at least a year and a half ago.
Your second thing is a little more harder to answer man. What plugin are you using, or are you one of those guys who are writing their own auth system?
Either way, check out how the 'famous' auth plugins do it. from Restful Auth to Devise, basically you want test that you can:
Signup for the User account
all of your confirmation emails are sent etc..
Most of these 'cheat' or take the easy way out by passing a helper called signed_in users(:one) for instance. Assuming you are cool and using fixtures.
Basically here is what a helper method looks like if your Auth plugin/gem doesn't have one, like Clearance which didn't have it when i was first writing my tests... not sure if it has it now but it sheds light on how it should look. Notice I've commented out Restful Auth and how he/they did it:
#login user
def login_user(user = users(:one))
#Restful Auth Example
# #request.session[:user_id] = user ? users(user).id : nil
# Clearance
#controller.class_eval { attr_accessor :current_user }
#controller.current_user = user
return user
end
Actually i think i stole this from their shoulda login helper... that's probably what i did. Either way it shows you how to fake login a user.
Now when you are testing, just pass this login_user method to your test when you need a user logged in and start testing the rest of the method without worrying about them actually signing in. That is what the plugin is supposed to do and the 1000 people following it on github would scream if it didn't at least LOG that guy in.
cheers

Resources