As best I can tell cucumber is only hitting the database once between these two scenarios, but it's clearing out the database between scenarios.
The Features:
Feature: a new user vists the site and signs up
in order to get new users
when an unlogged in users comes to the website
then they should see the sign-up dialog
and be able to signup for the website
Background:
Given I have at least one deal
Scenario: a new user is asked to signup
Given I am on show deal
Then I should see "New Here?"
#javascript
Scenario: new user signup failure
Given I am on show deal
When I fill in "consumer[user_attributes][email]" with "test#test.com"
And I press "consumer_submit"
Then I should see "1 error prohibited"
The Step Definition:
Given /^I have at least one deal$/ do
Deal.create copy:'Example Deal Copy', copy_header:'Example Deal Header', copy_subheader:'Example Deal Subheader' if Deal.all.size == 0
end
The Result:
Background: # features/new_user_signup.feature:7
Given I have at least one deal # features/step_definitions/new_user_signup_steps.rb:1
Scenario: a new user is asked to signup # features/new_user_signup.feature:10
Given I am on show deal # features/step_definitions/web_steps.rb:44
Then I should see "New Here?" # features/step_definitions/web_steps.rb:105
#javascript
Scenario: new user signup failure # features/new_user_signup.feature:15
Given I am on show deal # features/step_definitions/web_steps.rb:44
Couldn't find Deal with ID=1 (ActiveRecord::RecordNotFound)
./app/controllers/deals_controller.rb:17:in `show'
<internal:prelude>:10:in `synchronize'
./features/step_definitions/web_steps.rb:45:in `/^(?:|I )am on (.+)$/'
features/new_user_signup.feature:16:in `Given I am on show deal'
When I fill in "consumer[user_attributes][email]" with "test#test.com" # features/step_definitions/web_steps.rb:60
And I press "consumer_submit" # features/step_definitions/web_steps.rb:52
Then I should see "1 error prohibited" # features/step_definitions/web_steps.rb:105
Failing Scenarios:
cucumber features/new_user_signup.feature:15 # Scenario: new user signup failure
Whichever scenario I put second will give the ActiveRecord error. Why are there no records in the database for my second scenario?
Now I know how you've mapped "show deal" I am tempted to say that the problem is that the Deal instance possibly exists but it's id is not equal 1. Can you check please?
And here is a tip: while you're defining paths in your path.rb, you may do something like this:
when /the edit deal page/
edit_deal_path(Deal.first)
or even this:
when /the deal page for deal named ".*"/
deal_name = page_name.scan(/".*"/).first.gsub("\"", '')
deal = Deal.find_by_name(deal_name)
deal_path(deal)
As long as you've defined your "I am on" webstep like this:
Given /^(?:|I )am on (.+)$/ do |page_name|
visit path_to(page_name)
end
It's far better than "deals/1" :)
Related
I have set up this Cucumber feature in 'spree_fit_card/new_gift_card.feature`:
#gift-card
Feature: access gift cards
As a general user
I will be able to place an order for a gift card
Scenario: The gift card index page will redirect to /new
When I am on the gift card page
Then I will be redirected to the new gift card page
And in the support/paths.rb:
module NavigationHelpers
def path_to(page_name)
when /the gift card page/
spree.gift_cards_path
when /the new gift card page/
spree.new_gift_card_path
else
...
end
end
end
And when we checkout step_definitions/new_gift_card_steps.rb:
When(/^I am on the gift card page$/) do
pending
end
Then(/^I will be redirected to the new gift card page$/) do
pending
end
Cucumber outputs:
$ zeus cucumber --tags #gift-card
Loading fixtures
Using the default profile...
#gift-card
Feature: access gift cards
As a general user
I will be able to place an order for a gift card
Scenario: The gift card page will redirect to the new gift card page # features/spree_gift_card/new_gift_card.feature:6
When I am on the gift card page # features/spree_gift_card/new_gift_card.feature:7
Ambiguous match of "I am on the gift card page":
features/step_definitions/spree_gift_card/new_gift_cards_steps.rb:1:in `/^I am on the gift card page$/'
cucumber-websteps-0.10.0/lib/cucumber/websteps/browsing_steps.rb:1:in `/^(?:|I )am on (.+)$/'
You can run again with --guess to make Cucumber be more smart about it
(Cucumber::Ambiguous)
-e:1:in `<main>'
features/spree_gift_card/new_gift_card.feature:7:in `When I am on the gift card page'
Then I will be redirected to the new gift card page # features/step_definitions/spree_gift_card/new_gift_cards_steps.rb:5
Failing Scenarios:
cucumber features/spree_gift_card/new_gift_card.feature:6 # Scenario: The gift card page will redirect to the new gift card page
So I took Cucumber's suggestion into consideration and ran zeus cucumber --tags #gift-card --guess
Loading fixtures
Using the default profile...
#gift-card
Feature: access gift cards
As a general user
I will be able to place an order for a gift card
Scenario: The gift card page will redirect to the new gift card page # features/spree_gift_card/new_gift_card.feature:6
When I am on 'the gift card page' # features/step_definitions/spree_gift_card/new_gift_cards_steps.rb:1
TODO (Cucumber::Pending)
./features/step_definitions/spree_gift_card/new_gift_cards_steps.rb:2:in `/^I am on the gift card page$/'
features/spree_gift_card/new_gift_card.feature:7:in `When I am on the gift card page'
Then I will be redirected to the new gift card page # features/step_definitions/spree_gift_card/new_gift_cards_steps.rb:5
1 scenario (1 pending)
2 steps (1 skipped, 1 pending)
0m0.016s
Cleaning up database
I'm glad that it passes with --guess, but I don't understand why its not passing without it. I think I've set it up right, but I obviously haven't. I'm using the Spree framework if it helps with Ruby on Rails version 3.2.17.
Reason can be found back in the errors you're giving:
cucumber-websteps-0.10.0/lib/cucumber/websteps/browsing_steps.rb:1:in `/^(?:|I )am on (.+)$/'
shows that there is a "default" step, in browsing_steps.rb, which also matches with your test. That's the reason why you get this error. As you see, the matching is "less" than with your step, and that's the reason that "guess" works: it will chose automatically for the "best fitting" step definition.
I've already added the reply-to-microposts functionality to Michael Hartl's Rails 3 Tutorial book, but I'm now trying to write the tests for them (I know I did it backwards). The replies addition works, but I'm trying to write the following test
create user and two posts from user
create other_user and two posts from other_user
have user follow other_user
check that user's home page feed includes other_user's post
...
My tests are currently failing at step four. Below is the snippet from the spec file, the failure error, and the link to my repo. (user is defined before this describe, but within the scope of this block)
describe "replying to a micropost" do
let (:other_user) { FactoryGirl.create(:user) }
let (:first_post) { FactoryGirl.create(:micropost, user: other_user, content: "Whatever.") }
let (:second_post) { FactoryGirl.create(:micropost, user: other_user, content: "Nevermind.") }
before do
user.follow!(other_user)
visit root_path
end
it "should render the posts from other user" do
page.should have_selector("li##{first_post.id}", text: first_post.content)
page.should have_selector("li##{second_post.id}", text: second_post.content)
end
Failures:
1) Static pages Home page for signed-in users replying to a micropost should render the posts from other user
Failure/Error: page.should have_selector("li##{first_post.id}", text: first_post.content)
expected css "li#203" with text "Whatever." to return something
# ./spec/requests/static_pages_spec.rb:85:in `block (5 levels) in <top (required)>'
Finished in 3.43 seconds
17 examples, 1 failure
Failed examples:
rspec ./spec/requests/static_pages_spec.rb:84 # Static pages Home page for signed-in users replying to a micropost should render the posts from other user
Done.
https://github.com/johnklawlor/sample_app
In short, my tests failed because I need to user let! (let bang) in order to create the micropost at the time of the let! call. Using a simple let call (i.e. without the !) doesn't create the micropost until the page.should have_selector line, which is after the visit root_path call and therefore does not find the micropost on the page.
Here's how I figured it out... It's related to a statement iterated in this question regarding let vs before initializations, where s/he states, "For the method defined by let, the initialization code only runs if the example calls it." (source: stackoverflow.com/questions/5359558/when-to-use-rspec-let) In my example, first_post and second_post weren't being created until I called on their id's in the have_selector('li'... call, which means they aren't created until after the visit root_path call and therefore after the user's feed is built. The only thing I have to back up this assumption is that if you add some line like first_post.content=first_post.content (and the same for second_post) before the visit root_path call, the tags are generated for the posts as attested by the page opened from save_and_open_page and by the passing tests. Inserting a line like first_post.content=first_post.content after visit root_path produces no li tags and failing tests.
For example, the user should not see a login page while one has already logged in. How should I implement this functionality in cucumber?
Scenario: Authorizzation
Given I am logged in
Then I should not be asked to authenticate
Given(/^I am logged in$/) do
#user = User.new
end
Then(/^I should not be asked to authenticate$/) do
# what to write???
end
Assume the authentication page is called login.
Something like:
page.body.should_not include_text("Please enter your credentials")
Without seeing your existing code, its hard to assume. But it is along these lines
Given...do
...
arg1.should #=> should
...
end
Given...do
...
arg1.should_not #=> should not
...
end
Update
Then(/^I should not be asked to authenticate$/) do
# what to write???
unless #user.logged_in? #=> assumes there is a method that checks it
routines to login
end
end
From my practical experience, I recommend getting your Ruby basics right to enjoy cucumber. Besides, it is very useful when scenarios say what should happen.
Scenario: Authentication
Given user is not logged in
Then he should be asked to authenticate #=> (OR) Then he should be redirected to login page
I think you are fundamentally approaching it from the wrong direction. You might instead assert that I should see something that you expect like a link, text, or other. You can also follow a link one more level that you can assert you have proper access too.
It's hard to test something that isn't happening and you have no evidence, so test what you expect, not the world of things for which you can't test.
On login page it seems that buttons like "Login" or "Sign In" should be present.
So, after login, you can check whether this button not present.
page.should_not have_xpath(:xpath, '//here your xpath to element', :text => "Login")
Then /^(?:|I )should not be on (.+)$/ do |page_name|
URI.parse(current_url).path.should_not == path_to(page_name)
end
I use db/seeds.rb to populate my database with 2 user roles ("Admin", "User") that will never change. When i run tests though, the seed data does not get carried over and the results are error tests.
When i try to run cucumber i get the following error:
Using the default profile... Feature: Sign in In order to get access
to protected sections of the site A valid user Should be able to
sign in
Scenario: User is not signed up #
features/users/sign_in.feature:6 Not registered: role
(ArgumentError)
/Users/x/.rvm/gems/ruby-1.9.2-p180/gems/factory_girl-2.0.0.rc4/lib/factory_girl/registry.rb:15:in
find'
/Users/x/.rvm/gems/ruby-1.9.2-p180/gems/factory_girl-2.0.0.rc4/lib/factory_girl.rb:39:in
factory_by_name'
/Users/x/.rvm/gems/ruby-1.9.2-p180/gems/factory_girl-2.0.0.rc4/lib/factory_girl/syntax/vintage.rb:53:in
default_strategy'
/Users/x/.rvm/gems/ruby-1.9.2-p180/gems/factory_girl-2.0.0.rc4/lib/factory_girl/syntax/vintage.rb:146:in
Factory'
/Users/x/rails/ply_rails/features/support/db_setup.rb:6:in
`Before'
Given I am not logged in #
features/step_definitions/user_steps.rb:36
Here is what my setup looks like:
# features/support/db_setup.rb
Before do
# Truncates the DB before each Scenario,
# make sure you've added database_cleaner to your Gemfile.
DatabaseCleaner.clean
Factory(:role, :name => 'Admin')
Factory(:role, :name => 'User')
end
# features/users/sign_in.feature
Feature: Sign in
In order to get access to protected sections of the site
A valid user
Should be able to sign in
Scenario: User is not signed up # THIS IS LINE 6
Given I am not logged in
And no user exists with an email of "user#user.com"
When I go to the sign in page
And I sign in as "user#user.com/password"
Then I should see "Invalid email or password."
And I go to the home page
And I should be signed out
# features/step_definitions/user_steps.rb
Given /^I am a "([^"]*)" named "([^"]*)" with an email "([^"]*)" and password "([^"]*)"$/ do |role, name, email, password|
User.new(:name => name,
:email => email,
:role => Role.find_by_name(role.to_s.camelize),
:password => password,
:password_confirmation => password).save!
end
Not sure where to start on getting this working, thank you for your help/time!
Well the point of tests is to start with a clean database, i.e a consistent state, so it's kind of good that everything gets wiped.
Secondly, in terms of cucumber, you should be defining a Background block to do the set up. This will run for each scenario, and has the benefit of every action being explicitly known. This is especially useful if you use the cucumber scenario plain text to show to clients. So you should do something like:
Background:
Given that the role "Admin" exists
And that the role "User" exists
Scenario:
etc
And make custom steps for the that the role [blank] exists that will create the role for you.
I am trying to test my controllers, but some of the actions in my controller expect the user to be logged in. How will I test them? Do I mess with the session variable directly? Also, what if a lot of the actions expect the user to be logged in? Should I set up a before action, and log the user in there?
Another idea I had was that I could test them in an integration test, and do a post on the login form, before I actually test the desired action. Something like:
def setup
# log the user in, this will happen before every test
end
# integration test
test "I should see my posts" do
#setup should have happened before this, and I should be logged in
get posts_path
assert ...
end
Is this the way to test these actions? Am I missing something?
Depending on your authentication framework you use there are several ways. Devise for example has some TestHelpers, that make it easy to login users without having go through the actual webpage in functional tests. If thats not an option, like soundsop said, browser testing. (look at, from high to low: cucumber, capybara, selenium/...)
The Book includes some testing examples in their depot application:
test "should login" do
dave = users(:one)
post :create, :name => dave.name, :password => 'secret'
assert_redirected_to admin_url
assert_equal dave.id, session[:user_id]
end
Full details in the "Authenticating Users" section.
You can either make fake user credentials in the setup, or you can stub out the method which checks the credentials using a mocking library. I've done both and don't have a firm preference.