rspec-rails 5.1.2 → 7.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Changelog.md +355 -173
  4. data/README.md +40 -40
  5. data/lib/generators/rspec/channel/channel_generator.rb +1 -1
  6. data/lib/generators/rspec/controller/controller_generator.rb +4 -4
  7. data/lib/generators/rspec/feature/feature_generator.rb +1 -1
  8. data/lib/generators/rspec/generator/generator_generator.rb +3 -3
  9. data/lib/generators/rspec/generator/templates/generator_spec.rb +1 -2
  10. data/lib/generators/rspec/helper/helper_generator.rb +1 -1
  11. data/lib/generators/rspec/install/install_generator.rb +19 -2
  12. data/lib/generators/rspec/install/templates/spec/rails_helper.rb +27 -15
  13. data/lib/generators/rspec/job/job_generator.rb +1 -1
  14. data/lib/generators/rspec/mailbox/mailbox_generator.rb +1 -1
  15. data/lib/generators/rspec/mailer/mailer_generator.rb +5 -3
  16. data/lib/generators/rspec/mailer/templates/preview.rb +3 -3
  17. data/lib/generators/rspec/model/model_generator.rb +3 -3
  18. data/lib/generators/rspec/request/request_generator.rb +10 -3
  19. data/lib/generators/rspec/scaffold/scaffold_generator.rb +4 -4
  20. data/lib/generators/rspec/scaffold/templates/controller_spec.rb +4 -4
  21. data/lib/generators/rspec/scaffold/templates/edit_spec.rb +8 -4
  22. data/lib/generators/rspec/scaffold/templates/index_spec.rb +2 -1
  23. data/lib/generators/rspec/scaffold/templates/new_spec.rb +1 -1
  24. data/lib/generators/rspec/scaffold/templates/request_spec.rb +4 -4
  25. data/lib/generators/rspec/scaffold/templates/show_spec.rb +1 -1
  26. data/lib/generators/rspec/system/system_generator.rb +1 -1
  27. data/lib/generators/rspec/view/view_generator.rb +2 -2
  28. data/lib/generators/rspec.rb +18 -1
  29. data/lib/rspec/rails/adapters.rb +11 -0
  30. data/lib/rspec/rails/configuration.rb +43 -14
  31. data/lib/rspec/rails/example/mailbox_example_group.rb +1 -1
  32. data/lib/rspec/rails/example/rails_example_group.rb +6 -0
  33. data/lib/rspec/rails/example/routing_example_group.rb +0 -2
  34. data/lib/rspec/rails/example/system_example_group.rb +67 -12
  35. data/lib/rspec/rails/example/view_example_group.rb +6 -5
  36. data/lib/rspec/rails/feature_check.rb +6 -2
  37. data/lib/rspec/rails/file_fixture_support.rb +3 -0
  38. data/lib/rspec/rails/fixture_file_upload_support.rb +20 -31
  39. data/lib/rspec/rails/fixture_support.rb +44 -17
  40. data/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +16 -6
  41. data/lib/rspec/rails/matchers/action_cable.rb +6 -1
  42. data/lib/rspec/rails/matchers/active_job.rb +73 -12
  43. data/lib/rspec/rails/matchers/have_enqueued_mail.rb +40 -7
  44. data/lib/rspec/rails/matchers/have_http_status.rb +4 -8
  45. data/lib/rspec/rails/matchers/routing_matchers.rb +2 -2
  46. data/lib/rspec/rails/matchers/send_email.rb +122 -0
  47. data/lib/rspec/rails/matchers.rb +1 -0
  48. data/lib/rspec/rails/tasks/rspec.rake +3 -1
  49. data/lib/rspec/rails/vendor/capybara.rb +1 -3
  50. data/lib/rspec/rails/version.rb +1 -1
  51. data/lib/rspec/rails/view_assigns.rb +0 -18
  52. data/lib/rspec/rails/view_rendering.rb +13 -11
  53. data/lib/rspec-rails.rb +28 -7
  54. data.tar.gz.sig +0 -0
  55. metadata +42 -58
  56. metadata.gz.sig +0 -0
  57. data/lib/generators/rspec/integration/integration_generator.rb +0 -22
  58. /data/lib/generators/rspec/{integration → request}/templates/request_spec.rb +0 -0
@@ -3,7 +3,7 @@ require 'rails_helper'
3
3
  <% output_attributes = attributes.reject{|attribute| [:datetime, :timestamp, :time, :date].index(attribute.type) } -%>
4
4
  RSpec.describe "<%= ns_table_name %>/show", <%= type_metatag(:view) %> do
5
5
  before(:each) do
6
- @<%= ns_file_name %> = assign(:<%= ns_file_name %>, <%= class_name %>.create!(<%= '))' if output_attributes.empty? %>
6
+ assign(:<%= singular_table_name %>, <%= class_name %>.create!(<%= '))' if output_attributes.empty? %>
7
7
  <% output_attributes.each_with_index do |attribute, attribute_index| -%>
8
8
  <%= attribute.name %>: <%= value_for(attribute) %><%= attribute_index == output_attributes.length - 1 ? '' : ','%>
9
9
  <% end -%>
@@ -9,7 +9,7 @@ module Rspec
9
9
  def generate_system_spec
10
10
  return unless options[:system_specs]
11
11
 
12
- template template_name, File.join('spec/system', class_path, filename)
12
+ template template_name, target_path('system', class_path, filename)
13
13
  end
14
14
 
15
15
  def template_name
@@ -9,12 +9,12 @@ module Rspec
9
9
  class_option :template_engine, desc: "Template engine to generate view files"
10
10
 
11
11
  def create_view_specs
12
- empty_directory File.join("spec", "views", file_path)
12
+ empty_directory target_path("views", file_path)
13
13
 
14
14
  actions.each do |action|
15
15
  @action = action
16
16
  template 'view_spec.rb',
17
- File.join("spec", "views", file_path, "#{@action}.html.#{options[:template_engine]}_spec.rb")
17
+ target_path("views", file_path, "#{@action}.html.#{options[:template_engine]}_spec.rb")
18
18
  end
19
19
  end
20
20
  end
@@ -1,8 +1,9 @@
1
1
  require 'rails/generators/named_base'
2
+ require 'rspec/core'
2
3
  require 'rspec/rails/feature_check'
3
4
 
4
5
  # @private
5
- # Weirdly named generators namespace (should be `RSpec`) for compatability with
6
+ # Weirdly named generators namespace (should be `RSpec`) for compatibility with
6
7
  # rails loading.
7
8
  module Rspec
8
9
  # @private
@@ -18,6 +19,22 @@ module Rspec
18
19
  @_rspec_source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'rspec', generator_name, 'templates'))
19
20
  end
20
21
  end
22
+
23
+ # @private
24
+ # Load configuration from RSpec to ensure `--default-path` is set
25
+ def self.configuration
26
+ @configuration ||=
27
+ begin
28
+ configuration = RSpec.configuration
29
+ options = RSpec::Core::ConfigurationOptions.new({})
30
+ options.configure(configuration)
31
+ configuration
32
+ end
33
+ end
34
+
35
+ def target_path(*paths)
36
+ File.join(self.class.configuration.default_path, *paths)
37
+ end
21
38
  end
22
39
  end
23
40
  end
@@ -181,5 +181,16 @@ module RSpec
181
181
  #
182
182
  # @private
183
183
  TestUnitAssertionAdapter = MinitestAssertionAdapter
184
+
185
+ # @private
186
+ module TaggedLoggingAdapter
187
+ private
188
+ # Vendored from activesupport/lib/active_support/testing/tagged_logging.rb
189
+ # This implements the tagged_logger method where it is expected, but
190
+ # doesn't call `name` or set it up like Rails does.
191
+ def tagged_logger
192
+ @tagged_logger ||= (defined?(Rails.logger) && Rails.logger)
193
+ end
194
+ end
184
195
  end
185
196
  end
@@ -26,19 +26,19 @@ module RSpec
26
26
  #
27
27
  # @api private
28
28
  DIRECTORY_MAPPINGS = {
29
- channel: %w[spec channels],
29
+ channel: %w[spec channels],
30
30
  controller: %w[spec controllers],
31
- generator: %w[spec generator],
32
- helper: %w[spec helpers],
33
- job: %w[spec jobs],
34
- mailer: %w[spec mailers],
35
- model: %w[spec models],
36
- request: %w[spec (requests|integration|api)],
37
- routing: %w[spec routing],
38
- view: %w[spec views],
39
- feature: %w[spec features],
40
- system: %w[spec system],
41
- mailbox: %w[spec mailboxes]
31
+ generator: %w[spec generator],
32
+ helper: %w[spec helpers],
33
+ job: %w[spec jobs],
34
+ mailer: %w[spec mailers],
35
+ model: %w[spec models],
36
+ request: %w[spec (requests|integration|api)],
37
+ routing: %w[spec routing],
38
+ view: %w[spec views],
39
+ feature: %w[spec features],
40
+ system: %w[spec system],
41
+ mailbox: %w[spec mailboxes]
42
42
  }
43
43
 
44
44
  # Sets up the different example group modules for the different spec types
@@ -57,7 +57,7 @@ module RSpec
57
57
  end
58
58
 
59
59
  # @private
60
- def self.initialize_configuration(config) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity
60
+ def self.initialize_configuration(config) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/AbcSize,Metrics/PerceivedComplexity
61
61
  config.backtrace_exclusion_patterns << /vendor\//
62
62
  config.backtrace_exclusion_patterns << %r{lib/rspec/rails}
63
63
 
@@ -69,7 +69,13 @@ module RSpec
69
69
  config.add_setting :use_transactional_fixtures, alias_with: :use_transactional_examples
70
70
  config.add_setting :use_instantiated_fixtures
71
71
  config.add_setting :global_fixtures
72
- config.add_setting :fixture_path
72
+
73
+ if ::Rails::VERSION::STRING < "7.1.0"
74
+ config.add_setting :fixture_path
75
+ else
76
+ config.add_setting :fixture_paths
77
+ end
78
+
73
79
  config.include RSpec::Rails::FixtureSupport, :use_fixtures
74
80
 
75
81
  # We'll need to create a deprecated module in order to properly report to
@@ -157,6 +163,29 @@ module RSpec
157
163
  filter_gems_from_backtrace "activemodel", "activerecord",
158
164
  "activesupport", "activejob"
159
165
  end
166
+
167
+ # @deprecated TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2
168
+ if ::Rails::VERSION::STRING >= "7.1.0"
169
+ def fixture_path
170
+ RSpec.deprecate(
171
+ "config.fixture_path",
172
+ replacement: "config.fixture_paths",
173
+ message: "Rails 7.1 has deprecated the singular fixture_path in favour of an array." \
174
+ "You should migrate to plural:"
175
+ )
176
+ fixture_paths&.first
177
+ end
178
+
179
+ def fixture_path=(path)
180
+ RSpec.deprecate(
181
+ "config.fixture_path = #{path.inspect}",
182
+ replacement: "config.fixture_paths = [#{path.inspect}]",
183
+ message: "Rails 7.1 has deprecated the singular fixture_path in favour of an array." \
184
+ "You should migrate to plural:"
185
+ )
186
+ self.fixture_paths = Array(path)
187
+ end
188
+ end
160
189
  end
161
190
 
162
191
  add_test_type_configurations(config)
@@ -69,7 +69,7 @@ module RSpec
69
69
  #
70
70
  # @param message [Hash, Mail::Message] a mail message or hash of
71
71
  # attributes used to build one
72
- # @return [ActionMaibox::InboundMessage]
72
+ # @return [ActionMailbox::InboundMessage]
73
73
  def process(message)
74
74
  MailboxExampleGroup.create_inbound_email(message).tap do |mail|
75
75
  self.class.mailbox_class.receive(mail)
@@ -2,6 +2,9 @@
2
2
  # suite and ammeter.
3
3
  require 'rspec/rails/matchers'
4
4
 
5
+ require 'active_support/current_attributes/test_helper'
6
+ require 'active_support/execution_context/test_helper'
7
+
5
8
  module RSpec
6
9
  module Rails
7
10
  # @api public
@@ -12,6 +15,9 @@ module RSpec
12
15
  include RSpec::Rails::MinitestLifecycleAdapter
13
16
  include RSpec::Rails::MinitestAssertionAdapter
14
17
  include RSpec::Rails::FixtureSupport
18
+ include RSpec::Rails::TaggedLoggingAdapter
19
+ include ActiveSupport::CurrentAttributes::TestHelper
20
+ include ActiveSupport::ExecutionContext::TestHelper
15
21
  end
16
22
  end
17
23
  end
@@ -1,5 +1,3 @@
1
- require "action_dispatch/testing/assertions/routing"
2
-
3
1
  module RSpec
4
2
  module Rails
5
3
  # @private
@@ -44,33 +44,86 @@ module RSpec
44
44
  ].join("_").tr(CHARS_TO_TRANSLATE.join, "_").byteslice(0...200).scrub("") + "_#{rand(1000)}"
45
45
  end
46
46
 
47
+ if ::Rails::VERSION::STRING.to_f >= 7.1
48
+ # @private
49
+ # Allows failure screenshot to work whilst not exposing metadata
50
+ class SuppressRailsScreenshotMetadata
51
+ def initialize
52
+ @example_data = {}
53
+ end
54
+
55
+ def [](key)
56
+ if @example_data.key?(key)
57
+ @example_data[key]
58
+ else
59
+ raise_wrong_scope_error
60
+ end
61
+ end
62
+
63
+ def []=(key, value)
64
+ if key == :failure_screenshot_path
65
+ @example_data[key] = value
66
+ else
67
+ raise_wrong_scope_error
68
+ end
69
+ end
70
+
71
+ def method_missing(_name, *_args, &_block)
72
+ raise_wrong_scope_error
73
+ end
74
+
75
+ private
76
+
77
+ def raise_wrong_scope_error
78
+ raise RSpec::Core::ExampleGroup::WrongScopeError,
79
+ "`metadata` is not available from within an example " \
80
+ "(e.g. an `it` block) or from constructs that run in the " \
81
+ "scope of an example (e.g. `before`, `let`, etc). It is " \
82
+ "only available on an example group (e.g. a `describe` or "\
83
+ "`context` block)"
84
+ end
85
+ end
86
+
87
+ # @private
88
+ def metadata
89
+ @metadata ||= SuppressRailsScreenshotMetadata.new
90
+ end
91
+ end
92
+
47
93
  # Delegates to `Rails.application`.
48
94
  def app
49
95
  ::Rails.application
50
96
  end
51
97
 
98
+ # Default driver to assign if none specified.
99
+ DEFAULT_DRIVER =
100
+ if ::Rails::VERSION::STRING.to_f >= 7.2
101
+ :selenium_chrome_headless
102
+ else
103
+ :selenium
104
+ end
105
+
52
106
  included do |other|
53
107
  ActiveSupport.on_load(:action_dispatch_system_test_case) do
54
108
  ActionDispatch::SystemTesting::Server.silence_puma = true
55
109
  end
56
110
 
111
+ require 'action_dispatch/system_test_case'
112
+
57
113
  begin
58
114
  require 'capybara'
59
- require 'action_dispatch/system_test_case'
60
115
  rescue LoadError => e
61
116
  abort """
62
117
  LoadError: #{e.message}
63
- System test integration requires Rails >= 5.1 and has a hard
118
+ System test integration has a hard
64
119
  dependency on a webserver and `capybara`, please add capybara to
65
120
  your Gemfile and configure a webserver (e.g. `Capybara.server =
66
- :webrick`) before attempting to use system specs.
121
+ :puma`) before attempting to use system specs.
67
122
  """.gsub(/\s+/, ' ').strip
68
123
  end
69
124
 
70
- if ::Rails::VERSION::STRING >= '6.0'
71
- original_before_teardown =
72
- ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.instance_method(:before_teardown)
73
- end
125
+ original_before_teardown =
126
+ ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.instance_method(:before_teardown)
74
127
 
75
128
  original_after_teardown =
76
129
  ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.instance_method(:after_teardown)
@@ -92,7 +145,7 @@ module RSpec
92
145
  self.class.before do
93
146
  # A user may have already set the driver, so only default if driver
94
147
  # is not set
95
- driven_by(:selenium) unless @driver
148
+ driven_by(DEFAULT_DRIVER) unless @driver
96
149
  end
97
150
  end
98
151
 
@@ -108,10 +161,7 @@ module RSpec
108
161
  orig_stdout = $stdout
109
162
  $stdout = StringIO.new
110
163
  begin
111
- if ::Rails::VERSION::STRING >= '6.0'
112
- original_before_teardown.bind(self).call
113
- end
114
- original_after_teardown.bind(self).call
164
+ original_before_teardown.bind(self).call
115
165
  ensure
116
166
  myio = $stdout
117
167
  myio.rewind
@@ -119,6 +169,11 @@ module RSpec
119
169
  $stdout = orig_stdout
120
170
  end
121
171
  end
172
+
173
+ around do |example|
174
+ example.run
175
+ original_after_teardown.bind(self).call
176
+ end
122
177
  end
123
178
  end
124
179
  end
@@ -65,6 +65,7 @@ module RSpec
65
65
  # end
66
66
  def render(options = {}, local_assigns = {}, &block)
67
67
  options = _default_render_options if Hash === options && options.empty?
68
+ options = options.merge(_default_render_options) if Hash === options && options.keys == [:locals]
68
69
  super(options, local_assigns, &block)
69
70
  end
70
71
 
@@ -89,7 +90,7 @@ module RSpec
89
90
  #
90
91
  # stub_template("widgets/_widget.html.erb" => "This content.")
91
92
  def stub_template(hash)
92
- view.view_paths.unshift(StubResolverCache.resolver_for(hash))
93
+ controller.prepend_view_path(StubResolverCache.resolver_for(hash))
93
94
  end
94
95
 
95
96
  # Provides access to the params hash that will be available within the
@@ -149,11 +150,11 @@ module RSpec
149
150
  # the original string.
150
151
  match = path_regex.match(_default_file_to_render)
151
152
 
152
- render_options = {template: match[:template]}
153
- render_options[:handlers] = [match[:handler]] if match[:handler]
153
+ render_options = { template: match[:template] }
154
+ render_options[:handlers] = [match[:handler].to_sym] if match[:handler]
154
155
  render_options[:formats] = [match[:format].to_sym] if match[:format]
155
- render_options[:locales] = [match[:locale]] if match[:locale]
156
- render_options[:variants] = [match[:variant]] if match[:variant]
156
+ render_options[:locales] = [match[:locale].to_sym] if match[:locale]
157
+ render_options[:variants] = [match[:variant].to_sym] if match[:variant]
157
158
 
158
159
  render_options
159
160
  end
@@ -24,17 +24,21 @@ module RSpec
24
24
  end
25
25
 
26
26
  def has_action_cable_testing?
27
- defined?(::ActionCable) && ActionCable::VERSION::MAJOR >= 6
27
+ defined?(::ActionCable)
28
28
  end
29
29
 
30
30
  def has_action_mailer_parameterized?
31
- has_action_mailer? && defined?(::ActionMailer::Parameterized)
31
+ has_action_mailer? && defined?(::ActionMailer::Parameterized::DeliveryJob)
32
32
  end
33
33
 
34
34
  def has_action_mailer_unified_delivery?
35
35
  has_action_mailer? && defined?(::ActionMailer::MailDeliveryJob)
36
36
  end
37
37
 
38
+ def has_action_mailer_legacy_delivery_job?
39
+ defined?(ActionMailer::DeliveryJob)
40
+ end
41
+
38
42
  def has_action_mailbox?
39
43
  defined?(::ActionMailbox)
40
44
  end
@@ -9,6 +9,9 @@ module RSpec
9
9
 
10
10
  included do
11
11
  self.file_fixture_path = RSpec.configuration.file_fixture_path
12
+ if defined?(ActiveStorage::FixtureSet)
13
+ ActiveStorage::FixtureSet.file_fixture_path = RSpec.configuration.file_fixture_path
14
+ end
12
15
  end
13
16
  end
14
17
  end
@@ -6,44 +6,33 @@ module RSpec
6
6
 
7
7
  private
8
8
 
9
- # In Rails 6.2 fixture file path needs to be relative to `file_fixture_path` instead, this change
10
- # was brought in with a deprecation warning on 6.1. In Rails 6.2 expect to rework this to remove
9
+ # In Rails 7.0 fixture file path needs to be relative to `file_fixture_path` instead, this change
10
+ # was brought in with a deprecation warning on 6.1. In Rails 7.0 expect to rework this to remove
11
11
  # the old accessor.
12
- if ::Rails.version.to_f >= 6.1
13
- def rails_fixture_file_wrapper
14
- RailsFixtureFileWrapper.file_fixture_path = nil
15
- resolved_fixture_path =
16
- if respond_to?(:file_fixture_path) && !file_fixture_path.nil?
17
- file_fixture_path.to_s
18
- else
19
- (RSpec.configuration.fixture_path || '').to_s
20
- end
21
- RailsFixtureFileWrapper.file_fixture_path = File.join(resolved_fixture_path, '') unless resolved_fixture_path.strip.empty?
22
- RailsFixtureFileWrapper.instance
23
- end
24
- else
25
- def rails_fixture_file_wrapper
26
- RailsFixtureFileWrapper.fixture_path = nil
27
- resolved_fixture_path =
28
- if respond_to?(:fixture_path) && !fixture_path.nil?
29
- fixture_path.to_s
30
- else
31
- (RSpec.configuration.fixture_path || '').to_s
32
- end
33
- RailsFixtureFileWrapper.fixture_path = File.join(resolved_fixture_path, '') unless resolved_fixture_path.strip.empty?
34
- RailsFixtureFileWrapper.instance
35
- end
12
+ def rails_fixture_file_wrapper
13
+ RailsFixtureFileWrapper.file_fixture_path = nil
14
+ resolved_fixture_path =
15
+ if respond_to?(:file_fixture_path) && !file_fixture_path.nil?
16
+ file_fixture_path.to_s
17
+ elsif respond_to?(:fixture_paths)
18
+ (RSpec.configuration.fixture_paths&.first || '').to_s
19
+ else
20
+ (RSpec.configuration.fixture_path || '').to_s
21
+ end
22
+ RailsFixtureFileWrapper.file_fixture_path = File.join(resolved_fixture_path, '') unless resolved_fixture_path.strip.empty?
23
+ RailsFixtureFileWrapper.instance
36
24
  end
37
25
 
38
26
  class RailsFixtureFileWrapper
39
27
  include ActionDispatch::TestProcess if defined?(ActionDispatch::TestProcess)
40
-
41
- if ::Rails.version.to_f >= 6.1
42
- include ActiveSupport::Testing::FileFixtures
43
- end
28
+ include ActiveSupport::Testing::FileFixtures
44
29
 
45
30
  class << self
46
- attr_accessor :fixture_path
31
+ if ::Rails::VERSION::STRING < "7.1.0"
32
+ attr_accessor :fixture_path
33
+ else
34
+ attr_accessor :fixture_paths
35
+ end
47
36
 
48
37
  # Get instance of wrapper
49
38
  def instance
@@ -10,8 +10,7 @@ module RSpec
10
10
  include ActiveRecord::TestFixtures
11
11
 
12
12
  # @private prevent ActiveSupport::TestFixtures to start a DB transaction.
13
- # Monkey patched to avoid collisions with 'let(:name)' in Rails 6.1 and after
14
- # and let(:method_name) before Rails 6.1.
13
+ # Monkey patched to avoid collisions with 'let(:name)' since Rails 6.1
15
14
  def run_in_transaction?
16
15
  current_example_name = (RSpec.current_example && RSpec.current_example.metadata[:description])
17
16
  use_transactional_tests && !self.class.uses_transaction?(current_example_name)
@@ -21,7 +20,13 @@ module RSpec
21
20
  if RSpec.configuration.use_active_record?
22
21
  include Fixtures
23
22
 
24
- self.fixture_path = RSpec.configuration.fixture_path
23
+ # TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2
24
+ if respond_to?(:fixture_paths=)
25
+ self.fixture_paths = RSpec.configuration.fixture_paths
26
+ else
27
+ self.fixture_path = RSpec.configuration.fixture_path
28
+ end
29
+
25
30
  self.use_transactional_tests = RSpec.configuration.use_transactional_fixtures
26
31
  self.use_instantiated_fixtures = RSpec.configuration.use_instantiated_fixtures
27
32
 
@@ -32,28 +37,50 @@ module RSpec
32
37
  module Fixtures
33
38
  extend ActiveSupport::Concern
34
39
 
40
+ # rubocop:disable Metrics/BlockLength
35
41
  class_methods do
36
- def fixtures(*args)
37
- orig_methods = private_instance_methods
38
- super.tap do
39
- new_methods = private_instance_methods - orig_methods
40
- new_methods.each do |method_name|
41
- proxy_method_warning_if_called_in_before_context_scope(method_name)
42
+ if ::Rails.version.to_f >= 7.1
43
+ def fixtures(*args)
44
+ super.tap do
45
+ fixture_sets.each_pair do |method_name, fixture_name|
46
+ proxy_method_warning_if_called_in_before_context_scope(method_name, fixture_name)
47
+ end
48
+ end
49
+ end
50
+
51
+ def proxy_method_warning_if_called_in_before_context_scope(method_name, fixture_name)
52
+ define_method(method_name) do |*args, **kwargs, &blk|
53
+ if RSpec.current_scope == :before_context_hook
54
+ RSpec.warn_with("Calling fixture method in before :context ")
55
+ else
56
+ access_fixture(fixture_name, *args, **kwargs, &blk)
57
+ end
58
+ end
59
+ end
60
+ else
61
+ def fixtures(*args)
62
+ orig_methods = private_instance_methods
63
+ super.tap do
64
+ new_methods = private_instance_methods - orig_methods
65
+ new_methods.each do |method_name|
66
+ proxy_method_warning_if_called_in_before_context_scope(method_name)
67
+ end
42
68
  end
43
69
  end
44
- end
45
70
 
46
- def proxy_method_warning_if_called_in_before_context_scope(method_name)
47
- orig_implementation = instance_method(method_name)
48
- define_method(method_name) do |*args, &blk|
49
- if inspect.include?("before(:context)")
50
- RSpec.warn_with("Calling fixture method in before :context ")
51
- else
52
- orig_implementation.bind(self).call(*args, &blk)
71
+ def proxy_method_warning_if_called_in_before_context_scope(method_name)
72
+ orig_implementation = instance_method(method_name)
73
+ define_method(method_name) do |*args, &blk|
74
+ if RSpec.current_scope == :before_context_hook
75
+ RSpec.warn_with("Calling fixture method in before :context ")
76
+ else
77
+ orig_implementation.bind(self).call(*args, &blk)
78
+ end
53
79
  end
54
80
  end
55
81
  end
56
82
  end
83
+ # rubocop:enable Metrics/BlockLength
57
84
  end
58
85
  end
59
86
  end
@@ -51,6 +51,10 @@ module RSpec
51
51
  exactly(:thrice)
52
52
  end
53
53
 
54
+ def description
55
+ "have broadcasted #{base_description}"
56
+ end
57
+
54
58
  def failure_message
55
59
  "expected to broadcast #{base_message}".tap do |msg|
56
60
  if @unmatching_msgs.any?
@@ -96,8 +100,11 @@ module RSpec
96
100
  private
97
101
 
98
102
  def stream
99
- @stream ||= if @target.is_a?(String)
103
+ @stream ||= case @target
104
+ when String
100
105
  @target
106
+ when Symbol
107
+ @target.to_s
101
108
  else
102
109
  check_channel_presence
103
110
  @channel.broadcasting_for(@target)
@@ -109,7 +116,7 @@ module RSpec
109
116
  decoded = ActiveSupport::JSON.decode(msg)
110
117
  decoded = decoded.with_indifferent_access if decoded.is_a?(Hash)
111
118
 
112
- if @data.nil? || @data === decoded
119
+ if @data.nil? || values_match?(@data, decoded)
113
120
  @block.call(decoded)
114
121
  true
115
122
  else
@@ -137,18 +144,21 @@ module RSpec
137
144
  end
138
145
  end
139
146
 
140
- def base_message
147
+ def base_description
141
148
  "#{message_expectation_modifier} #{@expected_number} messages to #{stream}".tap do |msg|
142
149
  msg << " with #{data_description(@data)}" unless @data.nil?
143
- msg << ", but broadcast #{@matching_msgs_count}"
144
150
  end
145
151
  end
146
152
 
153
+ def base_message
154
+ "#{base_description}, but broadcast #{@matching_msgs_count}"
155
+ end
156
+
147
157
  def data_description(data)
148
158
  if data.is_a?(RSpec::Matchers::Composable)
149
159
  data.description
150
160
  else
151
- data
161
+ data.inspect
152
162
  end
153
163
  end
154
164
 
@@ -159,7 +169,7 @@ module RSpec
159
169
  def check_channel_presence
160
170
  return if @channel.present? && @channel.respond_to?(:channel_name)
161
171
 
162
- error_msg = "Broadcasting channel can't be infered. Please, specify it with `from_channel`"
172
+ error_msg = "Broadcasting channel can't be inferred. Please, specify it with `from_channel`"
163
173
  raise ArgumentError, error_msg
164
174
  end
165
175
  end
@@ -3,6 +3,8 @@ require "rspec/rails/matchers/action_cable/have_broadcasted_to"
3
3
  module RSpec
4
4
  module Rails
5
5
  module Matchers
6
+ extend RSpec::Matchers::DSL
7
+
6
8
  # Namespace for various implementations of ActionCable features
7
9
  #
8
10
  # @api private
@@ -50,7 +52,10 @@ module RSpec
50
52
 
51
53
  ActionCable::HaveBroadcastedTo.new(target, channel: described_class)
52
54
  end
53
- alias_method :broadcast_to, :have_broadcasted_to
55
+
56
+ alias_matcher :broadcast_to, :have_broadcasted_to do |desc|
57
+ desc.gsub("have broadcasted", "broadcast")
58
+ end
54
59
 
55
60
  private
56
61