cavalle / steak

DISCONTINUED - The delicious combination of RSpec and Capybara for Acceptance BDD
MIT License
763 stars 32 forks source link

Steak acceptance test suite runs two times #55

Open dcvezzani opened 8 years ago

dcvezzani commented 8 years ago

With rake, usually this means that there are two tasks with the same label.

pasted_image_12_30_15__12_00_pm

A little investigation. What is the task label?

rake -T accept

=> 
rake spec:acceptance  # Run the code examples in spec/acceptance / Run the acceptance specs in spec/acceptance

It turns out that when a task is created more than one time that ' / ' is used to separate the descriptions.

Where is the task defined?

rake -W spec:acceptance

=> 
rake spec:acceptance                /Users/davidvezzani/.rvm/gems/ruby-2.2.0/gems/rspec-core-3.3.2/lib/rspec/core/rake_task.rb:84:in `define'
rake spec:acceptance                /Users/davidvezzani/.rvm/gems/ruby-2.2.0/gems/rspec-core-3.3.2/lib/rspec/core/rake_task.rb:84:in `define'

Hmm. Two different places, but they are both the same. Probably because they are dynamically created tasks using a block looking something like this.

desc 'Run the acceptance specs in spec/acceptance'
RSpec::Core::RakeTask.new(:acceptance => 'db:test:prepare') do |t|
  t.pattern = 'spec/acceptance/**/*_spec.rb'
end

So what code is actually dynamically creating the spec:acceptance task? By trial and error including/excluding entries in Gemfile, we discover that this situation arises when steak is included. Looking at the source code for steak, we find a rake task. The description reflects the latter half of the description displayed when we originally listed all the rake tasks, so we're probably in the right place. So where is the first one defined?

If we comment out the definition in steak_tasks.rake, we can verify there is still some code somewhere that is defining spec:acceptance.

vim ~/.rvm/gems/ruby-2.2.0/gems/steak-2.0.0/lib/tasks/steak_tasks.rake

  # desc 'Run the acceptance specs in spec/acceptance'
  # RSpec::Core::RakeTask.new(:acceptance => 'db:test:prepare') do |t|
  #   t.pattern = 'spec/acceptance/**/*_spec.rb'
  # end

rake -T accept

rake spec:acceptance  # Run the code examples in spec/acceptance

The description no longer includes the description used in steak_tasks.rake. Now we have to hunt down the other code. Casting a large net, we search in all the gems for the current ruby environment.

cd ~/.rvm/gems/ruby-2.2.0/gems
grep -r 'Run the code examples in spec/acceptance' .

=> 
<nothing>

grep -r 'Run the code examples in' .

=> 
./rspec-rails-2.99.0/lib/rspec/rails/tasks/rspec.rake:    desc "Run the code examples in #{dir}"

Bingo! We found it. It seems that tasks are created for each subdirectory that is in the spec directory.

less ~/.rvm/gems/ruby-2.2.0/gems/rspec-rails-3.3.0/lib/rspec/rails/tasks/rspec.rake

=> 
namespace :spec do
  types = begin
            dirs = Dir['./spec/**/*_spec.rb'].
              map { |f| f.sub(/^\.\/(spec\/\w+)\/.*/, '\\1') }.
              uniq.
              select { |f| File.directory?(f) }
            Hash[dirs.map { |d| [d.split('/').last, d] }]
          end

  ...

  types.each do |type, dir|
    desc "Run the code examples in #{dir}"
    RSpec::Core::RakeTask.new(type => "spec:prepare") do |t|
      t.pattern = "./#{dir}/**/*_spec.rb"
    end
  end

Solution?