mirror of
https://github.com/TracksApp/tracks.git
synced 2026-02-25 16:44:09 +01:00
merge upstream
This commit is contained in:
parent
c58186451f
commit
ce1c092173
72 changed files with 4469 additions and 0 deletions
196
spec/models/todo_spec.rb
Normal file
196
spec/models/todo_spec.rb
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
||||
|
||||
describe Todo do
|
||||
def valid_attributes(attributes={})
|
||||
{
|
||||
:description => "don't forget the milk",
|
||||
:context => mock_model(Context, :name => 'errands')
|
||||
}.merge(attributes)
|
||||
end
|
||||
|
||||
def create_todo(attributes={})
|
||||
todo = Todo.new(valid_attributes(attributes))
|
||||
todo.stub!(:user).and_return(mock_model(User, :date => Time.now))
|
||||
todo.save!
|
||||
todo
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
@todo = Todo.new
|
||||
end
|
||||
|
||||
it_should_belong_to :context
|
||||
it_should_belong_to :project
|
||||
it_should_belong_to :user
|
||||
|
||||
it_should_validate_presence_of :description
|
||||
it_should_validate_presence_of :context
|
||||
it_should_validate_length_of :description, :maximum => 100
|
||||
it_should_validate_length_of :notes, :maximum => 60_000
|
||||
|
||||
it 'validates presence of show_from when deferred'
|
||||
|
||||
it 'ensures that show_from is a date in the future' do
|
||||
todo = Todo.new(valid_attributes)
|
||||
todo.stub!(:user).and_return(mock_model(User, :date => Time.now))
|
||||
todo.show_from = 3.days.ago
|
||||
todo.should have(1).error_on(:show_from)
|
||||
end
|
||||
|
||||
it 'allows show_from to be blank' do
|
||||
todo = Todo.new(valid_attributes(:show_from => ''))
|
||||
todo.should_not have(:any).error_on(:show_from)
|
||||
end
|
||||
|
||||
describe 'states' do
|
||||
it 'is active on initializing' do
|
||||
create_todo.should be_active
|
||||
end
|
||||
|
||||
it 'is deferred when show from is in the future' do
|
||||
create_todo(:show_from => 1.week.from_now).should be_deferred
|
||||
end
|
||||
|
||||
describe 'active' do
|
||||
%w(project_hidden completed deferred).each do |from_state|
|
||||
it "is activable from `#{from_state}'" do
|
||||
todo = create_todo
|
||||
todo.state = from_state
|
||||
todo.send("#{from_state}?").should be_true
|
||||
todo.activate!
|
||||
todo.should be_active
|
||||
end
|
||||
end
|
||||
|
||||
it 'clears show_from when entering active state' do
|
||||
todo = create_todo
|
||||
todo.show_from = 3.days.from_now
|
||||
todo.should be_deferred
|
||||
todo.activate!
|
||||
todo.should be_active
|
||||
todo.show_from.should be_nil
|
||||
end
|
||||
|
||||
it 'clears completed_at when entering active state' do
|
||||
todo = create_todo
|
||||
todo.complete!
|
||||
todo.should be_completed
|
||||
todo.activate!
|
||||
todo.should be_active
|
||||
todo.completed_at.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'completed' do
|
||||
%w(active project_hidden deferred).each do |from_state|
|
||||
it "is completable from `#{from_state}'" do
|
||||
todo = create_todo
|
||||
todo.state = from_state
|
||||
todo.send("#{from_state}?").should be_true
|
||||
todo.complete!
|
||||
todo.should be_completed
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets complated_at' do
|
||||
todo = create_todo
|
||||
todo.complete!
|
||||
todo.completed_at.should_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'project_hidden' do
|
||||
%w(active deferred).each do |from_state|
|
||||
it "is hiddable from `#{from_state}'" do
|
||||
todo = create_todo
|
||||
todo.state = from_state
|
||||
todo.send("#{from_state}?").should be_true
|
||||
todo.hide!
|
||||
todo.should be_project_hidden
|
||||
end
|
||||
end
|
||||
|
||||
it 'unhides to deferred when if show_from' do
|
||||
todo = create_todo(:show_from => 4.days.from_now)
|
||||
todo.hide!
|
||||
todo.should be_project_hidden
|
||||
todo.unhide!
|
||||
todo.should be_deferred
|
||||
end
|
||||
|
||||
it 'unhides to active when not show_from' do
|
||||
todo = create_todo(:show_from => '')
|
||||
todo.hide!
|
||||
todo.should be_project_hidden
|
||||
todo.unhide!
|
||||
todo.should be_active
|
||||
end
|
||||
end
|
||||
|
||||
it "is deferrable from `active'" do
|
||||
todo = create_todo
|
||||
todo.activate!
|
||||
todo.should be_active
|
||||
todo.defer!
|
||||
todo.should be_deferred
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when toggling completion' do
|
||||
it 'toggles to active when completed' do
|
||||
todo = create_todo
|
||||
todo.complete!
|
||||
todo.should be_completed
|
||||
todo.toggle_completion!
|
||||
todo.should be_active
|
||||
end
|
||||
|
||||
it 'toggles to completed when not completed' do
|
||||
todo = create_todo
|
||||
todo.should_not be_completed
|
||||
todo.toggle_completion!
|
||||
todo.should be_completed
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when retrieving project' do
|
||||
it 'returns project if set' do
|
||||
project = mock_model(Project)
|
||||
todo = Todo.new(:project => project)
|
||||
todo.project.should == project
|
||||
end
|
||||
|
||||
it 'returns a NullProject if not set' do
|
||||
Todo.new.project.should be_an_instance_of(NullProject)
|
||||
end
|
||||
end
|
||||
|
||||
describe('when setting show_from') { it 'is speced' }
|
||||
|
||||
it 'is starred if tag is "starred"' do
|
||||
todo = create_todo
|
||||
todo.should_not be_starred
|
||||
todo.add_tag('starred')
|
||||
todo.reload
|
||||
todo.should be_starred
|
||||
end
|
||||
|
||||
describe 'when toggling star flag' do
|
||||
it 'toggles to not starred when starred' do
|
||||
todo = create_todo
|
||||
todo.add_tag('starred')
|
||||
todo.should be_starred
|
||||
todo.toggle_star!
|
||||
todo.reload
|
||||
todo.should_not be_starred
|
||||
end
|
||||
|
||||
it 'toggles to starred when not starred' do
|
||||
todo = create_todo
|
||||
todo.should_not be_starred
|
||||
todo.toggle_star!
|
||||
todo.reload
|
||||
todo.should be_starred
|
||||
end
|
||||
end
|
||||
end
|
||||
181
spec/models/user_spec.rb
Normal file
181
spec/models/user_spec.rb
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
||||
|
||||
describe User do
|
||||
def valid_attributes(attributes={})
|
||||
{
|
||||
:login => 'simon',
|
||||
:password => 'foobarspam',
|
||||
:password_confirmation => 'foobarspam'
|
||||
}.merge(attributes)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
@user = User.new
|
||||
end
|
||||
|
||||
describe 'associations' do
|
||||
it 'has many contexts' do
|
||||
User.should have_many(:contexts).
|
||||
with_order('position ASC').
|
||||
with_dependent(:delete_all)
|
||||
end
|
||||
|
||||
it 'has many projects' do
|
||||
User.should have_many(:projects).
|
||||
with_order('projects.position ASC').
|
||||
with_dependent(:delete_all)
|
||||
end
|
||||
|
||||
# TODO: uses fixtures to test those
|
||||
it 'has many active_projects' do
|
||||
User.should have_many(:active_projects).
|
||||
with_order('projects.position ASC').
|
||||
with_conditions('state = ?', 'active').
|
||||
with_class_name('Project')
|
||||
end
|
||||
|
||||
it 'has many active contexts' do
|
||||
User.should have_many(:active_contexts).
|
||||
with_order('position ASC').
|
||||
with_conditions('hide = ?', 'true').
|
||||
with_class_name('Context')
|
||||
end
|
||||
|
||||
it 'has many todos' do
|
||||
User.should have_many(:todos).
|
||||
with_order('todos.completed_at DESC, todos.created_at DESC').
|
||||
with_dependent(:delete_all)
|
||||
end
|
||||
|
||||
it 'has many deferred todos' do
|
||||
User.should have_many(:deferred_todos).
|
||||
with_order('show_from ASC, todos.created_at DESC').
|
||||
with_conditions('state = ?', 'deferred').
|
||||
with_class_name('Todo')
|
||||
end
|
||||
|
||||
it 'has many completed todos' do
|
||||
User.should have_many(:completed_todos).
|
||||
with_order('todos.completed_at DESC').
|
||||
with_conditions('todos.state = ? and todos.completed_at is not null', 'completed').
|
||||
with_include(:project, :context).
|
||||
with_class_name('Todo')
|
||||
end
|
||||
|
||||
it 'has many notes' do
|
||||
User.should have_many(:notes).
|
||||
with_order('created_at DESC').
|
||||
with_dependent(:delete_all)
|
||||
end
|
||||
|
||||
it 'has many taggings' do
|
||||
User.should have_many(:taggings)
|
||||
end
|
||||
|
||||
it 'has many tags through taggings' do
|
||||
User.should have_many(:tags).through(:taggings).with_select('DISTINCT tags.*')
|
||||
end
|
||||
|
||||
it 'has one preference' do
|
||||
User.should have_one(:preference)
|
||||
end
|
||||
end
|
||||
|
||||
it_should_validate_presence_of :login
|
||||
it_should_validate_presence_of :password
|
||||
it_should_validate_presence_of :password_confirmation
|
||||
|
||||
it_should_validate_length_of :password, :within => 5..40
|
||||
it_should_validate_length_of :login, :within => 3..80
|
||||
|
||||
it_should_validate_uniqueness_of :login
|
||||
it_should_validate_confirmation_of :password
|
||||
|
||||
it 'validates presence of password only when password is required'
|
||||
it 'validates presence of password_confirmation only when password is required'
|
||||
it 'validates confirmation of password only when password is required'
|
||||
it 'validates presence of open_id_url only when using openid'
|
||||
|
||||
it 'accepts only allow auth_type authorized by the admin' do
|
||||
Tracks::Config.should_receive(:auth_schemes).exactly(3).times.and_return(%w(database open_id))
|
||||
User.new(valid_attributes(:auth_type => 'database')).should_not have(:any).error_on(:auth_type)
|
||||
User.new(valid_attributes(:auth_type => 'open_id')).should_not have(:any).error_on(:auth_type)
|
||||
User.new(valid_attributes(:auth_type => 'ldap')).should have(1).error_on(:auth_type)
|
||||
end
|
||||
|
||||
it 'returns login for #to_param' do
|
||||
@user.login = 'john'
|
||||
@user.to_param.should == 'john'
|
||||
end
|
||||
|
||||
it 'has a custom finder to find admin' do
|
||||
User.should_receive(:find).with(:first, :conditions => ['is_admin = ?', true])
|
||||
User.find_admin
|
||||
end
|
||||
|
||||
it 'has a custom finder to find by openid url'
|
||||
it 'knows if there is any user through #no_users_yet? (TODO: better description)'
|
||||
|
||||
describe 'when choosing what do display as a name' do
|
||||
it 'displays login when no first name and last name' do
|
||||
User.new(valid_attributes).display_name.should == 'simon'
|
||||
end
|
||||
|
||||
it 'displays last name when no first name' do
|
||||
User.new(valid_attributes(:last_name => 'foo')).display_name.should == 'foo'
|
||||
end
|
||||
|
||||
it 'displays first name when no last name' do
|
||||
User.new(valid_attributes(:first_name => 'bar')).display_name.should == 'bar'
|
||||
end
|
||||
|
||||
it 'displays first name and last name when both specified' do
|
||||
User.new(valid_attributes(:first_name => 'foo', :last_name => 'bar')).display_name.should == 'foo bar'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'authentication' do
|
||||
before(:each) do
|
||||
@user = User.create!(valid_attributes)
|
||||
end
|
||||
|
||||
it 'authenticates user' do
|
||||
User.authenticate('simon', 'foobarspam').should == @user
|
||||
end
|
||||
|
||||
it 'resets password' do
|
||||
@user.update_attributes(
|
||||
:password => 'new password',
|
||||
:password_confirmation => 'new password'
|
||||
)
|
||||
User.authenticate('simon', 'new password').should == @user
|
||||
end
|
||||
|
||||
it 'does not rehash password after update of login' do
|
||||
@user.update_attribute(:login, 'foobar')
|
||||
User.authenticate('foobar', 'foobarspam').should == @user
|
||||
end
|
||||
|
||||
it 'sets remember token' do
|
||||
@user.remember_me
|
||||
@user.remember_token.should_not be_nil
|
||||
@user.remember_token_expires_at.should_not be_nil
|
||||
end
|
||||
|
||||
it 'unsets remember token' do
|
||||
@user.remember_me
|
||||
@user.remember_token.should_not be_nil
|
||||
@user.forget_me
|
||||
@user.remember_token.should be_nil
|
||||
end
|
||||
|
||||
it 'remembers me default two weeks' do
|
||||
before = 2.weeks.from_now.utc
|
||||
@user.remember_me
|
||||
after = 2.weeks.from_now.utc
|
||||
@user.remember_token.should_not be_nil
|
||||
@user.remember_token_expires_at.should_not be_nil
|
||||
@user.remember_token_expires_at.should be_between(before, after)
|
||||
end
|
||||
end
|
||||
end
|
||||
19
spec/scenarios/contexts_scenario.rb
Normal file
19
spec/scenarios/contexts_scenario.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
class ContextsScenario < Scenario::Base
|
||||
uses :users
|
||||
|
||||
def load
|
||||
%w(Call Email Errand Someday).each_with_index do |context, index|
|
||||
create_context context, index+1
|
||||
end
|
||||
end
|
||||
|
||||
def create_context(name, position)
|
||||
create_model :context, name.downcase.to_sym,
|
||||
:name => name,
|
||||
:position => position,
|
||||
:hide => name == 'Someday' ? true : false,
|
||||
:created_at => Time.now,
|
||||
:updated_at => Time.now,
|
||||
:user_id => user_id(:sean)
|
||||
end
|
||||
end
|
||||
20
spec/scenarios/projects_scenario.rb
Normal file
20
spec/scenarios/projects_scenario.rb
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
class ProjectsScenario < Scenario::Base
|
||||
def load
|
||||
create_project :build_time_machine, 'Build a working time machine'
|
||||
create_project :make_more_money, 'Make more money than Billy Gates'
|
||||
create_project :evict_dinosaurs, 'Evict dinosaurs from the garden'
|
||||
create_project :attend_railsconf, 'Attend RailsConf'
|
||||
end
|
||||
|
||||
def create_project(identifier, name)
|
||||
attributes = {
|
||||
:name => name,
|
||||
:state => 'active',
|
||||
:created_at => 4.day.ago,
|
||||
:updated_at => 1.minute.ago
|
||||
}
|
||||
create_model :project,
|
||||
identifier || attributes[:name].split.first.downcase.to_sym,
|
||||
attributes
|
||||
end
|
||||
end
|
||||
30
spec/scenarios/todos_scenario.rb
Normal file
30
spec/scenarios/todos_scenario.rb
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
class TodosScenario < Scenario::Base
|
||||
uses :contexts, :projects, :users
|
||||
|
||||
def load
|
||||
create_todo :bill,
|
||||
:description => 'Call Bill Gates to find out how much he makes per day',
|
||||
:user => :sean,
|
||||
:context => :call,
|
||||
:project => :make_more_money
|
||||
create_todo :bank,
|
||||
:description => 'Call my bank',
|
||||
:user => :sean,
|
||||
:context => :call,
|
||||
:project => :make_more_money
|
||||
end
|
||||
|
||||
def create_todo(identifier, options={})
|
||||
context = options.delete(:context)
|
||||
project = options.delete(:project)
|
||||
user = options.delete(:user)
|
||||
attributes = {
|
||||
:state => 'active',
|
||||
:created_at => 1.week.ago,
|
||||
:context_id => context_id(context),
|
||||
:project_id => project_id(project),
|
||||
:user_id => user_id(user)
|
||||
}.merge(options)
|
||||
create_model :todo, identifier, attributes
|
||||
end
|
||||
end
|
||||
19
spec/scenarios/users_scenario.rb
Normal file
19
spec/scenarios/users_scenario.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
class UsersScenario < Scenario::Base
|
||||
def load
|
||||
create_user :login => 'johnny', :first_name => 'Johnny', :last_name => 'Smith'
|
||||
create_user :login => 'jane', :first_name => 'Jane', :last_name => 'Pilbeam'
|
||||
create_user :login => 'sean', :first_name => 'Sean', :last_name => 'Pallmer'
|
||||
end
|
||||
|
||||
def create_user(attributes={})
|
||||
password = attributes[:login] + Time.now.to_s
|
||||
attributes = {
|
||||
:password => password,
|
||||
:password_confirmation => password,
|
||||
:is_admin => attributes[:is_admin] || false,
|
||||
}.merge(attributes)
|
||||
identifier = attributes[:login].downcase.to_sym
|
||||
user = create_model :user, identifier, attributes
|
||||
Preference.create(:show_number_completed => 5, :user => user)
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue