Closed5
Capybaraとrspec-rails
Gemfile
group :test do
gem 'rspec-rails'
end
あえてCapybaraなし
$ bundle exec rails g rspec:install
Running via Spring preloader in process 43250
create .rspec
create spec
create spec/spec_helper.rb
create spec/rails_helper.rb
spec/features/example_spec.rb
require 'rails_helper'
describe 'example' do
it { |example|
require 'pry'
binding.pry
}
end
止めてみる。
$ bundle exec rspec spec/features/example_spec.rb
From: /Users/yusuke-iwaki/Desktop/railsfeature/spec/features/example_spec.rb:6 :
1: require 'rails_helper'
2:
3: describe 'example' do
4: it { |example|
5: require 'pry'
=> 6: binding.pry
7: }
8: end
[1] pry(#<RSpec::ExampleGroups::Example>)> example.metadata
=> {:block=>#<Proc:0x00007fe95746bf98 /Users/yusuke-iwaki/Desktop/railsfeature/spec/features/example_spec.rb:4>,
:description_args=>[],
:description=>"",
:full_description=>"example ",
:described_class=>nil,
:file_path=>"./spec/features/example_spec.rb",
:line_number=>4,
:location=>"./spec/features/example_spec.rb:4",
:absolute_file_path=>"/Users/yusuke-iwaki/Desktop/railsfeature/spec/features/example_spec.rb",
:rerun_file_path=>"./spec/features/example_spec.rb",
:scoped_id=>"1:1",
:type=>:feature,
:execution_result=>
#<RSpec::Core::Example::ExecutionResult:0x00007fe95746bca0 @started_at=2021-07-21 21:19:54.470283 +0900>,
:example_group=>
{:block=>#<Proc:0x00007fe95744a960 /Users/yusuke-iwaki/Desktop/railsfeature/spec/features/example_spec.rb:3>,
:description_args=>["example"],
:description=>"example",
:full_description=>"example",
:described_class=>nil,
:file_path=>"./spec/features/example_spec.rb",
:line_number=>3,
:location=>"./spec/features/example_spec.rb:3",
:absolute_file_path=>"/Users/yusuke-iwaki/Desktop/railsfeature/spec/features/example_spec.rb",
:rerun_file_path=>"./spec/features/example_spec.rb",
:scoped_id=>"1",
:type=>:feature},
:shared_group_inclusion_backtrace=>[],
:last_run_status=>"unknown"}
https://github.com/rspec/rspec-rails/blob/fe95eacb376f7fa558d3ffeeaa9afa6d3110a540/lib/rspec/rails/configuration.rb#L38 ここでrspec-railsが指定している type: :feature
が付与されているが、サーバーなどは特に起動してなさそう。
Capybara::DSLのロードは Capybara側でやっているが、今回はCapybaraを入れていないので、この処理は走らない。
RSpec.configure do |config|
config.include Capybara::DSL, type: :feature
config.include Capybara::RSpecMatchers, type: :feature
config.include Capybara::DSL, type: :system
config.include Capybara::RSpecMatchers, type: :system
config.include Capybara::RSpecMatchers, type: :view
RailsのSystemTestCase側からどうなってるか見てみる。
actionpack/lib/action_dispatch/system_test_case.rb
def self.start_application # :nodoc:
Capybara.app = Rack::Builder.new do
map "/" do
run Rails.application
end
end
SystemTesting::Server.new.run
end
actionpack/lib/action_dispatch/system_testing/server.rb
def run
setup
end
private
def setup
set_server
set_port
end
def set_server
Capybara.server = :puma, { Silent: self.class.silence_puma } if Capybara.server == Capybara.servers[:default]
end
def set_port
Capybara.always_include_port = true
end
ちなみにfeature specではRailsのSystemTestCaseではなくrspec-railsが require 'capybara/rails'
した先で、似たようなことをやっている。
lib/capybara/rails.rb
require 'capybara/dsl'
Capybara.app = Rack::Builder.new do
map '/' do
run Rails.application
end
end.to_app
Capybaraでサーバー立ててそうな場所
デフォルトだとPuma指定。
Pumaサーバーを起動してるところはここ。
Capybaraを入れるしかなさそうだが、Capybaraが入っていると
rspec-railsが勝手に Feature とか System specだと勝手にCapybara::DSLまで入れてしまう。
require 'rspec/rails/vendor/capybara'
begin
require 'capybara/rspec'
rescue LoadError
end
begin
require 'capybara/rails'
rescue LoadError
end
if defined?(Capybara)
RSpec.configure do |c|
if defined?(Capybara::DSL)
c.include Capybara::DSL, type: :feature
if defined?(ActionPack) && ActionPack::VERSION::STRING >= "5.1"
c.include Capybara::DSL, type: :system
end
end
$ bundle exec rspec spec/features/example_spec.rb
From: /Users/yusuke-iwaki/Desktop/railsfeature/spec/features/example_spec.rb:6 :
1: require 'rails_helper'
2:
3: describe 'example' do
4: it { |example|
5: require 'pry'
=> 6: binding.pry
7: }
8: end
[1] pry(#<RSpec::ExampleGroups::Example>)> Capybara
=> Capybara
[2] pry(#<RSpec::ExampleGroups::Example>)> method(:visit)
=> #<Method: RSpec::ExampleGroups::Example(RSpec::Rails::FeatureExampleGroup)#visit(*) /Users/yusuke-iwaki/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/rspec-rails-5.0.1/lib/rspec/rails/example/feature_example_group.rb:27>
[3] pry(#<RSpec::ExampleGroups::Example>)> visit '/'
ActionController::RoutingError: No route matches [GET] "/"
from /Users/yusuke-iwaki/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/actionpack-6.1.4/lib/action_dispatch/middleware/debug_exceptions.rb:33:in `call'
spec/features をspec/integration にリネームしてみる。
[1] pry(#<RSpec::ExampleGroups::Example>)> example.metadata
=> {:block=>#<Proc:0x00007faf027f9898 /Users/yusuke-iwaki/Desktop/railsfeature/spec/integration/example_spec.rb:4>,
:description_args=>[],
:description=>"",
:full_description=>"example ",
:described_class=>nil,
:file_path=>"./spec/integration/example_spec.rb",
:line_number=>4,
:location=>"./spec/integration/example_spec.rb:4",
:absolute_file_path=>"/Users/yusuke-iwaki/Desktop/railsfeature/spec/integration/example_spec.rb",
:rerun_file_path=>"./spec/integration/example_spec.rb",
:scoped_id=>"1:1",
:type=>:request,
:execution_result=>
#<RSpec::Core::Example::ExecutionResult:0x00007faf027f9348 @started_at=2021-07-21 22:40:45.25276 +0900>,
:example_group=>
{:block=>#<Proc:0x00007faf027a5c20 /Users/yusuke-iwaki/Desktop/railsfeature/spec/integration/example_spec.rb:3>,
:description_args=>["example"],
:description=>"example",
:full_description=>"example",
:described_class=>nil,
:file_path=>"./spec/integration/example_spec.rb",
:line_number=>3,
:location=>"./spec/integration/example_spec.rb:3",
:absolute_file_path=>"/Users/yusuke-iwaki/Desktop/railsfeature/spec/integration/example_spec.rb",
:rerun_file_path=>"./spec/integration/example_spec.rb",
:scoped_id=>"1",
:type=>:request},
:shared_group_inclusion_backtrace=>[],
:last_run_status=>"unknown"}
[2] pry(#<RSpec::ExampleGroups::Example>)> Capybara
=> Capybara
[3] pry(#<RSpec::ExampleGroups::Example>)> method(:visit)
NameError: undefined method `visit' for class `#<Class:#<RSpec::ExampleGroups::Example:0x00007faf08878ef8>>'
from (pry):3:in `method'
[12] pry(#<RSpec::ExampleGroups::Example>)> Capybara.current_session
=> #<Capybara::Session>
[13] pry(#<RSpec::ExampleGroups::Example>)> Capybara.current_session.visit('/')
ActionController::RoutingError: No route matches [GET] "/"
from /Users/yusuke-iwaki/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/actionpack-6.1.4/lib/action_dispatch/middleware/debug_exceptions.rb:33:in `call'
- Capybara.app にはRailsアプリケーションRack指定されている
- rspec-railsがrequire capybara/railsしていて、その中でやってるから
- Capybara::DSLは入っていない状態
- DSLがないだけで、
Capybara.current_session
から操作はできる
- DSLがないだけで、
- サーバーは起動していない
@server = if config.run_server && @app && driver.needs_server?
server_options = { port: config.server_port, host: config.server_host, reportable_errors: config.server_errors }
server_options[:extra_middleware] = [Capybara::Server::AnimationDisabler] if config.disable_animation
Capybara::Server.new(@app, **server_options).boot
end
[8] pry(#<RSpec::ExampleGroups::Example>)> Capybara.current_session.driver.needs_server?
=> false
サーバーを無理やり起動させるべく、カスタムドライバを入れる。
spec/integration/example_spec.rb
describe 'example' do
class NullDriver < Capybara::Driver::Base
def needs_server?
true
end
end
before(:all) do
Capybara.server = :puma, { Silent: false }
Capybara.always_include_port = true
Capybara.register_driver(:null) { NullDriver.new }
end
around do |example|
Capybara.current_driver = :null
example.run
Capybara.use_default_driver
end
it { |example|
require 'pry'
binding.pry
}
end
[1] pry(#<RSpec::ExampleGroups::Example>)> Capybara.current_session
Capybara starting Puma...
* Version 5.3.2 , codename: Sweetnighter
* Min threads: 0, max threads: 4
* Listening on http://127.0.0.1:61811
=> #<Capybara::Session>
[2] pry(#<RSpec::ExampleGroups::Example>)>
sessionオブジェクトは初回アクセス時に作られるっぽいので、 Capybara.current_session
が参照された時点でサーバーが起動する。
このスクラップは2021/07/23にクローズされました