Browser Always Running in Headless Mode Despite headless: false Configuration
I have registered the Capybara driver for Playwright using the following code:
Capybara.register_driver :playwright do |app|
Capybara::Playwright::Driver.new(app, browser_type: :chromium, headless: false)
end
My test configuration in test/application_system_test_case.rb is as follows:
require 'test_helper'
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :playwright, screen_size: [1400, 1400]
Capybara.configure do |config|
config.server = :puma, { Silent: true }
config.server_port = 31_337 # same as test.yml
config.default_max_wait_time = 10 # seconds
config.test_id = 'data-test-id'
end
end
However, when I run the tests, the browser window does not appear—it always runs in headless mode. How can I configure the tests to run with a visible browser window?
I'm using Capybara 3.40.0 and capybara-playwright-driver 0.5.4.
Any help or suggestions would be appreciated. Thank you!
I also tried it but Chrome actually appeared.
spec_helper.rb
Capybara.register_driver(:playwright) do |app|
Capybara::Playwright::Driver.new(app, browser_type: :chromium, channel: :chrome, headless: false)
end
Capybara.app = App
# Capybara.default_driver = :selenium_chrome_debugport
Capybara.default_driver = :playwright
require 'capybara'
require_relative '../app'
require 'playwright/test'
RSpec.describe 'app' do
include Playwright::Test::Matchers
it 'should work' do
visit '/login'
fill_in 'username', with: 'admin'
fill_in 'password', with: 'password!'
click_button 'ログイン'
page.driver.with_playwright_page do |page|
expect(page.get_by_text('ADMIN')).to be_in_viewport
expect(page.get_by_text('お知らせ')).to be_in_viewport
end
end
end
https://github.com/user-attachments/assets/1e157717-cb1c-4b58-ab6b-47aa4432369b
I've also run into this in the context of a Rails test suite. Is there perhaps an interaction with Rails happening here?
Running
capybara (3.40.0)
capybara-playwright-driver (0.5.4)
# rails_helper.rb
Capybara.register_driver :playwright do |app|
headless = (false unless ENV["CI"] || ENV["HEADLESS"]) || true
Capybara::Playwright::Driver.new(app,
browser_type: ENV["PLAYWRIGHT_BROWSER"]&.to_sym || :chromium,
channel: :chrome,
headless:)
end
Capybara.default_driver = :playwright
# some stuff
RSpec.configure do |config|
config.before(:each, type: :system) do
if ENV["SELENIUM_DRIVER"].present?
driver = (ENV["HEADLESS"] == "false") ? :chrome : :headless_chrome
driven_by(:selenium, using: driver, screen_size: [1920, 4096])
else
driven_by(:playwright)
end
end
end
I've also run into this in the context of a Rails test suite. Is there perhaps an interaction with Rails happening here?
Running
capybara (3.40.0) capybara-playwright-driver (0.5.4)# rails_helper.rb Capybara.register_driver :playwright do |app| headless = (false unless ENV["CI"] || ENV["HEADLESS"]) || true Capybara::Playwright::Driver.new(app, browser_type: ENV["PLAYWRIGHT_BROWSER"]&.to_sym || :chromium, channel: :chrome, headless:) end Capybara.default_driver = :playwright # some stuff RSpec.configure do |config| config.before(:each, type: :system) do if ENV["SELENIUM_DRIVER"].present? driver = (ENV["HEADLESS"] == "false") ? :chrome : :headless_chrome driven_by(:selenium, using: driver, screen_size: [1920, 4096]) else driven_by(:playwright) end end end
I will leave my previous comment up for posterity, but the problem in our case which is silly in hindsight is that we had already registred a :playwright driver in another context, and the configuration was conflicting. I've changed our suite runner driver's name to :playwright_tests and we get the behaviour we're expecting.
I can confirm that we encountered this problem and we've made the same change as @crespire (register it with a different name, rather than likely the default/suggested name) and it all works (so thanks @crespire !).
However, we didn't have the driver registered anywhere else in our codebase, only in one place in rails_helper.rb (so maybe a gem internally does that).
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
The renaming solution works for me, too.
My settings:
Capybara.register_driver :playwright_test do |app|
driver_options = {
# :chromium, :firefox, :webkit
browser_type: ENV["PLAYWRIGHT_BROWSER"]&.to_sym || :chromium,
headless: ENV["CI"].present? || ENV["PLAYWRIGHT_HEADLESS"].present?
}
Capybara::Playwright::Driver.new(app, **driver_options)
end
Capybara.default_driver = :playwright_test
Capybara.javascript_driver = :playwright_test
# Add this at the end to ensure it doesn't get overridden
RSpec.configure do |config|
config.before(:each, type: :system) do
driven_by :playwright_test
end
end
Seems like a bug that this doesn't work when the registered driver is called :playwright, but does work otherwise. I'm not seeing another driver registered with the name :playwright before registering the driver in my app, but, sure enough, the driver customizations don't seem to kick in unless the driver is named something other than :playwright.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I deeply investegated about this issue with adding log into Capybara::RegistrationContainer.
.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/capybara-3.40.0/lib/capybara/registration_container.rb
def initialize
@registered = {}
end
def register(name, block)
puts "REGISTER ------- name: #{name} --- #{block}"
puts caller
@registered[name] = block
end
Then I observed the logs below.
REGISTER ------- name: playwright --- #<Proc:0x0000000122567278 /Users/yusuke-iwaki/Desktop/railsplaywright/spec/rails_helper.rb:50>
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/capybara-3.40.0/lib/capybara.rb:132:in 'Capybara.register_driver'
/Users/yusuke-iwaki/Desktop/railsplaywright/spec/rails_helper.rb:50:in 'block (2 levels) in <top (required)>'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/example.rb:457:in 'BasicObject#instance_exec'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/example.rb:457:in 'RSpec::Core::Example#instance_exec'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/hooks.rb:365:in 'RSpec::Core::Hooks::BeforeHook#run'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/configuration.rb:2191:in 'block in RSpec::Core::Configuration#run_suite_hooks'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/configuration.rb:2189:in 'Array#each'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/configuration.rb:2189:in 'RSpec::Core::Configuration#run_suite_hooks'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/configuration.rb:2096:in 'RSpec::Core::Configuration#with_suite_hooks'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/runner.rb:116:in 'block in RSpec::Core::Runner#run_specs'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/reporter.rb:74:in 'RSpec::Core::Reporter#report'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/runner.rb:115:in 'RSpec::Core::Runner#run_specs'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/runner.rb:89:in 'RSpec::Core::Runner#run'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/runner.rb:71:in 'RSpec::Core::Runner.run'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/runner.rb:45:in 'RSpec::Core::Runner.invoke'
REGISTER ------- name: playwright --- #<Proc:0x0000000122522da8 /Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/actionpack-8.1.1/lib/action_dispatch/system_testing/driver.rb:41>
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/capybara-3.40.0/lib/capybara.rb:132:in 'Capybara.register_driver'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/actionpack-8.1.1/lib/action_dispatch/system_testing/driver.rb:41:in 'ActionDispatch::SystemTesting::Driver#register'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/actionpack-8.1.1/lib/action_dispatch/system_testing/driver.rb:28:in 'ActionDispatch::SystemTesting::Driver#use'
<internal:kernel>:91:in 'Kernel#tap'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-rails-7.1.1/lib/rspec/rails/example/system_example_group.rb:153:in 'RSpec::ExampleGroups::Authentication#driven_by'
/Users/yusuke-iwaki/Desktop/railsplaywright/spec/rails_helper.rb:58:in 'block (2 levels) in <top (required)>'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/example.rb:457:in 'BasicObject#instance_exec'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/example.rb:457:in 'RSpec::Core::Example#instance_exec'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/hooks.rb:365:in 'RSpec::Core::Hooks::BeforeHook#run'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/hooks.rb:529:in 'block in RSpec::Core::Hooks::HookCollections#run_owned_hooks_for'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/hooks.rb:528:in 'Array#each'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/hooks.rb:528:in 'RSpec::Core::Hooks::HookCollections#run_owned_hooks_for'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/hooks.rb:615:in 'block in RSpec::Core::Hooks::HookCollections#run_example_hooks_for'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/hooks.rb:614:in 'Array#reverse_each'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/hooks.rb:614:in 'RSpec::Core::Hooks::HookCollections#run_example_hooks_for'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/hooks.rb:484:in 'RSpec::Core::Hooks::HookCollections#run'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/example.rb:505:in 'RSpec::Core::Example#run_before_example'
/Users/yusuke-iwaki/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/rspec-core-3.13.6/lib/rspec/core/example.rb:261:in 'block in RSpec::Core::Example#run'
spec/rails_helper.rb:
# Configure Capybara to use Playwright driver
config.before(:suite, type: :system) do
Capybara.register_driver :playwright do |app|
Capybara::Playwright::Driver.new(app, browser_type: :chromium, headless: false)
end
Capybara.javascript_driver = :playwright
Capybara.default_driver = :playwright
end
config.before(:each, type: :system) do
driven_by :playwright, using: :chromium, screen_size: [1400, 1400], options: {
headless: true
}
end
With this code, most of us would expect that this code register and overrides Rails's default playwright driver configuration. However in fact, this works as:
- Register customized playwright driver
- Find playwright driver invoked by
driven_by
- driven_by internally register the default Rails's playwright first --> this overrides customized playwright driver
- https://github.com/rails/rails/blob/v8.1.1/actionpack/lib/action_dispatch/system_testing/driver.rb#28
- find a driver registered as playwright --> the Rails's default driver is found
Similar issue: https://github.com/rails/rails/issues/39987