From a7c4ccc105a4986d4a89959b6e4696b08a89890c Mon Sep 17 00:00:00 2001 From: Andrei Bondarev Date: Mon, 26 Oct 2026 14:43:58 -0400 Subject: [PATCH 1/2] =?UTF-8?q?Modernize:=20Rails=207.1=E2=80=938.1,=20Rub?= =?UTF-8?q?y=203.2=E2=80=934.0,=20Propshaft,=20browser=20specs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Require Ruby 3.2+, Rails 7.1+, Administrate 1.0+ and test the full Ruby 3.2–4.0 × Rails 7.1–8.1 matrix in CI (Rails 7.x on Sprockets, Rails 8 on Propshaft) - Drop the sprockets-rails dependency; only register the script for precompilation when Sprockets is present - Wrap script.js in an IIFE so it doesn't define globals like `init` - Include helpers via ActiveSupport.on_load(:action_view) - Load namespace controllers with Zeitwerk's eager_load_dir instead of require_dependency - Keep the button helper's default `button` class when other options such as `confirm:` are given - Replace the Rails 6.1 dummy app with a minimal version-agnostic one - Add Cuprite system specs for the batch action UI and make helper specs markup-order independent - Move dev dependencies to the Gemfile, stop committing Gemfile.lock, clean up gemspec metadata and packaged files - Add Dependabot config, ignore built gems, bump .tool-versions to 4.0 --- .github/dependabot.yml | 19 ++ .github/workflows/specs.yml | 31 ++- .gitignore | 10 + .tool-versions | 2 +- CHANGELOG.md | 6 + Gemfile | 27 +- Gemfile.lock | 257 ------------------ README.md | 15 +- administrate_batch_actions.gemspec | 39 +-- .../administrate_batch_actions/script.js | 210 +++++++------- config/routes.rb | 5 +- lib/administrate_batch_actions.rb | 16 +- lib/administrate_batch_actions/helpers.rb | 4 +- spec/administrate_batch_actions_spec.rb | 2 + spec/dummy/.gitattributes | 6 - spec/dummy/.gitignore | 26 -- spec/dummy/.ruby-version | 1 - spec/dummy/README.md | 24 -- spec/dummy/Rakefile | 6 - spec/dummy/app/assets/config/manifest.js | 3 +- spec/dummy/app/assets/images/.keep | 0 .../app/assets/stylesheets/application.css | 15 - .../app/controllers/admin/dummy_controller.rb | 4 +- .../backoffice/widgets_controller.rb | 4 +- spec/dummy/app/controllers/concerns/.keep | 0 .../dummy/app/controllers/pages_controller.rb | 3 + spec/dummy/app/helpers/application_helper.rb | 2 - spec/dummy/app/models/concerns/.keep | 0 .../app/views/layouts/application.html.erb | 7 +- spec/dummy/app/views/pages/batch.html.erb | 13 + spec/dummy/bin/rails | 4 - spec/dummy/bin/rake | 4 - spec/dummy/bin/setup | 25 -- spec/dummy/config.ru | 5 +- spec/dummy/config/application.rb | 39 +-- spec/dummy/config/boot.rb | 4 +- spec/dummy/config/credentials.yml.enc | 1 - spec/dummy/config/environment.rb | 4 +- spec/dummy/config/environments/development.rb | 62 ----- spec/dummy/config/environments/production.rb | 100 ------- spec/dummy/config/environments/test.rb | 47 +--- .../application_controller_renderer.rb | 8 - spec/dummy/config/initializers/assets.rb | 12 - .../initializers/backtrace_silencers.rb | 8 - .../initializers/content_security_policy.rb | 28 -- .../config/initializers/cookies_serializer.rb | 5 - .../initializers/filter_parameter_logging.rb | 6 - spec/dummy/config/initializers/inflections.rb | 16 -- spec/dummy/config/initializers/mime_types.rb | 4 - .../config/initializers/permissions_policy.rb | 11 - .../config/initializers/wrap_parameters.rb | 9 - spec/dummy/config/locales/en.yml | 33 --- spec/dummy/config/puma.rb | 43 --- spec/dummy/config/routes.rb | 2 +- spec/dummy/lib/assets/.keep | 0 spec/dummy/lib/tasks/.keep | 0 spec/dummy/log/.keep | 0 spec/dummy/public/404.html | 67 ----- spec/dummy/public/422.html | 67 ----- spec/dummy/public/500.html | 66 ----- .../public/apple-touch-icon-precomposed.png | 0 spec/dummy/public/apple-touch-icon.png | 0 spec/dummy/public/favicon.ico | 0 spec/dummy/public/robots.txt | 1 - spec/dummy/tmp/.keep | 0 spec/dummy/tmp/pids/.keep | 0 spec/dummy/vendor/.keep | 0 spec/helpers_spec.rb | 46 ++-- spec/rails_helper.rb | 15 +- spec/spec_helper.rb | 6 - spec/system/batch_actions_spec.rb | 48 ++++ 71 files changed, 360 insertions(+), 1193 deletions(-) create mode 100644 .github/dependabot.yml delete mode 100644 Gemfile.lock delete mode 100644 spec/dummy/.gitattributes delete mode 100644 spec/dummy/.gitignore delete mode 100644 spec/dummy/.ruby-version delete mode 100644 spec/dummy/README.md delete mode 100644 spec/dummy/Rakefile delete mode 100644 spec/dummy/app/assets/images/.keep delete mode 100644 spec/dummy/app/assets/stylesheets/application.css delete mode 100644 spec/dummy/app/controllers/concerns/.keep create mode 100644 spec/dummy/app/controllers/pages_controller.rb delete mode 100644 spec/dummy/app/helpers/application_helper.rb delete mode 100644 spec/dummy/app/models/concerns/.keep create mode 100644 spec/dummy/app/views/pages/batch.html.erb delete mode 100755 spec/dummy/bin/rails delete mode 100755 spec/dummy/bin/rake delete mode 100755 spec/dummy/bin/setup delete mode 100644 spec/dummy/config/credentials.yml.enc delete mode 100644 spec/dummy/config/environments/development.rb delete mode 100644 spec/dummy/config/environments/production.rb delete mode 100644 spec/dummy/config/initializers/application_controller_renderer.rb delete mode 100644 spec/dummy/config/initializers/assets.rb delete mode 100644 spec/dummy/config/initializers/backtrace_silencers.rb delete mode 100644 spec/dummy/config/initializers/content_security_policy.rb delete mode 100644 spec/dummy/config/initializers/cookies_serializer.rb delete mode 100644 spec/dummy/config/initializers/filter_parameter_logging.rb delete mode 100644 spec/dummy/config/initializers/inflections.rb delete mode 100644 spec/dummy/config/initializers/mime_types.rb delete mode 100644 spec/dummy/config/initializers/permissions_policy.rb delete mode 100644 spec/dummy/config/initializers/wrap_parameters.rb delete mode 100644 spec/dummy/config/locales/en.yml delete mode 100644 spec/dummy/config/puma.rb delete mode 100644 spec/dummy/lib/assets/.keep delete mode 100644 spec/dummy/lib/tasks/.keep delete mode 100644 spec/dummy/log/.keep delete mode 100644 spec/dummy/public/404.html delete mode 100644 spec/dummy/public/422.html delete mode 100644 spec/dummy/public/500.html delete mode 100644 spec/dummy/public/apple-touch-icon-precomposed.png delete mode 100644 spec/dummy/public/apple-touch-icon.png delete mode 100644 spec/dummy/public/favicon.ico delete mode 100644 spec/dummy/public/robots.txt delete mode 100644 spec/dummy/tmp/.keep delete mode 100644 spec/dummy/tmp/pids/.keep delete mode 100644 spec/dummy/vendor/.keep create mode 100644 spec/system/batch_actions_spec.rb diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..dd0211a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,19 @@ +version: 2 +updates: + - package-ecosystem: bundler + directory: / + schedule: + interval: monthly + groups: + dependencies: + patterns: + - "*" + + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + groups: + actions: + patterns: + - "*" diff --git a/.github/workflows/specs.yml b/.github/workflows/specs.yml index fde757d..1dbbe69 100644 --- a/.github/workflows/specs.yml +++ b/.github/workflows/specs.yml @@ -9,17 +9,35 @@ on: branches: - "*" +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest - name: Ruby ${{ matrix.ruby }} + name: Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }} strategy: + fail-fast: false matrix: ruby: - - "3.4.6" + - "3.2" + - "3.3" + - "3.4" + - "4.0" + rails: + - "7.1" + - "7.2" + - "8.0" + - "8.1" + env: + RAILS_VERSION: ${{ matrix.rails }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -27,3 +45,10 @@ jobs: bundler-cache: true - name: Run the default task run: bundle exec rake + - name: Upload system spec screenshots + if: failure() + uses: actions/upload-artifact@v4 + with: + name: screenshots-ruby-${{ matrix.ruby }}-rails-${{ matrix.rails }} + path: spec/dummy/tmp/capybara + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore index c51c30b..e8f62e2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,13 @@ # rspec failure tracking .rspec_status .DS_Store + +# built gems +*.gem + +# resolved per RAILS_VERSION, see Gemfile +/Gemfile.lock + +# dummy app runtime files +/spec/dummy/tmp/ +/spec/dummy/log/ diff --git a/.tool-versions b/.tool-versions index 1eb41cb..b77860b 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -ruby 3.1 +ruby 4.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3235233..1adc4ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,12 @@ All notable changes to this project will be documented in this file. - Clarified in the README that the button label is a string (#12) ### Changed +- Requires Ruby 3.2+, Rails 7.1+ and Administrate 1.0+, now tested on Ruby 3.2–4.0 and Rails 7.1–8.1 +- No longer depends on `sprockets-rails`, so Propshaft apps don't get Sprockets installed; the script works with either pipeline +- The button helper keeps its default `button` class when other options such as `confirm:` are passed +- The script no longer defines global variables, which could collide with other scripts on the page +- Helpers are included through `ActiveSupport.on_load(:action_view)`, so ActionView isn't loaded early +- Controllers are loaded for route generation through Zeitwerk instead of `require_dependency` - Batch action buttons are now `button_to` forms that are truly disabled until rows are selected (#48) - Batch action routes are now `POST //administrate_batch_actions//`, named `__`, e.g. `admin_delete_batch_action_users_path` diff --git a/Gemfile b/Gemfile index 2f92064..ba7712d 100644 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,27 @@ -source "https://rubygems.org" +source 'https://rubygems.org' -git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - -# Specify your gem's dependencies in administrate_batch_actions.gemspec gemspec +rails_version = ENV.fetch('RAILS_VERSION', '8.1') + +gem 'rails', "~> #{rails_version}.0" + +# Rails 8 apps default to Propshaft, older ones to Sprockets +if Gem::Version.new(rails_version) >= Gem::Version.new('8.0') + gem 'propshaft' +else + gem 'sprockets-rails' +end + +gem 'rake', '~> 13.0' + +group :development, :test do + gem 'pry' +end + group :test do - gem 'tzinfo-data', platforms: %i[mswin mswin64 mingw x64_mingw] + gem 'capybara' + gem 'cuprite' + gem 'puma' + gem 'rspec-rails', '>= 6.1' end diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 3141e8d..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,257 +0,0 @@ -PATH - remote: . - specs: - administrate_batch_actions (0.4.0) - administrate - rails (>= 5.2) - sprockets-rails - -GEM - remote: https://rubygems.org/ - specs: - actioncable (7.0.10) - actionpack (= 7.0.10) - activesupport (= 7.0.10) - nio4r (~> 2.0) - websocket-driver (>= 0.6.1) - actionmailbox (7.0.10) - actionpack (= 7.0.10) - activejob (= 7.0.10) - activerecord (= 7.0.10) - activestorage (= 7.0.10) - activesupport (= 7.0.10) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.0.10) - actionpack (= 7.0.10) - actionview (= 7.0.10) - activejob (= 7.0.10) - activesupport (= 7.0.10) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.10) - actionview (= 7.0.10) - activesupport (= 7.0.10) - racc - rack (~> 2.0, >= 2.2.4) - rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.10) - actionpack (= 7.0.10) - activerecord (= 7.0.10) - activestorage (= 7.0.10) - activesupport (= 7.0.10) - globalid (>= 0.6.0) - nokogiri (>= 1.8.5) - actionview (7.0.10) - activesupport (= 7.0.10) - builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.10) - activesupport (= 7.0.10) - globalid (>= 0.3.6) - activemodel (7.0.10) - activesupport (= 7.0.10) - activerecord (7.0.10) - activemodel (= 7.0.10) - activesupport (= 7.0.10) - activestorage (7.0.10) - actionpack (= 7.0.10) - activejob (= 7.0.10) - activerecord (= 7.0.10) - activesupport (= 7.0.10) - marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.10) - base64 - benchmark (>= 0.3) - bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) - drb - i18n (>= 1.6, < 2) - logger (>= 1.4.2) - minitest (>= 5.1) - mutex_m - securerandom (>= 0.3) - tzinfo (~> 2.0) - administrate (1.0.0) - actionpack (>= 6.0, < 9.0) - actionview (>= 6.0, < 9.0) - activerecord (>= 6.0, < 9.0) - kaminari (~> 1.2.2) - base64 (0.3.0) - benchmark (0.5.0) - bigdecimal (4.0.1) - builder (3.3.0) - coderay (1.1.3) - concurrent-ruby (1.3.6) - crass (1.0.6) - date (3.5.1) - diff-lcs (1.6.2) - drb (2.2.3) - erubi (1.13.1) - globalid (1.3.0) - activesupport (>= 6.1) - i18n (1.14.8) - concurrent-ruby (~> 1.0) - io-console (0.8.2) - kaminari (1.2.2) - activesupport (>= 4.1.0) - kaminari-actionview (= 1.2.2) - kaminari-activerecord (= 1.2.2) - kaminari-core (= 1.2.2) - kaminari-actionview (1.2.2) - actionview - kaminari-core (= 1.2.2) - kaminari-activerecord (1.2.2) - activerecord - kaminari-core (= 1.2.2) - kaminari-core (1.2.2) - logger (1.7.0) - loofah (2.25.1) - crass (~> 1.0.2) - nokogiri (>= 1.12.0) - mail (2.9.0) - logger - mini_mime (>= 0.1.1) - net-imap - net-pop - net-smtp - marcel (1.1.0) - method_source (1.1.0) - mini_mime (1.1.5) - minitest (5.27.0) - mutex_m (0.3.0) - net-imap (0.5.13) - date - net-protocol - net-pop (0.1.2) - net-protocol - net-protocol (0.2.2) - timeout - net-smtp (0.5.1) - net-protocol - nio4r (2.7.5) - nokogiri (1.18.10-aarch64-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.10-aarch64-linux-musl) - racc (~> 1.4) - nokogiri (1.18.10-arm-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.10-arm-linux-musl) - racc (~> 1.4) - nokogiri (1.18.10-arm64-darwin) - racc (~> 1.4) - nokogiri (1.18.10-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.18.10-x86_64-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.10-x86_64-linux-musl) - racc (~> 1.4) - pry (0.16.0) - coderay (~> 1.1) - method_source (~> 1.0) - reline (>= 0.6.0) - racc (1.8.1) - rack (2.2.22) - rack-test (2.2.0) - rack (>= 1.3) - rails (7.0.10) - actioncable (= 7.0.10) - actionmailbox (= 7.0.10) - actionmailer (= 7.0.10) - actionpack (= 7.0.10) - actiontext (= 7.0.10) - actionview (= 7.0.10) - activejob (= 7.0.10) - activemodel (= 7.0.10) - activerecord (= 7.0.10) - activestorage (= 7.0.10) - activesupport (= 7.0.10) - bundler (>= 1.15.0) - railties (= 7.0.10) - rails-dom-testing (2.3.0) - activesupport (>= 5.0.0) - minitest - nokogiri (>= 1.6) - rails-html-sanitizer (1.7.0) - loofah (~> 2.25) - nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - railties (7.0.10) - actionpack (= 7.0.10) - activesupport (= 7.0.10) - method_source - rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) - rake (13.3.1) - reline (0.6.3) - io-console (~> 0.5) - rspec (3.9.0) - rspec-core (~> 3.9.0) - rspec-expectations (~> 3.9.0) - rspec-mocks (~> 3.9.0) - rspec-core (3.9.3) - rspec-support (~> 3.9.3) - rspec-expectations (3.9.4) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.9.0) - rspec-mocks (3.9.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.9.0) - rspec-rails (3.9.1) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.9.0) - rspec-expectations (~> 3.9.0) - rspec-mocks (~> 3.9.0) - rspec-support (~> 3.9.0) - rspec-support (3.9.4) - securerandom (0.4.1) - sprockets (4.2.2) - concurrent-ruby (~> 1.0) - logger - rack (>= 2.2.4, < 4) - sprockets-rails (3.5.2) - actionpack (>= 6.1) - activesupport (>= 6.1) - sprockets (>= 3.0.0) - thor (1.5.0) - timeout (0.6.1) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - websocket-driver (0.8.0) - base64 - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.5) - zeitwerk (2.6.18) - -PLATFORMS - aarch64-linux-gnu - aarch64-linux-musl - arm-linux-gnu - arm-linux-musl - arm64-darwin - x86_64-darwin - x86_64-linux-gnu - x86_64-linux-musl - -DEPENDENCIES - administrate_batch_actions! - pry - rake (~> 13.0) - rspec (~> 3.0) - rspec-rails (~> 3.0) - tzinfo-data - -BUNDLED WITH - 2.6.9 diff --git a/README.md b/README.md index a69ce8a..0efcd72 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,13 @@ The available helpers add individual checkboxes, a 'select all' checkbox and bat ![Aug-21-2021 21-56-48](https://user-images.githubusercontent.com/541665/130339415-c69f4b53-e248-449a-8764-7a854c5b0dcb.gif) +## Requirements + +- Ruby 3.2+ +- Rails 7.1+ +- Administrate 1.0+ +- Propshaft or Sprockets. The script is added to Administrate's layout automatically with either asset pipeline. + ## Installation Add this line to your application's Gemfile: @@ -98,7 +105,13 @@ Routes are prefixed with their namespace, e.g. `Backoffice::UsersController#dele ## Development -After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. +After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec` to run the tests. The system specs drive a headless Chrome through [Cuprite](https://github.com/rubycdp/cuprite), so Chrome needs to be installed. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +The tests run against the latest Rails by default. To test another version, set `RAILS_VERSION` (Rails 7.x uses Sprockets, Rails 8 uses Propshaft): + + $ rm -f Gemfile.lock + $ RAILS_VERSION=7.2 bundle install + $ RAILS_VERSION=7.2 bundle exec rake spec To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). diff --git a/administrate_batch_actions.gemspec b/administrate_batch_actions.gemspec index d225f9c..c9b92f4 100644 --- a/administrate_batch_actions.gemspec +++ b/administrate_batch_actions.gemspec @@ -1,38 +1,27 @@ -lib = File.expand_path("../lib", __FILE__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'administrate_batch_actions/version' +require_relative 'lib/administrate_batch_actions/version' Gem::Specification.new do |spec| spec.name = 'administrate_batch_actions' spec.version = AdministrateBatchActions::VERSION spec.authors = ['Sourcelabs LLC'] spec.email = ['andrei@sourcelabs.io'] - spec.homepage = 'https://github.com/SourceLabsLLC/administrate-batch-actions' + spec.homepage = 'https://github.com/SourceLabsLLC/administrate_batch_actions' spec.summary = 'Batch Actions plugin for Administrate' - spec.description = spec.summary + spec.description = 'Adds checkboxes, a "select all" checkbox and batch action buttons to Administrate index pages.' spec.license = 'MIT' - # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' - # to allow pushing to a single host or delete this section to allow pushing to any host. - # if spec.respond_to?(:metadata) - # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'" - # else - # raise "RubyGems 2.0 or newer is required to protect against " \ - # "public gem pushes." - # end + spec.required_ruby_version = '>= 3.2' - spec.files = `git ls-files -z`.split("\x0").reject do |f| - f.match(%r{^(test|spec|features)/}) - end - spec.bindir = 'exe' - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.metadata = { + 'source_code_uri' => spec.homepage, + 'changelog_uri' => "#{spec.homepage}/blob/main/CHANGELOG.md", + 'bug_tracker_uri' => "#{spec.homepage}/issues", + 'rubygems_mfa_required' => 'true' + } + + spec.files = Dir['{app,config,lib}/**/*', 'CHANGELOG.md', 'LICENSE.txt', 'README.md'] spec.require_paths = ['lib'] - spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rspec', '~> 3.0' - spec.add_development_dependency 'rspec-rails', '~> 3.0' - spec.add_development_dependency 'pry' - spec.add_dependency 'sprockets-rails' - spec.add_dependency 'administrate' - spec.add_dependency 'rails', '>= 5.2' + spec.add_dependency 'administrate', '>= 1.0' + spec.add_dependency 'rails', '>= 7.1' end diff --git a/app/assets/javascripts/administrate_batch_actions/script.js b/app/assets/javascripts/administrate_batch_actions/script.js index 6b7a465..e0d04bb 100644 --- a/app/assets/javascripts/administrate_batch_actions/script.js +++ b/app/assets/javascripts/administrate_batch_actions/script.js @@ -1,122 +1,124 @@ -const boundForms = new WeakSet(); -const boundCheckboxes = new WeakSet(); -const boundSelectAllCheckboxes = new WeakSet(); - -const init = function () { - var buttons = document.querySelectorAll( - "[data-batch-action-option='button']", - ); - var checkboxes = document.querySelectorAll( - "[data-batch-action-option='checkbox']", - ); - var selectAllCheckboxes = document.querySelector( - "[data-batch-action-option='select_all']", - ); - - if (selectAllCheckboxes && checkboxes && buttons) { - // Reset selections restored by the browser's back/forward cache - window.onpageshow = function (event) { - if (selectedItemIds().length > 0) { - checkboxes.forEach(function (checkbox) { - checkbox.checked = false; - }); +(function () { + const boundForms = new WeakSet(); + const boundCheckboxes = new WeakSet(); + const boundSelectAllCheckboxes = new WeakSet(); + + const init = function () { + var buttons = document.querySelectorAll( + "[data-batch-action-option='button']", + ); + var checkboxes = document.querySelectorAll( + "[data-batch-action-option='checkbox']", + ); + var selectAllCheckboxes = document.querySelector( + "[data-batch-action-option='select_all']", + ); + + if (selectAllCheckboxes && checkboxes && buttons) { + // Reset selections restored by the browser's back/forward cache + window.onpageshow = function (event) { + if (selectedItemIds().length > 0) { + checkboxes.forEach(function (checkbox) { + checkbox.checked = false; + }); - selectAllCheckboxes.checked = false; - } + selectAllCheckboxes.checked = false; + } - checkAndToggleActionButtons(); - }; + checkAndToggleActionButtons(); + }; + + if (!isBoundElement(boundSelectAllCheckboxes, selectAllCheckboxes)) { + boundSelectAllCheckboxes.add(selectAllCheckboxes); - if (!isBoundElement(boundSelectAllCheckboxes, selectAllCheckboxes)) { - boundSelectAllCheckboxes.add(selectAllCheckboxes); + selectAllCheckboxes.addEventListener("click", function () { + checkboxes.forEach(function (checkbox) { + checkbox.checked = selectAllCheckboxes.checked; + }); - selectAllCheckboxes.addEventListener("click", function () { - checkboxes.forEach(function (checkbox) { - checkbox.checked = selectAllCheckboxes.checked; + checkAndToggleActionButtons(); }); + } - checkAndToggleActionButtons(); + buttons.forEach(function (button) { + var form = button.form; + if (!form || isBoundElement(boundForms, form)) return; + boundForms.add(form); + + form.addEventListener("submit", function (event) { + var confirmMessage = button.dataset.batchActionConfirm; + + if (confirmMessage && confirm(confirmMessage) !== true) { + event.preventDefault(); + return; + } + + // Replace ids from a previous submission (e.g. after navigating back) + form + .querySelectorAll("[data-batch-action-option='hidden_id']") + .forEach(function (hiddenInput) { + hiddenInput.remove(); + }); + + selectedItemIds().forEach(function (id) { + var hiddenInput = document.createElement("input"); + hiddenInput.type = "hidden"; + hiddenInput.name = "batch_action_ids[]"; + hiddenInput.value = id; + hiddenInput.dataset.batchActionOption = "hidden_id"; + form.appendChild(hiddenInput); + }); + }); }); - } - - buttons.forEach(function (button) { - var form = button.form; - if (!form || isBoundElement(boundForms, form)) return; - boundForms.add(form); - - form.addEventListener("submit", function (event) { - var confirmMessage = button.dataset.batchActionConfirm; - if (confirmMessage && confirm(confirmMessage) !== true) { - event.preventDefault(); + checkboxes.forEach(function (checkbox) { + if (isBoundElement(boundCheckboxes, checkbox)) { return; } + boundCheckboxes.add(checkbox); - // Replace ids from a previous submission (e.g. after navigating back) - form - .querySelectorAll("[data-batch-action-option='hidden_id']") - .forEach(function (hiddenInput) { - hiddenInput.remove(); - }); - - selectedItemIds().forEach(function (id) { - var hiddenInput = document.createElement("input"); - hiddenInput.type = "hidden"; - hiddenInput.name = "batch_action_ids[]"; - hiddenInput.value = id; - hiddenInput.dataset.batchActionOption = "hidden_id"; - form.appendChild(hiddenInput); + checkbox.closest("td").addEventListener("click", function (event) { + event.stopImmediatePropagation(); }); - }); - }); - checkboxes.forEach(function (checkbox) { - if (isBoundElement(boundCheckboxes, checkbox)) { - return; - } - boundCheckboxes.add(checkbox); + checkbox.addEventListener("click", function (event) { + event.stopImmediatePropagation(); - checkbox.closest("td").addEventListener("click", function (event) { - event.stopImmediatePropagation(); + checkAndToggleActionButtons(); + }); }); + } + + function selectedItemIds() { + return Array.prototype.filter + .call(checkboxes, function (checkbox) { + return checkbox.checked; + }) + .map(function (checkbox) { + return checkbox.value; + }); + } - checkbox.addEventListener("click", function (event) { - event.stopImmediatePropagation(); + function checkAndToggleActionButtons() { + var disabled = selectedItemIds().length === 0; - checkAndToggleActionButtons(); - }); - }); - } - - function selectedItemIds() { - return Array.prototype.filter - .call(checkboxes, function (checkbox) { - return checkbox.checked; - }) - .map(function (checkbox) { - return checkbox.value; + buttons.forEach(function (button) { + button.disabled = disabled; }); - } - - function checkAndToggleActionButtons() { - var disabled = selectedItemIds().length === 0; - - buttons.forEach(function (button) { - button.disabled = disabled; - }); - } - - function isBoundElement(boundElement, incomingElement) { - return boundElement.has(incomingElement); - } -}; - -document.addEventListener("DOMContentLoaded", function () { - init(); -}); -document.addEventListener("turbolinks:load", function () { - init(); -}); -document.addEventListener("turbo:load", function () { - init(); -}); + } + + function isBoundElement(boundElement, incomingElement) { + return boundElement.has(incomingElement); + } + }; + + document.addEventListener("DOMContentLoaded", function () { + init(); + }); + document.addEventListener("turbolinks:load", function () { + init(); + }); + document.addEventListener("turbo:load", function () { + init(); + }); +})(); diff --git a/config/routes.rb b/config/routes.rb index 3c943d5..cdc3b23 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,9 +2,8 @@ def controllers_for(namespaces) Array(namespaces).each do |namespace| - Dir[Rails.root.join('app', 'controllers', namespace.to_s, '**', '*.rb')].sort.each do |file| - require_dependency file - end + path = Rails.root.join('app', 'controllers', namespace.to_s) + Rails.autoloaders.main.eager_load_dir(path) if path.directory? end ::Administrate::ApplicationController.descendants.uniq diff --git a/lib/administrate_batch_actions.rb b/lib/administrate_batch_actions.rb index c113228..b41e7a1 100644 --- a/lib/administrate_batch_actions.rb +++ b/lib/administrate_batch_actions.rb @@ -1,7 +1,6 @@ require 'rails' require 'active_support' require 'active_support/core_ext' -require 'active_support/dependencies' require 'administrate/engine' require 'administrate_batch_actions/helpers' @@ -13,16 +12,21 @@ module AdministrateBatchActions mattr_accessor :namespace, default: :admin class Engine < ::Rails::Engine + # Propshaft serves every engine asset automatically; Sprockets needs it listed initializer "administrate_batch_actions.assets.precompile" do |app| - app.config.assets.precompile += [ - "administrate_batch_actions/script.js" - ] + if defined?(Sprockets::Railtie) + app.config.assets.precompile += [ + "administrate_batch_actions/script.js" + ] + end end Administrate::Engine.add_javascript 'administrate_batch_actions/script' - initializer "administrate_batch_actions.engine" do |app| - ActionView::Base.send :include, AdministrateBatchActions::Helpers + initializer "administrate_batch_actions.helpers" do + ActiveSupport.on_load(:action_view) do + include AdministrateBatchActions::Helpers + end end end end diff --git a/lib/administrate_batch_actions/helpers.rb b/lib/administrate_batch_actions/helpers.rb index 8dcc2ee..e2aa3b5 100644 --- a/lib/administrate_batch_actions/helpers.rb +++ b/lib/administrate_batch_actions/helpers.rb @@ -1,8 +1,8 @@ module AdministrateBatchActions module Helpers - def administrate_batch_actions_button(name, path, html_options = {class: 'button'}) + def administrate_batch_actions_button(name, path, html_options = {}) render partial: 'shared/administrate_batch_actions/button', - locals: { name: name, path: path, html_options: html_options } + locals: { name: name, path: path, html_options: { class: 'button' }.merge(html_options) } end def administrate_batch_actions_select_all diff --git a/spec/administrate_batch_actions_spec.rb b/spec/administrate_batch_actions_spec.rb index 1aba72f..bcaee44 100644 --- a/spec/administrate_batch_actions_spec.rb +++ b/spec/administrate_batch_actions_spec.rb @@ -1,3 +1,5 @@ +require "rails_helper" + RSpec.describe AdministrateBatchActions do it 'has a version number' do expect(AdministrateBatchActions::VERSION).not_to be nil diff --git a/spec/dummy/.gitattributes b/spec/dummy/.gitattributes deleted file mode 100644 index 6af43c0..0000000 --- a/spec/dummy/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -# See https://git-scm.com/docs/gitattributes for more about git attribute files. - - - -# Mark any vendored files as having been vendored. -vendor/* linguist-vendored diff --git a/spec/dummy/.gitignore b/spec/dummy/.gitignore deleted file mode 100644 index a64aab2..0000000 --- a/spec/dummy/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# See https://help.github.com/articles/ignoring-files for more about ignoring files. -# -# If you find yourself ignoring temporary files generated by your text editor -# or operating system, you probably want to add a global ignore instead: -# git config --global core.excludesfile '~/.gitignore_global' - -# Ignore bundler config. -/.bundle - -# Ignore all logfiles and tempfiles. -/log/* -/tmp/* -!/log/.keep -!/tmp/.keep - -# Ignore pidfiles, but keep the directory. -/tmp/pids/* -!/tmp/pids/ -!/tmp/pids/.keep - - -/public/assets -.byebug_history - -# Ignore master key for decrypting credentials and more. -/config/master.key diff --git a/spec/dummy/.ruby-version b/spec/dummy/.ruby-version deleted file mode 100644 index 2eb2fe9..0000000 --- a/spec/dummy/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -ruby-2.7.2 diff --git a/spec/dummy/README.md b/spec/dummy/README.md deleted file mode 100644 index 7db80e4..0000000 --- a/spec/dummy/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# README - -This README would normally document whatever steps are necessary to get the -application up and running. - -Things you may want to cover: - -* Ruby version - -* System dependencies - -* Configuration - -* Database creation - -* Database initialization - -* How to run the test suite - -* Services (job queues, cache servers, search engines, etc.) - -* Deployment instructions - -* ... diff --git a/spec/dummy/Rakefile b/spec/dummy/Rakefile deleted file mode 100644 index 9a5ea73..0000000 --- a/spec/dummy/Rakefile +++ /dev/null @@ -1,6 +0,0 @@ -# Add your own tasks in files placed in lib/tasks ending in .rake, -# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. - -require_relative "config/application" - -Rails.application.load_tasks diff --git a/spec/dummy/app/assets/config/manifest.js b/spec/dummy/app/assets/config/manifest.js index 5918193..0bd2cc6 100644 --- a/spec/dummy/app/assets/config/manifest.js +++ b/spec/dummy/app/assets/config/manifest.js @@ -1,2 +1 @@ -//= link_tree ../images -//= link_directory ../stylesheets .css +//= link administrate_batch_actions/script.js diff --git a/spec/dummy/app/assets/images/.keep b/spec/dummy/app/assets/images/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/app/assets/stylesheets/application.css b/spec/dummy/app/assets/stylesheets/application.css deleted file mode 100644 index d05ea0f..0000000 --- a/spec/dummy/app/assets/stylesheets/application.css +++ /dev/null @@ -1,15 +0,0 @@ -/* - * This is a manifest file that'll be compiled into application.css, which will include all the files - * listed below. - * - * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's - * vendor/assets/stylesheets directory can be referenced here using a relative path. - * - * You're free to add application-wide styles to this file and they'll appear at the bottom of the - * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS - * files in this directory. Styles in this file should be added after the last require_* statement. - * It is generally better to create a new file per style scope. - * - *= require_tree . - *= require_self - */ diff --git a/spec/dummy/app/controllers/admin/dummy_controller.rb b/spec/dummy/app/controllers/admin/dummy_controller.rb index 553165f..be24093 100644 --- a/spec/dummy/app/controllers/admin/dummy_controller.rb +++ b/spec/dummy/app/controllers/admin/dummy_controller.rb @@ -1,6 +1,8 @@ module Admin class DummyController < Administrate::ApplicationController - def dummy_batch_action; end + def dummy_batch_action + render plain: "ids=#{params[:batch_action_ids].join(',')} scope=#{params[:scope]}" + end def not_valid; end end diff --git a/spec/dummy/app/controllers/backoffice/widgets_controller.rb b/spec/dummy/app/controllers/backoffice/widgets_controller.rb index 7d7d67e..7e3a6a6 100644 --- a/spec/dummy/app/controllers/backoffice/widgets_controller.rb +++ b/spec/dummy/app/controllers/backoffice/widgets_controller.rb @@ -1,5 +1,7 @@ module Backoffice class WidgetsController < Administrate::ApplicationController - def archive_batch_action; end + def archive_batch_action + render plain: "archived=#{params[:batch_action_ids].join(',')}" + end end end diff --git a/spec/dummy/app/controllers/concerns/.keep b/spec/dummy/app/controllers/concerns/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/app/controllers/pages_controller.rb b/spec/dummy/app/controllers/pages_controller.rb new file mode 100644 index 0000000..ccb8219 --- /dev/null +++ b/spec/dummy/app/controllers/pages_controller.rb @@ -0,0 +1,3 @@ +class PagesController < ApplicationController + def batch; end +end diff --git a/spec/dummy/app/helpers/application_helper.rb b/spec/dummy/app/helpers/application_helper.rb deleted file mode 100644 index de6be79..0000000 --- a/spec/dummy/app/helpers/application_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module ApplicationHelper -end diff --git a/spec/dummy/app/models/concerns/.keep b/spec/dummy/app/models/concerns/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/app/views/layouts/application.html.erb b/spec/dummy/app/views/layouts/application.html.erb index b74860f..5502733 100644 --- a/spec/dummy/app/views/layouts/application.html.erb +++ b/spec/dummy/app/views/layouts/application.html.erb @@ -2,13 +2,8 @@ Dummy - - <%= csrf_meta_tags %> - <%= csp_meta_tag %> - - <%= stylesheet_link_tag 'application', media: 'all' %> + <%= javascript_include_tag 'administrate_batch_actions/script' %> - <%= yield %> diff --git a/spec/dummy/app/views/pages/batch.html.erb b/spec/dummy/app/views/pages/batch.html.erb new file mode 100644 index 0000000..66cf51e --- /dev/null +++ b/spec/dummy/app/views/pages/batch.html.erb @@ -0,0 +1,13 @@ +<%= administrate_batch_actions_button('Delete', admin_dummy_batch_action_dummy_path(scope: 'active'), confirm: 'Are you sure?') %> +<%= administrate_batch_actions_button('Archive', backoffice_archive_batch_action_widgets_path) %> + + + + <%= administrate_batch_actions_select_all %> + + + <% [1, 2, 3].each do |id| %> + <%= administrate_batch_actions_checkbox(id) %> + <% end %> + +
diff --git a/spec/dummy/bin/rails b/spec/dummy/bin/rails deleted file mode 100755 index 6fb4e40..0000000 --- a/spec/dummy/bin/rails +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env ruby -APP_PATH = File.expand_path('../config/application', __dir__) -require_relative "../config/boot" -require "rails/commands" diff --git a/spec/dummy/bin/rake b/spec/dummy/bin/rake deleted file mode 100755 index 4fbf10b..0000000 --- a/spec/dummy/bin/rake +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env ruby -require_relative "../config/boot" -require "rake" -Rake.application.run diff --git a/spec/dummy/bin/setup b/spec/dummy/bin/setup deleted file mode 100755 index bf08171..0000000 --- a/spec/dummy/bin/setup +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env ruby -require "fileutils" - -# path to your application root. -APP_ROOT = File.expand_path('..', __dir__) - -def system!(*args) - system(*args) || abort("\n== Command #{args} failed ==") -end - -FileUtils.chdir APP_ROOT do - # This script is a way to set up or update your development environment automatically. - # This script is idempotent, so that you can run it at any time and get an expectable outcome. - # Add necessary setup steps to this file. - - puts '== Installing dependencies ==' - system! 'gem install bundler --conservative' - system('bundle check') || system!('bundle install') - - puts "\n== Removing old logs and tempfiles ==" - system! 'bin/rails log:clear tmp:clear' - - puts "\n== Restarting application server ==" - system! 'bin/rails restart' -end diff --git a/spec/dummy/config.ru b/spec/dummy/config.ru index 4a3c09a..b5f2923 100644 --- a/spec/dummy/config.ru +++ b/spec/dummy/config.ru @@ -1,6 +1,3 @@ -# This file is used by Rack-based servers to start the application. - -require_relative "config/environment" +require_relative 'config/environment' run Rails.application -Rails.application.load_server diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb index 92a4867..71fa431 100644 --- a/spec/dummy/config/application.rb +++ b/spec/dummy/config/application.rb @@ -1,38 +1,17 @@ -require_relative "boot" +require_relative 'boot' -require "rails" -# Pick the frameworks you want: -require "active_model/railtie" -# require "active_job/railtie" -# require "active_record/railtie" -# require "active_storage/engine" -require "action_controller/railtie" -# require "action_mailer/railtie" -# require "action_mailbox/engine" -# require "action_text/engine" -require "action_view/railtie" -# require "action_cable/engine" -require "sprockets/railtie" -# require "rails/test_unit/railtie" +require 'rails' +require 'action_controller/railtie' +require 'action_view/railtie' -# Require the gems listed in Gemfile, including any gems -# you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module Dummy class Application < Rails::Application - # Initialize configuration defaults for originally generated Rails version. - # config.load_defaults 6.1 - - # Configuration for the application, engines, and railties goes here. - # - # These settings can be overridden in specific environments using the files - # in config/environments, which are processed later. - # - # config.time_zone = "Central Time (US & Canada)" - # config.eager_load_paths << Rails.root.join("extras") - - # Don't generate system test files. - config.generators.system_tests = nil + config.load_defaults Rails::VERSION::STRING.to_f + config.root = File.expand_path('..', __dir__) + config.eager_load = false + config.logger = Logger.new(nil) + config.secret_key_base = 'dummy' end end diff --git a/spec/dummy/config/boot.rb b/spec/dummy/config/boot.rb index 34f5030..53813b2 100644 --- a/spec/dummy/config/boot.rb +++ b/spec/dummy/config/boot.rb @@ -1,3 +1,3 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) -require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) -$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) \ No newline at end of file + +require 'bundler/setup' diff --git a/spec/dummy/config/credentials.yml.enc b/spec/dummy/config/credentials.yml.enc deleted file mode 100644 index 7ea2e09..0000000 --- a/spec/dummy/config/credentials.yml.enc +++ /dev/null @@ -1 +0,0 @@ -8fxPolG1mQknn+u6wRWcu1AA9Z8MVWx+NqcZII7cgbPBmr76FpqInkiBOikdpY4YFqYiEqabXMVCKZL84WR7rObbkwCR8ZNiM+anBgdbfNIbrqvaSwMFeA8JFDqSbXB9fFHXpjzmGGzSIZNq28wEB/NKAaafsSixmDvBysN3/MK49S5U8jxiJ3inYwnGzmb6S2xQmSs43LRCLzcdY4WgNR2AB+D39yb9Xoxw0BzoisffkHaIYebKy3GCv7t6GZA+DhLalFZBHp7HxvTE3abS1V5nmPDI15eexR5jDUKET9DIKeAMAhVqNRhplCYevvrNaaFNUWXDKIE+9r708SZMo0AZ0P3Lkyqcu1TkWv0PvZnERKp7Hx3zBfg/Q9yLen8OWCe7bPSQBAL2oeU2/jSTaWR/nes3EydLUXet--m6GrE3tAxa0kSuj1--M8I8f0E/177h795rPacjLw== \ No newline at end of file diff --git a/spec/dummy/config/environment.rb b/spec/dummy/config/environment.rb index cac5315..875ab0f 100644 --- a/spec/dummy/config/environment.rb +++ b/spec/dummy/config/environment.rb @@ -1,5 +1,3 @@ -# Load the Rails application. -require_relative "application" +require_relative 'application' -# Initialize the Rails application. Rails.application.initialize! diff --git a/spec/dummy/config/environments/development.rb b/spec/dummy/config/environments/development.rb deleted file mode 100644 index 839944c..0000000 --- a/spec/dummy/config/environments/development.rb +++ /dev/null @@ -1,62 +0,0 @@ -require "active_support/core_ext/integer/time" - -Rails.application.configure do - # Settings specified here will take precedence over those in config/application.rb. - - # In the development environment your application's code is reloaded any time - # it changes. This slows down response time but is perfect for development - # since you don't have to restart the web server when you make code changes. - config.cache_classes = false - - # Do not eager load code on boot. - config.eager_load = false - - # Show full error reports. - config.consider_all_requests_local = true - - # Enable/disable caching. By default caching is disabled. - # Run rails dev:cache to toggle caching. - if Rails.root.join('tmp', 'caching-dev.txt').exist? - config.action_controller.perform_caching = true - config.action_controller.enable_fragment_cache_logging = true - - config.cache_store = :memory_store - config.public_file_server.headers = { - 'Cache-Control' => "public, max-age=#{2.days.to_i}" - } - else - config.action_controller.perform_caching = false - - config.cache_store = :null_store - end - - # Print deprecation notices to the Rails logger. - config.active_support.deprecation = :log - - # Raise exceptions for disallowed deprecations. - config.active_support.disallowed_deprecation = :raise - - # Tell Active Support which deprecation messages to disallow. - config.active_support.disallowed_deprecation_warnings = [] - - # Debug mode disables concatenation and preprocessing of assets. - # This option may cause significant delays in view rendering with a large - # number of complex assets. - config.assets.debug = true - - # Suppress logger output for asset requests. - config.assets.quiet = true - - # Raises error for missing translations. - # config.i18n.raise_on_missing_translations = true - - # Annotate rendered view with file names. - # config.action_view.annotate_rendered_view_with_filenames = true - - # Use an evented file watcher to asynchronously detect changes in source code, - # routes, locales, etc. This feature depends on the listen gem. - # config.file_watcher = ActiveSupport::EventedFileUpdateChecker - - # Uncomment if you wish to allow Action Cable access from any origin. - # config.action_cable.disable_request_forgery_protection = true -end diff --git a/spec/dummy/config/environments/production.rb b/spec/dummy/config/environments/production.rb deleted file mode 100644 index 20990cb..0000000 --- a/spec/dummy/config/environments/production.rb +++ /dev/null @@ -1,100 +0,0 @@ -require "active_support/core_ext/integer/time" - -Rails.application.configure do - # Settings specified here will take precedence over those in config/application.rb. - - # Code is not reloaded between requests. - config.cache_classes = true - - # Eager load code on boot. This eager loads most of Rails and - # your application in memory, allowing both threaded web servers - # and those relying on copy on write to perform better. - # Rake tasks automatically ignore this option for performance. - config.eager_load = true - - # Full error reports are disabled and caching is turned on. - config.consider_all_requests_local = false - config.action_controller.perform_caching = true - - # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] - # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). - # config.require_master_key = true - - # Disable serving static files from the `/public` folder by default since - # Apache or NGINX already handles this. - config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? - - # Compress CSS using a preprocessor. - # config.assets.css_compressor = :sass - - # Do not fallback to assets pipeline if a precompiled asset is missed. - config.assets.compile = false - - # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.asset_host = 'http://assets.example.com' - - # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX - - # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true - - # Include generic and useful information about system operation, but avoid logging too much - # information to avoid inadvertent exposure of personally identifiable information (PII). - config.log_level = :info - - # Prepend all log lines with the following tags. - config.log_tags = [ :request_id ] - - # Use a different cache store in production. - # config.cache_store = :mem_cache_store - - - # Enable locale fallbacks for I18n (makes lookups for any locale fall back to - # the I18n.default_locale when a translation cannot be found). - config.i18n.fallbacks = true - - # Send deprecation notices to registered listeners. - config.active_support.deprecation = :notify - - # Log disallowed deprecations. - config.active_support.disallowed_deprecation = :log - - # Tell Active Support which deprecation messages to disallow. - config.active_support.disallowed_deprecation_warnings = [] - - # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new - - # Use a different logger for distributed setups. - # require "syslog/logger" - # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') - - if ENV["RAILS_LOG_TO_STDOUT"].present? - logger = ActiveSupport::Logger.new(STDOUT) - logger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(logger) - end - - # Inserts middleware to perform automatic connection switching. - # The `database_selector` hash is used to pass options to the DatabaseSelector - # middleware. The `delay` is used to determine how long to wait after a write - # to send a subsequent read to the primary. - # - # The `database_resolver` class is used by the middleware to determine which - # database is appropriate to use based on the time delay. - # - # The `database_resolver_context` class is used by the middleware to set - # timestamps for the last write to the primary. The resolver uses the context - # class timestamps to determine how long to wait before reading from the - # replica. - # - # By default Rails will store a last write timestamp in the session. The - # DatabaseSelector middleware is designed as such you can define your own - # strategy for connection switching and pass that into the middleware through - # these configuration options. - # config.active_record.database_selector = { delay: 2.seconds } - # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver - # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session -end diff --git a/spec/dummy/config/environments/test.rb b/spec/dummy/config/environments/test.rb index 9fa79dd..d82ff61 100644 --- a/spec/dummy/config/environments/test.rb +++ b/spec/dummy/config/environments/test.rb @@ -1,49 +1,6 @@ -require "active_support/core_ext/integer/time" - -# The test environment is used exclusively to run your application's -# test suite. You never need to work with it otherwise. Remember that -# your test database is "scratch space" for the test suite and is wiped -# and recreated between test runs. Don't rely on the data there! - Rails.application.configure do - # Settings specified here will take precedence over those in config/application.rb. - - config.cache_classes = true - - # Do not eager load code on boot. This avoids loading your whole application - # just for the purpose of running a single test. If you are using a tool that - # preloads Rails for running tests, you may have to set it to true. - config.eager_load = false - - # Configure public file server for tests with Cache-Control for performance. - config.public_file_server.enabled = true - config.public_file_server.headers = { - 'Cache-Control' => "public, max-age=#{1.hour.to_i}" - } - - # Show full error reports and disable caching. - config.consider_all_requests_local = true - config.action_controller.perform_caching = false - config.cache_store = :null_store - - # Raise exceptions instead of rendering exception templates. - config.action_dispatch.show_exceptions = false - - # Disable request forgery protection in test environment. + config.enable_reloading = false if config.respond_to?(:enable_reloading=) + config.consider_all_requests_local = true config.action_controller.allow_forgery_protection = false - - # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr - - # Raise exceptions for disallowed deprecations. - config.active_support.disallowed_deprecation = :raise - - # Tell Active Support which deprecation messages to disallow. - config.active_support.disallowed_deprecation_warnings = [] - - # Raises error for missing translations. - # config.i18n.raise_on_missing_translations = true - - # Annotate rendered view with file names. - # config.action_view.annotate_rendered_view_with_filenames = true end diff --git a/spec/dummy/config/initializers/application_controller_renderer.rb b/spec/dummy/config/initializers/application_controller_renderer.rb deleted file mode 100644 index 89d2efa..0000000 --- a/spec/dummy/config/initializers/application_controller_renderer.rb +++ /dev/null @@ -1,8 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# ActiveSupport::Reloader.to_prepare do -# ApplicationController.renderer.defaults.merge!( -# http_host: 'example.org', -# https: false -# ) -# end diff --git a/spec/dummy/config/initializers/assets.rb b/spec/dummy/config/initializers/assets.rb deleted file mode 100644 index fe48fc3..0000000 --- a/spec/dummy/config/initializers/assets.rb +++ /dev/null @@ -1,12 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Version of your assets, change this if you want to expire all your assets. -Rails.application.config.assets.version = '1.0' - -# Add additional assets to the asset load path. -# Rails.application.config.assets.paths << Emoji.images_path - -# Precompile additional assets. -# application.js, application.css, and all non-JS/CSS in the app/assets -# folder are already added. -# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/spec/dummy/config/initializers/backtrace_silencers.rb b/spec/dummy/config/initializers/backtrace_silencers.rb deleted file mode 100644 index 33699c3..0000000 --- a/spec/dummy/config/initializers/backtrace_silencers.rb +++ /dev/null @@ -1,8 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. -# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } - -# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code -# by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". -Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] diff --git a/spec/dummy/config/initializers/content_security_policy.rb b/spec/dummy/config/initializers/content_security_policy.rb deleted file mode 100644 index 41c4301..0000000 --- a/spec/dummy/config/initializers/content_security_policy.rb +++ /dev/null @@ -1,28 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Define an application-wide content security policy -# For further information see the following documentation -# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy - -# Rails.application.config.content_security_policy do |policy| -# policy.default_src :self, :https -# policy.font_src :self, :https, :data -# policy.img_src :self, :https, :data -# policy.object_src :none -# policy.script_src :self, :https -# policy.style_src :self, :https - -# # Specify URI for violation reports -# # policy.report_uri "/csp-violation-report-endpoint" -# end - -# If you are using UJS then enable automatic nonce generation -# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } - -# Set the nonce only to specific directives -# Rails.application.config.content_security_policy_nonce_directives = %w(script-src) - -# Report CSP violations to a specified URI -# For further information see the following documentation: -# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only -# Rails.application.config.content_security_policy_report_only = true diff --git a/spec/dummy/config/initializers/cookies_serializer.rb b/spec/dummy/config/initializers/cookies_serializer.rb deleted file mode 100644 index 5a6a32d..0000000 --- a/spec/dummy/config/initializers/cookies_serializer.rb +++ /dev/null @@ -1,5 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Specify a serializer for the signed and encrypted cookie jars. -# Valid options are :json, :marshal, and :hybrid. -Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/spec/dummy/config/initializers/filter_parameter_logging.rb b/spec/dummy/config/initializers/filter_parameter_logging.rb deleted file mode 100644 index 4b34a03..0000000 --- a/spec/dummy/config/initializers/filter_parameter_logging.rb +++ /dev/null @@ -1,6 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Configure sensitive parameters which will be filtered from the log file. -Rails.application.config.filter_parameters += [ - :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn -] diff --git a/spec/dummy/config/initializers/inflections.rb b/spec/dummy/config/initializers/inflections.rb deleted file mode 100644 index ac033bf..0000000 --- a/spec/dummy/config/initializers/inflections.rb +++ /dev/null @@ -1,16 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Add new inflection rules using the following format. Inflections -# are locale specific, and you may define rules for as many different -# locales as you wish. All of these examples are active by default: -# ActiveSupport::Inflector.inflections(:en) do |inflect| -# inflect.plural /^(ox)$/i, '\1en' -# inflect.singular /^(ox)en/i, '\1' -# inflect.irregular 'person', 'people' -# inflect.uncountable %w( fish sheep ) -# end - -# These inflection rules are supported but not enabled by default: -# ActiveSupport::Inflector.inflections(:en) do |inflect| -# inflect.acronym 'RESTful' -# end diff --git a/spec/dummy/config/initializers/mime_types.rb b/spec/dummy/config/initializers/mime_types.rb deleted file mode 100644 index dc18996..0000000 --- a/spec/dummy/config/initializers/mime_types.rb +++ /dev/null @@ -1,4 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Add new mime types for use in respond_to blocks: -# Mime::Type.register "text/richtext", :rtf diff --git a/spec/dummy/config/initializers/permissions_policy.rb b/spec/dummy/config/initializers/permissions_policy.rb deleted file mode 100644 index 00f64d7..0000000 --- a/spec/dummy/config/initializers/permissions_policy.rb +++ /dev/null @@ -1,11 +0,0 @@ -# Define an application-wide HTTP permissions policy. For further -# information see https://developers.google.com/web/updates/2018/06/feature-policy -# -# Rails.application.config.permissions_policy do |f| -# f.camera :none -# f.gyroscope :none -# f.microphone :none -# f.usb :none -# f.fullscreen :self -# f.payment :self, "https://secure.example.com" -# end diff --git a/spec/dummy/config/initializers/wrap_parameters.rb b/spec/dummy/config/initializers/wrap_parameters.rb deleted file mode 100644 index 633c1c8..0000000 --- a/spec/dummy/config/initializers/wrap_parameters.rb +++ /dev/null @@ -1,9 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# This file contains settings for ActionController::ParamsWrapper which -# is enabled by default. - -# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. -ActiveSupport.on_load(:action_controller) do - wrap_parameters format: [:json] -end diff --git a/spec/dummy/config/locales/en.yml b/spec/dummy/config/locales/en.yml deleted file mode 100644 index cf9b342..0000000 --- a/spec/dummy/config/locales/en.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Files in the config/locales directory are used for internationalization -# and are automatically loaded by Rails. If you want to use locales other -# than English, add the necessary files in this directory. -# -# To use the locales, use `I18n.t`: -# -# I18n.t 'hello' -# -# In views, this is aliased to just `t`: -# -# <%= t('hello') %> -# -# To use a different locale, set it with `I18n.locale`: -# -# I18n.locale = :es -# -# This would use the information in config/locales/es.yml. -# -# The following keys must be escaped otherwise they will not be retrieved by -# the default I18n backend: -# -# true, false, on, off, yes, no -# -# Instead, surround them with single quotes. -# -# en: -# 'true': 'foo' -# -# To learn more, please read the Rails Internationalization guide -# available at https://guides.rubyonrails.org/i18n.html. - -en: - hello: "Hello world" diff --git a/spec/dummy/config/puma.rb b/spec/dummy/config/puma.rb deleted file mode 100644 index d9b3e83..0000000 --- a/spec/dummy/config/puma.rb +++ /dev/null @@ -1,43 +0,0 @@ -# Puma can serve each request in a thread from an internal thread pool. -# The `threads` method setting takes two numbers: a minimum and maximum. -# Any libraries that use thread pools should be configured to match -# the maximum value specified for Puma. Default is set to 5 threads for minimum -# and maximum; this matches the default thread size of Active Record. -# -max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } -min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } -threads min_threads_count, max_threads_count - -# Specifies the `worker_timeout` threshold that Puma will use to wait before -# terminating a worker in development environments. -# -worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" - -# Specifies the `port` that Puma will listen on to receive requests; default is 3000. -# -port ENV.fetch("PORT") { 3000 } - -# Specifies the `environment` that Puma will run in. -# -environment ENV.fetch("RAILS_ENV") { "development" } - -# Specifies the `pidfile` that Puma will use. -pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } - -# Specifies the number of `workers` to boot in clustered mode. -# Workers are forked web server processes. If using threads and workers together -# the concurrency of the application would be max `threads` * `workers`. -# Workers do not work on JRuby or Windows (both of which do not support -# processes). -# -# workers ENV.fetch("WEB_CONCURRENCY") { 2 } - -# Use the `preload_app!` method when specifying a `workers` number. -# This directive tells Puma to first boot the application and load code -# before forking the application. This takes advantage of Copy On Write -# process behavior so workers use less memory. -# -# preload_app! - -# Allow puma to be restarted by `rails restart` command. -plugin :tmp_restart diff --git a/spec/dummy/config/routes.rb b/spec/dummy/config/routes.rb index c06383a..1b1035d 100644 --- a/spec/dummy/config/routes.rb +++ b/spec/dummy/config/routes.rb @@ -1,3 +1,3 @@ Rails.application.routes.draw do - # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html + get 'batch' => 'pages#batch' end diff --git a/spec/dummy/lib/assets/.keep b/spec/dummy/lib/assets/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/lib/tasks/.keep b/spec/dummy/lib/tasks/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/log/.keep b/spec/dummy/log/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/public/404.html b/spec/dummy/public/404.html deleted file mode 100644 index 2be3af2..0000000 --- a/spec/dummy/public/404.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - The page you were looking for doesn't exist (404) - - - - - - -
-
-

The page you were looking for doesn't exist.

-

You may have mistyped the address or the page may have moved.

-
-

If you are the application owner check the logs for more information.

-
- - diff --git a/spec/dummy/public/422.html b/spec/dummy/public/422.html deleted file mode 100644 index c08eac0..0000000 --- a/spec/dummy/public/422.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - The change you wanted was rejected (422) - - - - - - -
-
-

The change you wanted was rejected.

-

Maybe you tried to change something you didn't have access to.

-
-

If you are the application owner check the logs for more information.

-
- - diff --git a/spec/dummy/public/500.html b/spec/dummy/public/500.html deleted file mode 100644 index 78a030a..0000000 --- a/spec/dummy/public/500.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - We're sorry, but something went wrong (500) - - - - - - -
-
-

We're sorry, but something went wrong.

-
-

If you are the application owner check the logs for more information.

-
- - diff --git a/spec/dummy/public/apple-touch-icon-precomposed.png b/spec/dummy/public/apple-touch-icon-precomposed.png deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/public/apple-touch-icon.png b/spec/dummy/public/apple-touch-icon.png deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/public/favicon.ico b/spec/dummy/public/favicon.ico deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/public/robots.txt b/spec/dummy/public/robots.txt deleted file mode 100644 index c19f78a..0000000 --- a/spec/dummy/public/robots.txt +++ /dev/null @@ -1 +0,0 @@ -# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/spec/dummy/tmp/.keep b/spec/dummy/tmp/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/tmp/pids/.keep b/spec/dummy/tmp/pids/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/spec/dummy/vendor/.keep b/spec/dummy/vendor/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/spec/helpers_spec.rb b/spec/helpers_spec.rb index 15dadc1..251386d 100644 --- a/spec/helpers_spec.rb +++ b/spec/helpers_spec.rb @@ -1,49 +1,47 @@ require 'rails_helper' RSpec.describe 'Helpers', type: :helper do + def render_html(html) + Capybara.string(html) + end + it 'renders action button (default)' do - expected_html = <<~HTML -
- HTML + html = render_html(helper.administrate_batch_actions_button('Delete All', '/')) - expect(helper.administrate_batch_actions_button('Delete All', '/').squish).to include(expected_html.squish) + expect(html).to have_css('form.button_to[method="post"][action="/"][data-turbo="false"]') + expect(html).to have_css('form button.btn.button[type="submit"][disabled][data-batch-action-option="button"]', text: 'Delete All') + expect(html).to have_no_css('button[data-batch-action-confirm]') end it 'renders action button (with class)' do - expected_html = <<~HTML -
- HTML + html = render_html(helper.administrate_batch_actions_button('Delete All', '/', class: 'button text-danger')) - expect(helper.administrate_batch_actions_button('Delete All', '/', class: 'button text-danger').squish).to include(expected_html.squish) + expect(html).to have_css('button.btn.button.text-danger', text: 'Delete All') end it 'renders action button (with confirm window)' do - expected_html = <<~HTML -
- HTML + html = render_html(helper.administrate_batch_actions_button('Delete All', '/', confirm: 'Are you sure to do this?')) - expect(helper.administrate_batch_actions_button('Delete All', '/', class: 'button', confirm: 'Are you sure to do this?').squish).to include(expected_html.squish) + expect(html).to have_css('button.btn.button', text: 'Delete All') + expect(html).to have_css('button[data-batch-action-confirm="Are you sure to do this?"]') + expect(html).to have_no_css('[data-confirm]') end it 'renders action button (keeps query params in the path)' do - expect(helper.administrate_batch_actions_button('Delete All', '/?scope=active')).to include 'action="/?scope=active"' + html = render_html(helper.administrate_batch_actions_button('Delete All', '/?scope=active')) + + expect(html).to have_css('form[action="/?scope=active"]') end it 'renders select all' do - expect(helper.administrate_batch_actions_select_all).to include '' + html = render_html(helper.administrate_batch_actions_select_all) + + expect(html).to have_css('th input[type="checkbox"][data-batch-action-option="select_all"]') end it 'renders checkbox' do - expected_html = <<~HTML - - HTML + html = render_html(helper.administrate_batch_actions_checkbox(1)) - expect(helper.administrate_batch_actions_checkbox(1).squish).to include(expected_html.squish) + expect(html).to have_css('td input[type="checkbox"][value="1"][data-batch-action-option="checkbox"]') end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index b9abd9b..5bbbd55 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,2 +1,15 @@ require 'spec_helper' -require 'rspec/rails' \ No newline at end of file + +ENV['RAILS_ENV'] = 'test' +require_relative 'dummy/config/environment' + +require 'rspec/rails' +require 'capybara/cuprite' + +Capybara.server = :puma, { Silent: true } + +RSpec.configure do |config| + config.before(:each, type: :system) do + driven_by :cuprite, options: { headless: true, js_errors: true } + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f81e36b..ce77e93 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,8 +1,3 @@ -Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each { |f| require f } -ENV['RAILS_ENV'] = 'test' -require_relative '../spec/dummy/config/environment' -ENV['RAILS_ROOT'] ||= "#{File.dirname(__FILE__)}../../../spec/dummy" - RSpec.configure do |config| config.example_status_persistence_file_path = ".rspec_status" config.disable_monkey_patching! @@ -11,4 +6,3 @@ c.syntax = :expect end end - diff --git a/spec/system/batch_actions_spec.rb b/spec/system/batch_actions_spec.rb new file mode 100644 index 0000000..745567e --- /dev/null +++ b/spec/system/batch_actions_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe 'Batch actions', type: :system do + before { visit '/batch' } + + def checkbox(id) + find("input[data-batch-action-option='checkbox'][value='#{id}']") + end + + it 'keeps the buttons disabled until a row is selected' do + expect(page).to have_button('Delete', disabled: true) + + checkbox(1).click + expect(page).to have_button('Delete', disabled: false) + + checkbox(1).click + expect(page).to have_button('Delete', disabled: true) + end + + it 'submits the selected ids and keeps query params in the path' do + checkbox(1).click + checkbox(3).click + + accept_confirm('Are you sure?') { click_button 'Delete' } + + expect(page).to have_content('ids=1,3 scope=active') + end + + it 'does not submit when the confirm is dismissed' do + checkbox(2).click + + dismiss_confirm('Are you sure?') { click_button 'Delete' } + + expect(page).to have_current_path('/batch') + end + + it 'selects every row with select all, without asking to confirm' do + find("input[data-batch-action-option='select_all']").click + + click_button 'Archive' + + expect(page).to have_content('archived=1,2,3') + end + + it 'does not leak globals' do + expect(page.evaluate_script('typeof init')).to eq('undefined') + end +end From f1ab2aa131aa58da07bfae74646171cac7118a3e Mon Sep 17 00:00:00 2001 From: Andrei Bondarev Date: Mon, 26 Oct 2026 14:46:22 -0400 Subject: [PATCH 2/2] Give Chrome more time to start on CI --- spec/rails_helper.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 5bbbd55..618d75c 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -10,6 +10,12 @@ RSpec.configure do |config| config.before(:each, type: :system) do - driven_by :cuprite, options: { headless: true, js_errors: true } + # Chrome can be slow to start on a cold CI runner + driven_by :cuprite, options: { + headless: true, + js_errors: true, + process_timeout: 30, + browser_options: ENV['CI'] ? { 'no-sandbox' => nil } : {} + } end end