diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6da7e4af1..7dcba9da0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,19 +38,15 @@ jobs: include: # Edge Rails (7.1) builds >= 2.7 - ruby: 3.2 - allow_failure: true env: RAILS_VERSION: 'main' - ruby: 3.1 - allow_failure: true env: RAILS_VERSION: 'main' - ruby: '3.0' - allow_failure: true env: RAILS_VERSION: 'main' - ruby: 2.7 - allow_failure: true env: RAILS_VERSION: 'main' diff --git a/Gemfile-rails-dependencies b/Gemfile-rails-dependencies index c69e62e05..83c1e7841 100644 --- a/Gemfile-rails-dependencies +++ b/Gemfile-rails-dependencies @@ -14,8 +14,11 @@ end # sqlite3 is an optional, unspecified, dependency and Rails 6.0 only supports `~> 1.4` gem 'sqlite3', '~> 1.4', platforms: [:ruby] -# Due to capybara strings issue -gem 'puma', '< 6.0.0' +if RUBY_VERSION.to_f < 2.7 + gem 'puma', '< 6.0.0' +else + gem 'puma' +end case version = ENV['RAILS_VERSION'] || (File.exist?(version_file) && File.read(version_file).chomp) || '' when /main/ diff --git a/Rakefile b/Rakefile index 95d48cda2..77d282a72 100644 --- a/Rakefile +++ b/Rakefile @@ -95,6 +95,11 @@ end namespace :smoke do desc "create a new example app with generated specs and run them" task app: ["clobber:app", "generate:app", "generate:stuff", :smoke] + + desc "run RSPEC_OPTS environment variable in the example app for local dev" + task :rspec do + in_example_app "LOCATION='../../example_app_generator/run_specs.rb' bin/rspec #{ENV.fetch("RSPEC_OPTS")}" + end end desc 'clobber generated files' @@ -129,6 +134,11 @@ namespace :no_active_record do "no_active_record:generate:stuff", "no_active_record:smoke", ] + + desc "run RSPEC_OPTS environment variable in the example app for local dev" + task :rspec do + in_example_app "LOCATION='../../example_app_generator/run_specs.rb' bin/rspec #{ENV.fetch("RSPEC_OPTS")}", app_dir: example_app_dir + end end desc "remove the old non-ActiveRecord app" diff --git a/example_app_generator/no_active_record/app/models/in_memory/model.rb b/example_app_generator/no_active_record/app/models/in_memory/model.rb index 9b440e2c7..f9c59143d 100644 --- a/example_app_generator/no_active_record/app/models/in_memory/model.rb +++ b/example_app_generator/no_active_record/app/models/in_memory/model.rb @@ -72,11 +72,13 @@ def save(*) self.class.all << self true end + alias :save! :save def destroy self.class.all.delete(self) true end + alias :destroy! :destroy def reload(*) self diff --git a/lib/rspec/rails/example/view_example_group.rb b/lib/rspec/rails/example/view_example_group.rb index 7aea51b98..2449c95a3 100644 --- a/lib/rspec/rails/example/view_example_group.rb +++ b/lib/rspec/rails/example/view_example_group.rb @@ -83,14 +83,26 @@ def view _view end - # Simulates the presence of a template on the file system by adding a - # Rails' FixtureResolver to the front of the view_paths list. Designed to - # help isolate view examples from partials rendered by the view template - # that is the subject of the example. - # - # stub_template("widgets/_widget.html.erb" => "This content.") - def stub_template(hash) - view.view_paths.unshift(StubResolverCache.resolver_for(hash)) + if ::Rails.version.to_f >= 7.1 + # Simulates the presence of a template on the file system by adding a + # Rails' FixtureResolver to the front of the view_paths list. Designed to + # help isolate view examples from partials rendered by the view template + # that is the subject of the example. + # + # stub_template("widgets/_widget.html.erb" => "This content.") + def stub_template(hash) + view.view_paths.send(:initialize_copy, ActionView::PathSet.new([StubResolverCache.resolver_for(hash)] + view.view_paths.paths)) + end + else + # Simulates the presence of a template on the file system by adding a + # Rails' FixtureResolver to the front of the view_paths list. Designed to + # help isolate view examples from partials rendered by the view template + # that is the subject of the example. + # + # stub_template("widgets/_widget.html.erb" => "This content.") + def stub_template(hash) + view.view_paths.unshift(StubResolverCache.resolver_for(hash)) + end end # Provides access to the params hash that will be available within the diff --git a/lib/rspec/rails/fixture_support.rb b/lib/rspec/rails/fixture_support.rb index ac71b0a04..b5909f885 100644 --- a/lib/rspec/rails/fixture_support.rb +++ b/lib/rspec/rails/fixture_support.rb @@ -38,28 +38,50 @@ def run_in_transaction? module Fixtures extend ActiveSupport::Concern + # rubocop:disable Metrics/BlockLength class_methods do - def fixtures(*args) - orig_methods = private_instance_methods - super.tap do - new_methods = private_instance_methods - orig_methods - new_methods.each do |method_name| - proxy_method_warning_if_called_in_before_context_scope(method_name) + if ::Rails.version.to_f >= 7.1 + def fixtures(*args) + super.tap do + fixture_sets.each_key do |fixture_name| + proxy_method_warning_if_called_in_before_context_scope(fixture_name) + end + end + end + + def proxy_method_warning_if_called_in_before_context_scope(fixture_name) + define_method(fixture_name) do |*args, **kwargs, &blk| + if RSpec.current_scope == :before_context_hook + RSpec.warn_with("Calling fixture method in before :context ") + else + access_fixture(fixture_name, *args, **kwargs, &blk) + end + end + end + else + def fixtures(*args) + orig_methods = private_instance_methods + super.tap do + new_methods = private_instance_methods - orig_methods + new_methods.each do |method_name| + proxy_method_warning_if_called_in_before_context_scope(method_name) + end end end - end - def proxy_method_warning_if_called_in_before_context_scope(method_name) - orig_implementation = instance_method(method_name) - define_method(method_name) do |*args, &blk| - if RSpec.current_scope == :before_context_hook - RSpec.warn_with("Calling fixture method in before :context ") - else - orig_implementation.bind(self).call(*args, &blk) + def proxy_method_warning_if_called_in_before_context_scope(method_name) + orig_implementation = instance_method(method_name) + define_method(method_name) do |*args, &blk| + if RSpec.current_scope == :before_context_hook + RSpec.warn_with("Calling fixture method in before :context ") + else + orig_implementation.bind(self).call(*args, &blk) + end end end end end + # rubocop:enable Metrics/BlockLength end end end diff --git a/spec/rspec/rails/example/view_example_group_spec.rb b/spec/rspec/rails/example/view_example_group_spec.rb index f4ca8ea94..d2a5f86ed 100644 --- a/spec/rspec/rails/example/view_example_group_spec.rb +++ b/spec/rspec/rails/example/view_example_group_spec.rb @@ -283,7 +283,7 @@ def _view; end Class.new do include ViewExampleGroup::ExampleMethods def _view - @_view ||= Struct.new(:view_paths).new(['some-path']) + @_view ||= Struct.new(:view_paths).new(ActionView::PathSet.new(['some-path'])) end end end