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
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
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
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 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
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).