Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: CI
on:
pull_request:
push:
branches: [master]

permissions:
contents: read

jobs:
test:
name: Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }} / AA ${{ matrix.activeadmin }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Ruby 3.3 is the floor: 3.1 (eol 2025-03-26) and 3.2 (eol 2026-03-31)
# are both out of support.
ruby: ['3.3', '3.4', '4.0']
# Rails 7.2 went eol 2026-08-09; 8.2 is not released yet.
rails: ['8.0.0', '8.1.0']
# Every activeadmin 3.2+ resolves and passes against Rails 8.0 and 8.1,
# so no exclude rules are needed.
activeadmin: ['3.2.0', '3.3.0', '3.4.0', '3.5.0']
env:
RAILS: ${{ matrix.rails }}
AA: ${{ matrix.activeadmin }}
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: Run tests
run: bundle exec rspec spec
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/.bundle/
/bin/
/Gemfile.lock
/pkg/
/tmp/
spec/rails/rails-*
/coverage
20 changes: 19 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
source 'http://rubygems.org'
source 'https://rubygems.org'

gemspec

default_rails_version = '8.1.0'
default_activeadmin_version = '3.5.0'

gem 'rails', "~> #{ENV['RAILS'] || default_rails_version}"
gem 'activeadmin', "~> #{ENV['AA'] || default_activeadmin_version}"
gem 'sprockets-rails'
gem 'sass-rails'

group :test do
gem 'simplecov', require: false
gem 'rspec-rails'
gem 'sqlite3', '~> 2.0'
gem 'database_cleaner'
gem 'capybara'
gem 'cuprite'
gem 'webrick', require: false
end
6 changes: 5 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
require 'bundler/gem_tasks'
require "bundler"
require 'rake'
Bundler.setup
Bundler::GemHelper.install_tasks
FileList['tasks/**/*.rake'].each { |task| import task }
4 changes: 3 additions & 1 deletion active_admin_filters_visibility.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ Gem::Specification.new do |s|
s.summary = %q{active_admin_filters_visibility gem}
s.description = %q{extension for activeadmin gem to hide any filters from sidebar-filters panel}

s.add_dependency 'activeadmin'
s.required_ruby_version = '>= 3.3'

s.add_dependency 'activeadmin', '>= 3.2', '< 4.0'

s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
Expand Down
90 changes: 90 additions & 0 deletions spec/filters_visibility_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
require 'spec_helper'

describe 'filters visibility', type: :feature, js: true do

# The dummy app's active_admin.js calls
# `$('#filters_sidebar_section').activeAdminFiltersVisibility()`, so these
# are the filters Active Admin derives from the authors table.
FILTERS = {
'Name' => '#q_name_input',
'Last name' => '#q_last_name_input',
'Birthday' => '#q_birthday_input',
'Created at' => '#q_created_at_input',
'Updated at' => '#q_updated_at_input'
}.freeze

# The visibility panel is `display: none` until the gear button is clicked.
def open_visibility_panel
page.find('#filters_sidebar_section .filters-visibility-button').click
expect(page).to have_css('.filters-visibility-panel')
end

def visibility_checkbox(label)
page.find(".filters-visibility-panel input[type=checkbox][value='#{label}']")
end

before do
Author.create!(name: 'John', last_name: 'Doe')
Author.create!(name: 'Jane', last_name: 'Roe')
add_author_resource
visit '/admin/authors'
end

it 'renders the gear button and the visibility panel in the filters sidebar' do
expect(page).to have_css('#filters_sidebar_section h3 span.filters-visibility-button')
# hidden until the button is clicked
expect(page).to have_css('#filters_sidebar_section .panel_contents > .filters-visibility-panel', visible: :hidden)
expect(page).to have_css('.filters-visibility-panel > div > strong', text: 'Visibility:', visible: :hidden)

open_visibility_panel
end

it 'has one checked checkbox per filter and shows every filter' do
open_visibility_panel

expect(page).to have_css('.filters-visibility-panel input[type=checkbox]', count: FILTERS.size)
FILTERS.each do |label, selector|
expect(visibility_checkbox(label)).to be_checked
expect(page).to have_css(selector)
end
expect(page).not_to have_css('.filters-visibility-button.active')
end

it 'hides a filter when its checkbox is unchecked' do
open_visibility_panel
visibility_checkbox('Birthday').click

expect(page).to have_css('#q_birthday_input', visible: :hidden)
expect(page).to have_css('.filters-visibility-button.active')
# the other filters are untouched
expect(page).to have_css('#q_name_input')
expect(page).to have_css('#q_created_at_input')
end

it 'keeps the filter hidden after a page reload' do
open_visibility_panel
visibility_checkbox('Birthday').click
expect(page).to have_css('#q_birthday_input', visible: :hidden)

visit '/admin/authors'

expect(page).to have_css('#q_birthday_input', visible: :hidden)
expect(page).to have_css('.filters-visibility-button.active')

open_visibility_panel
expect(visibility_checkbox('Birthday')).not_to be_checked
expect(visibility_checkbox('Name')).to be_checked
end

it 'shows the filter again when the checkbox is re-checked' do
open_visibility_panel
visibility_checkbox('Birthday').click
expect(page).to have_css('#q_birthday_input', visible: :hidden)

visibility_checkbox('Birthday').click

expect(page).to have_css('#q_birthday_input')
expect(page).not_to have_css('.filters-visibility-button.active')
end

end
56 changes: 56 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
require 'simplecov'
SimpleCov.start do
add_filter '/spec/'
end

$LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH << File.expand_path('../support', __FILE__)

ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
require "bundler"
Bundler.setup

ENV['RAILS_ENV'] = 'test'
require 'rails'
ENV['RAILS'] = Rails.version
ENV['RAILS_ROOT'] = File.expand_path("../rails/rails-#{ENV['RAILS']}", __FILE__)
unless File.exist?(ENV['RAILS_ROOT'])
system 'rake setup'
end

require 'rails/all'
require 'active_admin'
ActiveAdmin.application.load_paths = [ENV['RAILS_ROOT'] + "/app/admin"]
require ENV['RAILS_ROOT'] + '/config/environment.rb'
ActiveAdmin.application.authentication_method = false
ActiveAdmin.application.current_user_method = false

# Rails 8.1 draws routes lazily, so ActiveAdmin's `before_load` hooks -- the
# ones that mix BatchActions/Filters into ActiveAdmin::Resource -- have not run
# by the time a spec calls `ActiveAdmin.register`. Resources built before them
# come out half-initialized (`@batch_actions` nil) and the index page blows up.
ActiveAdmin.application.load!

require 'rspec/rails'
require 'capybara/rails'
require 'capybara/rspec'

require 'support/admin'
require 'support/capybara'

RSpec.configure do |config|
config.use_transactional_fixtures = false

config.before(:suite) do
ActiveRecord::Migration.maintain_test_schema!
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
9 changes: 9 additions & 0 deletions spec/support/admin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
def add_author_resource(options = {}, &block)

ActiveAdmin.register Author do
config.filters = true
end

Rails.application.reload_routes!

end
29 changes: 29 additions & 0 deletions spec/support/capybara.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require 'capybara/cuprite'

Capybara.server = :webrick
Capybara.register_driver :cuprite do |app|
# Chrome intermittently fails to hand back a websocket URL on GitHub
# runners and the leg dies with Ferrum::ProcessTimeoutError. The cause
# is not established. Two theories were tried and both are ruled out:
#
# * /dev/shm exhaustion -- Ferrum already passes
# --disable-dev-shm-usage by default
# (Ferrum::Browser::Options::Chrome::DEFAULT_OPTIONS), so the runs
# that failed were already using it.
# * the ubuntu-24.04 AppArmor restriction on unprivileged user
# namespaces -- the sibling repo capybara_active_admin passes
# --no-sandbox and --disable-setuid-sandbox already, and flakes
# the same way.
#
# So: --no-sandbox is kept because it is harmless on a single-tenant
# CI VM serving only this suite's dummy app and may still help, and
# process_timeout is raised from Ferrum's 10s default because a slow
# start is at least a failure mode a budget can cover. Neither is
# demonstrated to fix it. A rerun is currently the answer when it
# happens.
Capybara::Cuprite::Driver.new(app, headless: true, window_size: [1280, 800],
process_timeout: 30,
browser_options: { 'no-sandbox': nil })
end
Capybara.javascript_driver = :cuprite
Capybara.default_max_wait_time = 5
67 changes: 67 additions & 0 deletions spec/support/rails_template.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Rails 8.1 generates `stale_when_importmap_changes` into ApplicationController,
# but importmap-rails is not in this bundle (the suite serves assets through
# Sprockets), so the constant never gets defined and loading the controller
# raises NameError.
#
# This has to happen before anything else in this template: `generate` shells
# out to `rails generate`, which boots the app, and `config/environments/test.rb`
# sets `config.eager_load = ENV["CI"].present?` -- so on CI the controller is
# eager-loaded during generation and the template dies on its first model.
# Locally (no CI env var) it stays lazy and only the specs would notice.
gsub_file "app/controllers/application_controller.rb", /^\s*stale_when_importmap_changes\s*\n/, "", verbose: false

# Ensure Sprockets manifest exists (required by Rails 8+)
FileUtils.mkdir_p("app/assets/config")
File.write("app/assets/config/manifest.js",
"//= link_directory ../javascripts .js\n//= link_directory ../stylesheets .css\n")

generate :model, 'author name:string{10}:uniq last_name:string birthday:date --force'
generate :model, 'post title:string:uniq body:text author:references --force'

inject_into_file "app/models/author.rb", " validates_presence_of :name\n validates_uniqueness_of :last_name\n", after: "ApplicationRecord\n"
inject_into_file "app/models/post.rb", " validates_presence_of :author\n", after: ":author\n"

# Add ransackable_attributes for Ransack 4+
inject_into_file "app/models/author.rb",
" def self.ransackable_attributes(auth_object = nil)\n" \
" [\"name\", \"last_name\", \"birthday\", \"created_at\"]\n" \
" end\n",
after: "ApplicationRecord\n"

inject_into_file "app/models/post.rb",
" def self.ransackable_attributes(auth_object = nil)\n" \
" [\"title\", \"body\", \"author_id\"]\n" \
" end\n" \
" def self.ransackable_associations(auth_object = nil)\n" \
" [\"author\"]\n" \
" end\n",
after: "ApplicationRecord\n"

# Add our local Active Admin to the load path (Rails 7.1+)
gsub_file "config/environment.rb",
'require_relative "application"',
"require_relative \"application\"\n$LOAD_PATH.unshift('#{File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib'))}')\nrequire \"active_admin\"\n"

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))

generate :'active_admin:install --skip-users'
generate :'formtastic:install'

# Wire the plugin into the dummy app: require the asset, then invoke the
# jQuery plugin on the filters sidebar panel. Without the invocation the
# plugin never runs and no spec can see anything.
inject_into_file "app/assets/javascripts/active_admin.js",
"//= require active_admin_filters_visibility\n",
after: "//= require active_admin/base\n"

append_to_file "app/assets/javascripts/active_admin.js", <<~JS
$(document).ready(function() {
$('#filters_sidebar_section').activeAdminFiltersVisibility();
});
JS

run "rm -rf test"
route "root :to => 'admin/dashboard#index'"
rake "db:migrate"

run "rm -f Gemfile Gemfile.lock"
13 changes: 13 additions & 0 deletions tasks/test.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
desc "Creates a test rails app for the specs to run against"
task :setup do
require 'rails/version'

rails_new_opts = %w(
--skip-turbolinks
--skip-spring
--skip-bootsnap
-m
spec/support/rails_template.rb
)
system "bundle exec rails new spec/rails/rails-#{Rails::VERSION::STRING} #{rails_new_opts.join(' ')}"
end
Loading