From 629bb74451242060298c6fb305c5337002379cc2 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 10 Jun 2025 12:33:46 -0400 Subject: [PATCH] Replace selenium-webdriver with playwright (#34867) --- .github/workflows/test-ruby.yml | 15 +++++++++++++++ Gemfile | 2 +- Gemfile.lock | 16 ++++++++-------- spec/support/browser_errors.rb | 21 ++++++++++++++------- spec/support/capybara.rb | 32 ++++++-------------------------- spec/system/log_out_spec.rb | 2 +- 6 files changed, 45 insertions(+), 43 deletions(-) diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 0dd55c77e4..63d3172504 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -332,6 +332,21 @@ jobs: - name: Load database schema run: './bin/rails db:create db:schema:load db:seed' + - name: Cache Playwright Chromium browser + id: playwright-cache + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + + - name: Install Playwright Chromium browser (with deps) + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: yarn run playwright install --with-deps chromium + + - name: Install Playwright Chromium browser deps + if: steps.playwright-cache.outputs.cache-hit == 'true' + run: yarn run playwright install-deps chromium + - run: bin/rspec spec/system --tag streaming --tag js - name: Archive logs diff --git a/Gemfile b/Gemfile index 5e8cee24b6..db2b82955b 100644 --- a/Gemfile +++ b/Gemfile @@ -137,7 +137,7 @@ group :test do # Browser integration testing gem 'capybara', '~> 3.39' - gem 'selenium-webdriver' + gem 'capybara-playwright-driver' # Used to reset the database between system tests gem 'database_cleaner-active_record' diff --git a/Gemfile.lock b/Gemfile.lock index 1cd6210f40..a144ba021d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -142,6 +142,10 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) + capybara-playwright-driver (0.5.6) + addressable + capybara + playwright-ruby-client (>= 1.16.0) case_transform (0.2) activesupport cbor (0.5.9.8) @@ -603,6 +607,9 @@ GEM pg (1.5.9) pghero (3.7.0) activerecord (>= 7.1) + playwright-ruby-client (1.52.0) + concurrent-ruby (>= 1.1.6) + mime-types (>= 3.0) pp (0.6.2) prettyprint premailer (1.27.0) @@ -808,12 +815,6 @@ GEM activerecord (>= 4.0.0) railties (>= 4.0.0) securerandom (0.4.1) - selenium-webdriver (4.33.0) - base64 (~> 0.2) - logger (~> 1.4) - rexml (~> 3.2, >= 3.2.5) - rubyzip (>= 1.2.2, < 3.0) - websocket (~> 1.0) shoulda-matchers (6.5.0) activesupport (>= 5.2.0) sidekiq (7.3.9) @@ -927,7 +928,6 @@ GEM crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) webrick (1.9.1) - websocket (1.2.11) websocket-driver (0.7.7) base64 websocket-extensions (>= 0.1.0) @@ -955,6 +955,7 @@ DEPENDENCIES browser bundler-audit (~> 0.9) capybara (~> 3.39) + capybara-playwright-driver charlock_holmes (~> 0.7.7) chewy (~> 7.3) climate_control @@ -1070,7 +1071,6 @@ DEPENDENCIES rubyzip (~> 2.3) sanitize (~> 7.0) scenic (~> 1.7) - selenium-webdriver shoulda-matchers sidekiq (< 8) sidekiq-bulk (~> 0.2.0) diff --git a/spec/support/browser_errors.rb b/spec/support/browser_errors.rb index 8a31ba3ab6..6c101540a3 100644 --- a/spec/support/browser_errors.rb +++ b/spec/support/browser_errors.rb @@ -9,29 +9,36 @@ end RSpec.configure do |config| config.include BrowserErrorsHelpers, :js, type: :system - config.before(:each, :js, type: :system) do + config.before(:each, :js, type: :system) do |example| @ignored_js_errors_for_spec = [] + + example.metadata[:js_console_messages] ||= [] + Capybara.current_session.driver.with_playwright_page do |page| + page.on('console', lambda { |msg| + example.metadata[:js_console_messages] << { type: msg.type, text: msg.text, location: msg.location } + }) + end end - config.after(:each, :js, type: :system) do + config.after(:each, :js, type: :system) do |example| # Classes of intermittent ignorable errors ignored_errors = [ /Error while trying to use the following icon from the Manifest/, # https://github.com/mastodon/mastodon/pull/30793 /Manifest: Line: 1, column: 1, Syntax error/, # Similar parsing/interruption issue as above ].concat(@ignored_js_errors_for_spec) - errors = page.driver.browser.logs.get(:browser).reject do |error| - ignored_errors.any? { |pattern| pattern.match(error.message) } + errors = example.metadata[:js_console_messages].reject do |msg| + ignored_errors.any? { |pattern| pattern.match(msg[:text]) } end if errors.present? aggregate_failures 'browser errrors' do errors.each do |error| - expect(error.level).to_not eq('SEVERE'), error.message - next unless error.level == 'WARNING' + expect(error[:type]).to_not eq('error'), error[:text] + next unless error[:type] == 'warning' warn 'WARN: browser warning' - warn error.message + warn error[:text] end end end diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index e8cb852c7b..aa548c3782 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -4,36 +4,16 @@ Capybara.server_host = 'localhost' Capybara.server_port = 3000 Capybara.app_host = "http://#{Capybara.server_host}:#{Capybara.server_port}" -require 'selenium/webdriver' - -def common_chrome_options - options = Selenium::WebDriver::Chrome::Options.new - options.add_argument '--window-size=1680,1050' - options.add_argument '--disable-search-engine-choice-screen' - options +Capybara.register_driver(:playwright) do |app| + Capybara::Playwright::Driver.new(app) end +Capybara.javascript_driver = :playwright -Capybara.register_driver :chrome do |app| - Capybara::Selenium::Driver.new(app, browser: :chrome, options: common_chrome_options) +if ENV['CI'].present? + # Reduce intermittent failures from slow CI runner environment + Capybara.default_max_wait_time = 2**3 end -Capybara.register_driver :headless_chrome do |app| - options = common_chrome_options - options.add_argument '--headless=new' - - Capybara::Selenium::Driver.new( - app, - browser: :chrome, - options: options - ) -end - -Capybara.javascript_driver = :headless_chrome - -# Some of the flaky tests seem to be caused by github runners being too slow for the -# default timeout of 2 seconds -Capybara.default_max_wait_time = 8 - RSpec.configure do |config| config.before(:each, type: :system) do driven_by :rack_test diff --git a/spec/system/log_out_spec.rb b/spec/system/log_out_spec.rb index ebbf5a5772..94c8ddbee5 100644 --- a/spec/system/log_out_spec.rb +++ b/spec/system/log_out_spec.rb @@ -26,7 +26,7 @@ RSpec.describe 'Log out' do describe 'Logging out from the JS app', :js, :streaming do it 'logs the user out' do # The frontend tries to load announcements after a short delay, but the session might be expired by then, and the browser will output an error. - ignore_js_error(/Failed to load resource: the server responded with a status of 422/) + ignore_js_error(/Failed to load resource: the server responded with a status/) visit root_path expect(page)