diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..4e1e0d2 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--color diff --git a/Gemfile b/Gemfile index 2aa838c..d020d13 100755 --- a/Gemfile +++ b/Gemfile @@ -1,12 +1,16 @@ -source 'http://rubygems.org' -source 'http://gems.github.com' +## ----------------------------------- +## Uncomment content of this Gemfile +## only if you need to run plugin specs. +## ----------------------------------- -group :test do - gem 'rake' - gem 'sqlite3' - gem 'rspec', "~> 2.10.0" - gem 'rspec-rails', "~> 2.10.0" - gem 'factory_girl', "~>3.5.0" - gem 'database_cleaner' - gem 'RedCloth' -end +#redmine_root = ENV["REDMINE_ROOT"] || File.dirname(__FILE__) + "/../../" +#eval File.read File.expand_path(redmine_root + 'Gemfile', __FILE__) + +#group :test do + #gem 'rspec', "~> 2.14.0" + #gem 'rspec-rails', "~> 2.14.0" + #gem 'factory_girl', "~> 2.3.2" + #gem 'database_cleaner' + #gem 'mysql2' + #gem 'pry' +#end diff --git a/Gemfile.lock b/Gemfile.lock index 224d729..83f331d 100755 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,83 +1,7 @@ GEM - remote: http://rubygems.org/ - remote: http://gems.github.com/ specs: - RedCloth (4.2.9) - actionpack (3.2.6) - activemodel (= 3.2.6) - activesupport (= 3.2.6) - builder (~> 3.0.0) - erubis (~> 2.7.0) - journey (~> 1.0.1) - rack (~> 1.4.0) - rack-cache (~> 1.2) - rack-test (~> 0.6.1) - sprockets (~> 2.1.3) - activemodel (3.2.6) - activesupport (= 3.2.6) - builder (~> 3.0.0) - activesupport (3.2.6) - i18n (~> 0.6) - multi_json (~> 1.0) - builder (3.0.0) - database_cleaner (0.6.7) - diff-lcs (1.1.3) - erubis (2.7.0) - factory_girl (3.5.0) - activesupport (>= 3.0.0) - hike (1.2.1) - i18n (0.6.0) - journey (1.0.4) - json (1.7.3) - multi_json (1.3.6) - mysql2 (0.3.11) - rack (1.4.1) - rack-cache (1.2) - rack (>= 0.4) - rack-ssl (1.3.2) - rack - rack-test (0.6.1) - rack (>= 1.0) - railties (3.2.6) - actionpack (= 3.2.6) - activesupport (= 3.2.6) - rack-ssl (~> 1.3.2) - rake (>= 0.8.7) - rdoc (~> 3.4) - thor (>= 0.14.6, < 2.0) - rake (0.9.2) - rdoc (3.12) - json (~> 1.4) - rspec (2.10.0) - rspec-core (~> 2.10.0) - rspec-expectations (~> 2.10.0) - rspec-mocks (~> 2.10.0) - rspec-core (2.10.1) - rspec-expectations (2.10.0) - diff-lcs (~> 1.1.3) - rspec-mocks (2.10.1) - rspec-rails (2.10.1) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec (~> 2.10.0) - sprockets (2.1.3) - hike (~> 1.2) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sqlite3 (1.3.4) - thor (0.15.4) - tilt (1.3.3) PLATFORMS ruby DEPENDENCIES - RedCloth (~> 4.2.9) - database_cleaner - factory_girl (~> 3.5.0) - mysql2 - rake - rspec (~> 2.10.0) - rspec-rails (~> 2.10.0) - sqlite3 diff --git a/README.rdoc b/README.rdoc index b557c6a..99e2b17 100755 --- a/README.rdoc +++ b/README.rdoc @@ -17,7 +17,7 @@ The plugin improves functionality of Redmine Gantt Chart. == Compatibility -Tested with Redmine versions: 1.1.0, 1.1.1, 1.1.2, 1.1.3, 1.2, 1.3, 1.4 +Tested with Redmine versions: 1.1.0, 1.1.1, 1.1.2, 1.1.3, 1.2, 1.3, 1.4, 2.1, 2.2, 2.3 == Installation and Setup @@ -60,6 +60,13 @@ New setting *Work on weekends* introduced in v.0.6. If you notice any problems, please report them to the GitHub issue tracker {here}[https://github.com/kulesa/redmine_better_gantt_chart/issues]. Feel free to contact me via GitHub or Twitter or whatever with any other questions or feature requests. To submit changes fork the project and send a pull request. +=== Running specs + +To run specs, + +- go to the plugin folder, uncomment content of Gemfile, run `bundle` +- run `bundle exec rspec`. + == Contributors Thanks to Jeremy Subtil ({BigMadWolf}[https://github.com/BigMadWolf]) for contributing a patch for displaying connections between cross-project related issues. diff --git a/init.rb b/init.rb index 17c0984..1cb0225 100755 --- a/init.rb +++ b/init.rb @@ -22,10 +22,10 @@ name 'Redmine Better Gantt Chart plugin' author 'Alexey Kuleshov' description 'This plugin improves Redmine Gantt Chart' - version '0.7.0' + version '0.9.0' url 'https://github.com/kulesa/redmine_better_gantt_chart' author_url 'http://github.com/kulesa' - + requires_redmine :version_or_higher => '1.1.0' settings(:default => { diff --git a/spec/controllers/gantts_controller_spec.rb b/spec/controllers/gantts_controller_spec.rb index d6a8b1a..941014e 100755 --- a/spec/controllers/gantts_controller_spec.rb +++ b/spec/controllers/gantts_controller_spec.rb @@ -2,79 +2,88 @@ describe GanttsController, '#show' do include Redmine::I18n - integrate_views - - before(:all) do + render_views + + before(:all) do # Precedes - Follows @preceding_issue, @following_issue = create_related_issues("precedes") - + # Blocks - Blocked @blocks_issue, @blocked_issue = create_related_issues("blocks") - + # Duplicates - Duplicated @duplicates_issue, @duplicated_issue = create_related_issues("duplicates") # Relates @one_issue, @other_issue = create_related_issues("relates") end - + before(:each) do - @current_user = mock_model(User, :admin? => true, :logged? => true, :language => :en, :active? => true, :memberships => [], :anonymous? => false, :name => "A Test >User", :projects => Project) - User.stub!(:current).and_return(@current_user) - @current_user.stub!(:allowed_to?).and_return(true) - @current_user.stub!(:pref).and_return(Factory(:user_preference, :user_id => @current_user.id)) + @current_user = mock_model(User, :admin? => true, + :logged? => true, + :language => :en, + :active? => true, + :memberships => [], + :anonymous? => false, + :name => "A Test >User", + :projects => Project, + :groups => [], + :css_classes => 'user_active') + User.stub(:current).and_return(@current_user) + @current_user.stub(:allowed_to?).and_return(true) + @current_user.stub(:pref).and_return(Factory(:user_preference, :user_id => @current_user.id)) end it 'should be successful' do get :show - response.should be_success + response.status.should == 200 end - it 'should have custom javascripts included' do + it 'should have custom javascripts included' do get :show - response.should have_text(/raphael.min.js/) - response.should have_text(/raphael.arrow.js/) + response.body.should have_text(/raphael.min.js/) + response.body.should have_text(/raphael.arrow.js/) end - + it 'should insert issue ids and follow tags' do get :show - response.should have_text(/div id='#{@preceding_issue.id}'/) - response.should have_text(/div id='#{@following_issue.id}' follows='#{@preceding_issue.id}'/) + response.body.should have_text(/div id='#{@preceding_issue.id}'/) + response.body.should have_text(/div id='#{@following_issue.id}' follows='#{@preceding_issue.id}'/) end - + it 'should insert blocked tags' do get :show - response.should have_text(/div id='#{@blocks_issue.id}'/) - response.should have_text(/div id='#{@blocked_issue.id}' blocked='#{@blocks_issue.id}'/) + response.body.should have_text(/div id='#{@blocks_issue.id}'/) + response.body.should have_text(/div id='#{@blocked_issue.id}' blocked='#{@blocks_issue.id}'/) end - + it 'should insert duplicated tags' do get :show - response.should have_text(/div id='#{@duplicates_issue.id}'/) - response.should have_text(/div id='#{@duplicated_issue.id}' duplicated='#{@duplicates_issue.id}'/) + response.body.should have_text(/div id='#{@duplicates_issue.id}'/) + response.body.should have_text(/div id='#{@duplicated_issue.id}' duplicated='#{@duplicates_issue.id}'/) end - + it 'should insert relates tags' do get :show - response.should have_text(/div id='#{@one_issue.id}'/) - response.should have_text(/div id='#{@other_issue.id}' relates='#{@one_issue.id}'/) + response.body.should have_text(/div id='#{@one_issue.id}'/) + response.body.should have_text(/div id='#{@other_issue.id}' relates='#{@one_issue.id}'/) end - + it 'should insert an array of ids to a tag' do @blocks_issue.relations << IssueRelation.create!(:issue_from => @blocks_issue, :issue_to => @duplicated_issue, :relation_type => "duplicates", :delay => 0) @blocks_issue.save! get :show - response.should have_text(/duplicated='#{@duplicates_issue.id},#{@blocks_issue.id}'/) + response.body.should have_text(/duplicated='#{@duplicates_issue.id},#{@blocks_issue.id}'/) end - it 'should mix different relation types' do + it 'should mix different relation types' do @blocks_issue.relations << IssueRelation.create!(:issue_from => @blocks_issue, :issue_to => @duplicated_issue, :relation_type => "duplicates", :delay => 0) @blocks_issue.save! @one_issue.relations << IssueRelation.create!(:issue_from => @one_issue, :issue_to => @duplicated_issue, :relation_type => "relates") @one_issue.save! get :show - response.should have_text(/duplicated='#{@duplicates_issue.id},#{@blocks_issue.id}' relates='#{@one_issue.id}'|relates='#{@one_issue.id}' duplicated='#{@duplicates_issue.id},#{@blocks_issue.id}'/) + response.body.should have_text(/duplicated='#{@duplicates_issue.id},#{@blocks_issue.id}' relates='#{@one_issue.id}'|relates='#{@one_issue.id}' duplicated='#{@duplicates_issue.id},#{@blocks_issue.id}'/) end end diff --git a/spec/controllers/issues_controller_spec.rb b/spec/controllers/issues_controller_spec.rb index 6ab13c9..0bf5a38 100755 --- a/spec/controllers/issues_controller_spec.rb +++ b/spec/controllers/issues_controller_spec.rb @@ -2,15 +2,14 @@ describe IssuesController do include Redmine::I18n - integrate_views + render_views before(:each) do @current_user = Factory :user - #@current_user = mock_model(User, :admin? => true, :logged? => true, :language => :en, :active? => true, :memberships => [], :anonymous? => false, :name => "A Test >User", :projects => Project) - User.stub!(:current).and_return(@current_user) - @current_user.stub!(:allowed_to?).and_return(true) - @current_user.stub!(:pref).and_return(Factory(:user_preference, :user_id => @current_user.id)) - @current_user.stub!(:mail) + User.stub(:current).and_return(@current_user) + @current_user.stub(:allowed_to?).and_return(true) + @current_user.stub(:pref).and_return(Factory(:user_preference, :user_id => @current_user.id)) + @current_user.stub(:mail) end let!(:issue) { Factory(:issue) } diff --git a/spec/factories.rb b/spec/factories.rb index 13ace33..ceb2e20 100755 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -4,7 +4,7 @@ single_instances = lambda do |factory_key| begin saved_single_instances[factory_key].reload - rescue NoMethodError, ActiveRecord::RecordNotFound + rescue NoMethodError, ActiveRecord::RecordNotFound #was never created (is nil) or was cleared from db saved_single_instances[factory_key] = Factory.create(factory_key) #recreate end @@ -13,68 +13,73 @@ end def test_time - @test_time ||= Time.new() + @test_time ||= Time.zone.now.to_date end -Factory.define :user_preference do |p| - p.time_zone '' - p.hide_mail false - p.others {{:gantt_months=>6, :comments_sorting=>"asc", :gantt_zoom=>3, :no_self_notified=>true}} -end +FactoryGirl.define do + factory :user_preference do + time_zone '' + hide_mail false + others {{:gantt_months=>6, :comments_sorting=>"asc", :gantt_zoom=>3, :no_self_notified=>true}} + end -Factory.define :user do |u| - u.sequence(:firstname) {|n| "John#{n}"} - u.lastname 'Kilmer' - u.sequence(:login) {|n| "john_#{n}"} - u.sequence(:mail) {|n| "john#{n}@local.com"} - u.association :preference, :factory => :user_preference -end + factory :user do + sequence(:firstname) {|n| "John#{n}"} + lastname 'Kilmer' + sequence(:login) {|n| "john_#{n}"} + sequence(:mail) {|n| "john#{n}@local.com"} + after_create do |u| + Factory(:user_preference, :user => u) + end + end -Factory.define :admin, :parent => :user do |u| - u.admin true -end + factory :admin, :parent => :user do + admin true + end -Factory.define :project do |p| - p.sequence(:name) {|n| "project#{n}"} - p.identifier {|u| u.name } - p.is_public true - # enabled_modules -end + factory :project do + sequence(:name) {|n| "project#{n}"} + identifier {|u| u.name } + is_public true + end -Factory.define :tracker do |t| - t.sequence(:name) { |n| "Feature #{n}" } - t.sequence(:position) {|n| n} -end + factory :tracker do + sequence(:name) { |n| "Feature #{n}" } + sequence(:position) {|n| n} + end -Factory.define :bug, :parent => :tracker do |t| - t.name 'Bug' -end + factory :bug, :parent => :tracker do + name 'Bug' + end -Factory.define :main_project, :parent => :project do |project| - project.name 'The Main Project' - project.identifier 'supaproject' - project.after_create { |p| p.trackers << single_instances[:bug]; p.save! } -end + factory :main_project, :parent => :project do + name 'The Main Project' + identifier 'supaproject' + after_create do |p| + p.trackers << single_instances[:bug]; p.save! + end + end -Factory.define :issue_priority do |i| - i.sequence(:name) {|n| "Issue#{n}"} -end + factory :issue_priority do + sequence(:name) {|n| "Issue#{n}"} + end -Factory.define :issue_status do |s| - s.sequence(:name) {|n| "status#{n}"} - s.is_closed false - s.is_default false - s.sequence(:position) {|n| n} -end + factory :issue_status do + sequence(:name) {|n| "status#{n}"} + is_closed false + is_default false + sequence(:position) {|n| n} + end -Factory.define :issue do |i| - i.sequence(:subject) {|n| "Issue_no_#{n}"} - i.description {|u| u.subject} - i.project { single_instances[:main_project] } - i.tracker { single_instances[:bug] } - i.association :priority, :factory => :issue_priority - i.association :status, :factory => :issue_status - i.association :author, :factory => :user - i.start_date { test_time } - i.due_date { |u| u.start_date + 3.days} + factory :issue do + sequence(:subject) {|n| "Issue_no_#{n}"} + description {|u| u.subject} + project { single_instances[:main_project] } + tracker { single_instances[:bug] } + priority { Factory(:issue_priority) } + status { Factory(:issue_status) } + author { Factory(:user) } + start_date test_time + due_date { |u| u.start_date + 3.days} + end end diff --git a/spec/models/issue_patch_spec.rb b/spec/models/issue_patch_spec.rb index 4c72b80..28e1303 100755 --- a/spec/models/issue_patch_spec.rb +++ b/spec/models/issue_patch_spec.rb @@ -6,7 +6,7 @@ work_on_weekends true end - before(:each) do + before(:each) do @first_issue, @second_issue = create_related_issues("precedes") end @@ -34,10 +34,10 @@ it 'doesn\'t allow set start date earlier than parent.soonest_start' do child_issue = Factory.build(:issue) child_issue.parent_issue_id = @second_issue.id - lambda { + expect { child_issue.start_date = @second_issue.start_date - 1 child_issue.save! - }.should raise_error(ActiveRecord::RecordInvalid) + }.to raise_error(ActiveRecord::RecordInvalid) end it "doesn't fail when removing an only child issue from the parent" do @@ -47,10 +47,10 @@ child_issue.save! parent_issue.reload - lambda { + expect { child_issue.parent_issue_id = nil child_issue.save! - }.should_not raise_error(NoMethodError) + }.not_to raise_error() end it "doesn't fail when assigning start_date to a child issue when parent's start_date is empty and siblings' start_dates are empty" do @@ -63,10 +63,10 @@ child_issue2.save! parent_issue.reload - lambda { + expect { child_issue1.start_date = Date.today child_issue1.save! - }.should_not raise_error(ArgumentError) + }.not_to raise_error() end it "doesn't fail when start_date of an issue deep in hierarchy is changed from empty" do @@ -92,20 +92,20 @@ child_issue2_1.save! child_issue2_2.save! - lambda { + expect { child_issue2_2.start_date = Date.today child_issue2_2.save! - }.should_not raise_error(ArgumentError) + }.not_to raise_error() end it "doesn't fail when an issue without start or due date becomes a parent issue" do parent_issue = Factory(:issue, :start_date => nil, :due_date => nil) child_issue = Factory(:issue, :due_date => nil) - lambda { + expect { child_issue.parent_issue_id = parent_issue.id child_issue.save! - }.should_not raise_error(NoMethodError) + }.not_to raise_error() end describe 'handles long dependency chains' do @@ -136,9 +136,9 @@ end it 'and doesn\'t allow create circular dependencies' do - lambda { + expect { create_related_issues("precedes", @current_issue, @start_issue) - }.should raise_error(ActiveRecord::RecordInvalid) + }.to raise_error(ActiveRecord::RecordInvalid) end end @@ -174,7 +174,7 @@ }.should change(@child2, :start_date).to(@child2.start_date - 2.days) end - it "should not fail when due_date of one of rescheduled issues is nil" do + it "should not fail when due_date of one of rescheduled issues is nil" do initial, child = create_related_issues("precedes") parent = Factory(:issue, :due_date => nil) other_child = Factory(:issue, :due_date => nil) @@ -212,7 +212,7 @@ parent_b.reload parent_start = parent_b.start_date - parent_due = parent_b.due_date + parent_due = parent_b.due_date child_a.due_date = child_a.due_date - 2.days child_a.save! @@ -224,7 +224,7 @@ it "should reshedule a following task of a parent task, when the parent task itself being rescheduled after changes in it's child task" do parent = Factory(:issue) - child = Factory(:issue, :start_date => Date.today, + child = Factory(:issue, :start_date => Date.today, :due_date => Date.today + 1, :parent_issue_id => parent.id) follower = Factory(:issue, :start_date => Date.today, :due_date => Date.today + 1) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index be27245..e120ffd 100755 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,38 +1,29 @@ # This file is copied to ~/spec when you run 'ruby script/generate rspec' # from the project root directory. ENV["RAILS_ENV"] = "test" +require 'active_record' +require 'active_record/connection_adapters/abstract_adapter' +require 'active_record/connection_adapters/abstract_mysql_adapter' # Allows loading of an environment config based on the environment -redmine_root = ENV["REDMINE_ROOT"] || File.dirname(__FILE__) + "/../../../.." -require File.expand_path(redmine_root + "/config/environment") -require 'spec' -require 'spec/rails' +redmine_root = ENV["REDMINE_ROOT"] || File.dirname(__FILE__) + "/../../.." +require File.expand_path(redmine_root + "/config/environment", __FILE__) +require 'rspec/rails' require 'factory_girl' -require 'database_cleaner' require File.expand_path(File.dirname(__FILE__) + '/factories.rb') require File.expand_path(File.dirname(__FILE__) + '/helpers') -Spec::Runner.configure do |config| +RSpec.configure do |config| + config.use_transactional_fixtures = false + require 'database_cleaner' DatabaseCleaner.strategy = :truncation - config.use_transactional_fixtures = true - config.use_instantiated_fixtures = false - config.fixture_path = RAILS_ROOT + '/spec/fixtures/' config.include Helpers + config.treat_symbols_as_metadata_keys_with_true_values = true + config.run_all_when_everything_filtered = true + config.filter_run_including :focus => true - config.before(:suite) do + config.before(:suite) do DatabaseCleaner.clean end - - config.after(:suite) do - end -end - -# require the entire app if we're running under coverage testing, -# so we measure 0% covered files in the report -# -# http://www.pervasivecode.com/blog/2008/05/16/making-rcov-measure-your-whole-rails-app-even-if-tests-miss-entire-source-files/ -if defined?(Rcov) - all_app_files = Dir.glob('{app,lib}/**/*.rb') - all_app_files.each{|rb| require rb} end