Cucumber mała zagwozdka

Pewnie jakiś prosty błąd, ale nie mogę znaleźć.
Mam takie scenariusze:

Feature: Ending (settling) bets

As an admin
I want to end bet

Background: With bet
  Given I have a published bet

Scenario: Settle bet with no bids
  And I am logged as admin
  And I choose to end bet as positive on settle page
  Then I should have this bet closed

Scenario: Settle bet with bids on both sides
  And I am logged as admin
  And I choose to end bet as positive on settle page
  Given I have a users with amounts:
  |1|2.0|
  |2|1.0|
  |3|1.2|
  And I have bids like:
  |1|1.0|true|
  |2|0.5|true|
  |3|1.0|false|
  Then I should have this bet closed
  And I should have users with amounts:
  |1|2.6|
  |2|1.3|
  |3|0.2|

Scenariusz pierwszy przechodzi bez problemu.
Scenariusz drugi wywala na kroku, który poprzednio przeszedł:

Scenario: Settle bet with no bids                    # features/end_bet.feature:9
And I am logged as admin                           # features/step_definitions/end_bet_steps.rb:6
And I choose to end bet as positive on settle page # features/step_definitions/end_bet_steps.rb:14
Then I should have this bet closed                 # features/step_definitions/end_bet_steps.rb:19

Scenario: Settle bet with bids on both sides         # features/end_bet.feature:14
And I am logged as admin                           # features/step_definitions/end_bet_steps.rb:6
And I choose to end bet as positive on settle page # features/step_definitions/end_bet_steps.rb:14
  undefined method `admin?' for nil:NilClass (NoMethodError)
  ./app/helpers/sessions_helper.rb:46:in `admin_user'
  ./features/step_definitions/end_bet_steps.rb:15:in `/^I choose to end bet as positive on settle page$/'
  features/end_bet.feature:16:in `And I choose to end bet as positive on settle page'

A tak wyglądają kroki:

Given (/^I have a published bet$/) do
    @bet = FactoryGirl.create(:published_bet)
end

Given (/^I am logged as admin$/) do
    @user = FactoryGirl.create(:admin)
    visit login_path
    fill_in "Użytkownik", with: "user_1"
    fill_in "Hasło", with: "111111"
    click_button "Zaloguj się"
end

When (/^I choose to end bet as positive on settle page$/) do
    visit "/bets/#{@bet.id}/end"
    click_button "Zakończ jako PRAWDA"
end

Then (/^I should have this bet closed$/) do
    visit "/bets/#{@bet.id}"
    page.body.should =~ /Zdarzenie zakończone i rozliczone/m
end

Given(/^I have a users with amounts:$/) do |table|
    table.raw.each do |id, amount|
	   bid_user = FactoryGirl.create(:user, { id: id })
    end
end

Given(/^I have bids like:$/) do |table|
    table.raw.each do |id, amount, positive|
        bid = Bid.create({ bet_id: @bet.id, user_id: id, amount_in_stc: amount, positive: positive })
    end
end

Then(/^I should have users with amounts:$/) do |table|
    pending
end

Gdzie robię błąd?

Z jakiegoś powodu wylogowuje użytkownika. Puść sobie tail -f log/test.log podczas tego testu.

Hmm… myślałem że to jakiś błąd systemowy (cache, albo sesja), bo w logu było na końcu:

CACHE (0.0ms)  SELECT `users`.* FROM `users` WHERE `users`.`remember_token` = 'da39a3ee5e6b4b0d3255bfef95601890afd80709' LIMIT 1
Completed 500 Internal Server Error

Ale zrobiłem jedną poprawkę. Miałem:

factory :user do
  sequence(:name) { |n| "user_#{n}" }
  sequence(:email)  { |n| "user#{n}@mail.com" }
  password "111111"
  password_confirmation "111111"

  factory :admin do
    admin true
  end

end

Zmieniłem na:

factory :user do
  sequence(:name) { |n| "user_#{n}" }
  sequence(:email)  { |n| "user#{n}@mail.com" }
  password "111111"
  password_confirmation "111111"

  factory :admin do
    name "admin"
    admin true
  end

end

I w testach oczywiście z:
fill_in "Użytkownik", with: "user_1"

na:
fill_in "Użytkownik", with: "admin"

I jest OK :expressionless: :expressionless:

Ale jak wywalę z factorii nazwę dla admina i zostawię generowaną automatycznie, to przy pierwszym scenariuszu zaloguje się i przejdzie na stronę wymagającą uprawnień admina a w drugim już nie.
I teraz najciekawsze - jak ten drugi scenariusz wyrzucę a dam jeszcze raz pierwszy (czyli dwa takie same pod rząd) to przy drugim też się wywali :smiley:

Ot, problem rozwiązany, ale zagadka pozostaje - co ma tu do rzeczy nazwa admina??

W obu scenariuszach podajesz I am logged as admin, gdzie tworzysz za każdym razem konto admina na nowo. A jako, że w fabryce tworzysz pole name z użyciem sekwencji - pierwsze konto admina będzie miało name: user_1, drugie name: user_2 itd. Pomiędzy scenariuszami baza danych jest czyszczona, także w drugim scenariuszu w bazie nie będzie użytkownika user_1, będzie za to user_2. Każdorazowe wywołanie FactoryGirl.create(:admin) utworzy konto o innym polu name.

W I am logged as admin możesz zmienić fill_in "Użytkownik", with: "user_1" na fill_in "Użytkownik", with: @user.name.

A, w ten sposób :smile: To tak, jak podejrzewałem prosty błąd - założyłem, że FactoryGirl pomiędzy scenariuszami resetuje sobie licznik.
Dzięki za wyjaśnienie!

Dobra, nie będę otwierał nowego wątku dla kolejnego problemu z cucumberem :stuck_out_tongue:
Skrót modelu:

 class Bet < ActiveRecord::Base

has_many :bids
def sum_positive
  bids.positive.sum('amount')
end
    
def settle(positive)
	self.closed_at = DateTime.now
	self.positive = positive
	if save(validate: false)
	   Fee.create({ bet_id: id, amount: sum_positive })
	end			 
end

Fragment testu:

Then(/^I should have "(.*?)" on "(.*?)" account$/) do |arg1, arg2|
  @bet.sum_positive.should == 150000000
  fee = Fee.find_by_bet_id(@bet.id)
  fee.amount.should == 5000000
end

I jak to wywołam przez kontroler to działa - tworzy nowy rekord dla Fee, który ma prawidłowy amount. Natomiast jak przez cucumbera, to rekord owszem tworzy, ale amount jest zawsze 0, chyba że go wstawię z palca (np. Fee.create({ bet_id: id, amount: 5000000 }) w modelu.
Dziwne bo sama metoda sum_positive działa (pierwsza asercja w teście), rekord jest tworzony (bo jak nie to fee == nil i wywala brak metody amount).