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
@@ -14,6 +14,7 @@ module RSpec
14
14
  def initialize
15
15
  @args = []
16
16
  @queue = nil
17
+ @priority = nil
17
18
  @at = nil
18
19
  @block = proc { }
19
20
  set_expected_number(:exactly, 1)
@@ -30,6 +31,11 @@ module RSpec
30
31
  self
31
32
  end
32
33
 
34
+ def at_priority(priority)
35
+ @priority = priority.to_i
36
+ self
37
+ end
38
+
33
39
  def at(time_or_date)
34
40
  case time_or_date
35
41
  when Time then @at = Time.at(time_or_date.to_f)
@@ -71,6 +77,8 @@ module RSpec
71
77
  end
72
78
 
73
79
  def failure_message
80
+ return @failure_message if defined?(@failure_message)
81
+
74
82
  "expected to #{self.class::FAILURE_MESSAGE_EXPECTATION_ACTION} #{base_message}".tap do |msg|
75
83
  if @unmatching_jobs.any?
76
84
  msg << "\nQueued jobs:"
@@ -101,7 +109,7 @@ module RSpec
101
109
 
102
110
  def check(jobs)
103
111
  @matching_jobs, @unmatching_jobs = jobs.partition do |job|
104
- if job_match?(job) && arguments_match?(job) && queue_match?(job) && at_match?(job)
112
+ if matches_constraints?(job)
105
113
  args = deserialize_arguments(job)
106
114
  @block.call(*args)
107
115
  true
@@ -109,6 +117,12 @@ module RSpec
109
117
  false
110
118
  end
111
119
  end
120
+
121
+ if (signature_mismatch = detect_args_signature_mismatch(@matching_jobs))
122
+ @failure_message = signature_mismatch
123
+ return false
124
+ end
125
+
112
126
  @matching_jobs_count = @matching_jobs.size
113
127
 
114
128
  case @expectation_type
@@ -123,6 +137,7 @@ module RSpec
123
137
  msg << " with #{@args}," if @args.any?
124
138
  msg << " on queue #{@queue}," if @queue
125
139
  msg << " at #{@at.inspect}," if @at
140
+ msg << " with priority #{@priority}," if @priority
126
141
  msg << " but #{self.class::MESSAGE_EXPECTATION_ACTION} #{@matching_jobs_count}"
127
142
  end
128
143
  end
@@ -132,13 +147,23 @@ module RSpec
132
147
  msg_parts << "with #{deserialize_arguments(job)}" if job[:args].any?
133
148
  msg_parts << "on queue #{job[:queue]}" if job[:queue]
134
149
  msg_parts << "at #{Time.at(job[:at])}" if job[:at]
150
+ msg_parts <<
151
+ if job[:priority]
152
+ "with priority #{job[:priority]}"
153
+ else
154
+ "with no priority specified"
155
+ end
135
156
 
136
157
  "#{job[:job].name} job".tap do |msg|
137
158
  msg << " #{msg_parts.join(', ')}" if msg_parts.any?
138
159
  end
139
160
  end
140
161
 
141
- def job_match?(job)
162
+ def matches_constraints?(job)
163
+ job_matches?(job) && arguments_match?(job) && queue_match?(job) && at_match?(job) && priority_match?(job)
164
+ end
165
+
166
+ def job_matches?(job)
142
167
  @job ? @job == job[:job] : true
143
168
  end
144
169
 
@@ -152,12 +177,48 @@ module RSpec
152
177
  end
153
178
  end
154
179
 
180
+ def detect_args_signature_mismatch(jobs)
181
+ return if skip_signature_verification?
182
+
183
+ jobs.each do |job|
184
+ args = deserialize_arguments(job)
185
+
186
+ if (signature_mismatch = check_args_signature_mismatch(job.fetch(:job), :perform, args))
187
+ return signature_mismatch
188
+ end
189
+ end
190
+
191
+ nil
192
+ end
193
+
194
+ def skip_signature_verification?
195
+ return true unless defined?(::RSpec::Mocks) && (::RSpec::Mocks.respond_to?(:configuration))
196
+
197
+ !RSpec::Mocks.configuration.verify_partial_doubles? ||
198
+ RSpec::Mocks.configuration.temporarily_suppress_partial_double_verification
199
+ end
200
+
201
+ def check_args_signature_mismatch(job_class, job_method, args)
202
+ signature = Support::MethodSignature.new(job_class.public_instance_method(job_method))
203
+ verifier = Support::StrictSignatureVerifier.new(signature, args)
204
+
205
+ unless verifier.valid?
206
+ "Incorrect arguments passed to #{job_class.name}: #{verifier.error_message}"
207
+ end
208
+ end
209
+
155
210
  def queue_match?(job)
156
211
  return true unless @queue
157
212
 
158
213
  @queue == job[:queue]
159
214
  end
160
215
 
216
+ def priority_match?(job)
217
+ return true unless @priority
218
+
219
+ @priority == job[:priority]
220
+ end
221
+
161
222
  def at_match?(job)
162
223
  return true unless @at
163
224
  return job[:at].nil? if @at == :no_wait
@@ -181,7 +242,7 @@ module RSpec
181
242
  |`Time.current.change(usec: 0)`
182
243
  |
183
244
  |Note: RSpec cannot do this for you because jobs can be scheduled with usec
184
- |precision and we do not know wether it is on purpose or not.
245
+ |precision and we do not know whether it is on purpose or not.
185
246
  |
186
247
  |
187
248
  WARNING
@@ -230,11 +291,11 @@ module RSpec
230
291
  def matches?(proc)
231
292
  raise ArgumentError, "have_enqueued_job and enqueue_job only support block expectations" unless Proc === proc
232
293
 
233
- original_enqueued_jobs_count = queue_adapter.enqueued_jobs.count
294
+ original_enqueued_jobs = Set.new(queue_adapter.enqueued_jobs)
234
295
  proc.call
235
- in_block_jobs = queue_adapter.enqueued_jobs.drop(original_enqueued_jobs_count)
296
+ enqueued_jobs = Set.new(queue_adapter.enqueued_jobs)
236
297
 
237
- check(in_block_jobs)
298
+ check(enqueued_jobs - original_enqueued_jobs)
238
299
  end
239
300
 
240
301
  def does_not_match?(proc)
@@ -384,33 +445,33 @@ module RSpec
384
445
  #
385
446
  # @example
386
447
  # expect {
387
- # perform_jobs { HeavyLiftingJob.perform_later }
448
+ # perform_enqueued_jobs { HeavyLiftingJob.perform_later }
388
449
  # }.to have_performed_job
389
450
  #
390
451
  # expect {
391
- # perform_jobs {
452
+ # perform_enqueued_jobs {
392
453
  # HelloJob.perform_later
393
454
  # HeavyLiftingJob.perform_later
394
455
  # }
395
456
  # }.to have_performed_job(HelloJob).exactly(:once)
396
457
  #
397
458
  # expect {
398
- # perform_jobs { 3.times { HelloJob.perform_later } }
459
+ # perform_enqueued_jobs { 3.times { HelloJob.perform_later } }
399
460
  # }.to have_performed_job(HelloJob).at_least(2).times
400
461
  #
401
462
  # expect {
402
- # perform_jobs { HelloJob.perform_later }
463
+ # perform_enqueued_jobs { HelloJob.perform_later }
403
464
  # }.to have_performed_job(HelloJob).at_most(:twice)
404
465
  #
405
466
  # expect {
406
- # perform_jobs {
467
+ # perform_enqueued_jobs {
407
468
  # HelloJob.perform_later
408
469
  # HeavyLiftingJob.perform_later
409
470
  # }
410
471
  # }.to have_performed_job(HelloJob).and have_performed_job(HeavyLiftingJob)
411
472
  #
412
473
  # expect {
413
- # perform_jobs {
474
+ # perform_enqueued_jobs {
414
475
  # HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42)
415
476
  # }
416
477
  # }.to have_performed_job.with(42).on_queue("low").at(Date.tomorrow.noon)
@@ -41,6 +41,8 @@ module RSpec
41
41
  end
42
42
 
43
43
  def failure_message
44
+ return @failure_message if defined?(@failure_message)
45
+
44
46
  "expected to enqueue #{base_message}".tap do |msg|
45
47
  msg << "\n#{unmatching_mail_jobs_message}" if unmatching_mail_jobs.any?
46
48
  end
@@ -70,7 +72,7 @@ module RSpec
70
72
  @mailer_class ? @mailer_class.name : 'ActionMailer::Base'
71
73
  end
72
74
 
73
- def job_match?(job)
75
+ def job_matches?(job)
74
76
  legacy_mail?(job) || parameterized_mail?(job) || unified_mail?(job)
75
77
  end
76
78
 
@@ -89,6 +91,23 @@ module RSpec
89
91
  super(job)
90
92
  end
91
93
 
94
+ def detect_args_signature_mismatch(jobs)
95
+ return if @method_name.nil?
96
+ return if skip_signature_verification?
97
+
98
+ mailer_class = mailer_class_name.constantize
99
+
100
+ jobs.each do |job|
101
+ mailer_args = extract_args_without_parameterized_params(job)
102
+
103
+ if (signature_mismatch = check_args_signature_mismatch(mailer_class, @method_name, mailer_args))
104
+ return signature_mismatch
105
+ end
106
+ end
107
+
108
+ nil
109
+ end
110
+
92
111
  def base_mailer_args
93
112
  [mailer_class_name, @method_name.to_s, MAILER_JOB_METHOD]
94
113
  end
@@ -105,18 +124,18 @@ module RSpec
105
124
 
106
125
  def unmatching_mail_jobs
107
126
  @unmatching_jobs.select do |job|
108
- job_match?(job)
127
+ job_matches?(job)
109
128
  end
110
129
  end
111
130
 
112
131
  def unmatching_mail_jobs_message
113
- msg = "Queued deliveries:"
132
+ messages = ["Queued deliveries:"]
114
133
 
115
134
  unmatching_mail_jobs.each do |job|
116
- msg << "\n #{mail_job_message(job)}"
135
+ messages << " #{mail_job_message(job)}"
117
136
  end
118
137
 
119
- msg
138
+ messages.join("\n")
120
139
  end
121
140
 
122
141
  def mail_job_message(job)
@@ -134,7 +153,7 @@ module RSpec
134
153
  end
135
154
 
136
155
  # Ruby 3.1 changed how params were serialized on Rails 6.1
137
- # so we override the active job implementation and customise it here.
156
+ # so we override the active job implementation and customize it here.
138
157
  def deserialize_arguments(job)
139
158
  args = super
140
159
 
@@ -157,8 +176,21 @@ module RSpec
157
176
  end
158
177
  end
159
178
 
179
+ def extract_args_without_parameterized_params(job)
180
+ args = deserialize_arguments(job)
181
+ mailer_args = args - base_mailer_args
182
+
183
+ if parameterized_mail?(job)
184
+ mailer_args = mailer_args[1..-1] # ignore parameterized params
185
+ elsif mailer_args.last.is_a?(Hash) && mailer_args.last.key?(:args)
186
+ mailer_args = args.last[:args]
187
+ end
188
+
189
+ mailer_args
190
+ end
191
+
160
192
  def legacy_mail?(job)
161
- job[:job] <= ActionMailer::DeliveryJob
193
+ RSpec::Rails::FeatureCheck.has_action_mailer_legacy_delivery_job? && job[:job] <= ActionMailer::DeliveryJob
162
194
  end
163
195
 
164
196
  def parameterized_mail?(job)
@@ -169,6 +201,7 @@ module RSpec
169
201
  RSpec::Rails::FeatureCheck.has_action_mailer_unified_delivery? && job[:job] <= ActionMailer::MailDeliveryJob
170
202
  end
171
203
  end
204
+
172
205
  # @api public
173
206
  # Passes if an email has been enqueued inside block.
174
207
  # May chain with to specify expected arguments.
@@ -33,7 +33,7 @@ module RSpec
33
33
  # @param obj [Object] object to convert to a response
34
34
  # @return [ActionDispatch::TestResponse]
35
35
  def as_test_response(obj)
36
- if ::ActionDispatch::Response === obj
36
+ if ::ActionDispatch::Response === obj || ::Rack::MockResponse === obj
37
37
  ::ActionDispatch::TestResponse.from_response(obj)
38
38
  elsif ::ActionDispatch::TestResponse === obj
39
39
  obj
@@ -216,11 +216,7 @@ module RSpec
216
216
  # @see Rack::Utils::SYMBOL_TO_STATUS_CODE
217
217
  # @raise [ArgumentError] if an associated code could not be found
218
218
  def set_expected_code!
219
- @expected ||=
220
- Rack::Utils::SYMBOL_TO_STATUS_CODE.fetch(expected_status) do
221
- raise ArgumentError,
222
- "Invalid HTTP status: #{expected_status.inspect}"
223
- end
219
+ @expected ||= Rack::Utils.status_code(expected_status)
224
220
  end
225
221
  end
226
222
 
@@ -237,7 +233,7 @@ module RSpec
237
233
  # expect(response).to have_http_status(:redirect)
238
234
  #
239
235
  # @see RSpec::Rails::Matchers#have_http_status
240
- # @see https://github.com/rails/rails/blob/6-0-stable/actionpack/lib/action_dispatch/testing/test_response.rb `ActionDispatch::TestResponse`
236
+ # @see https://github.com/rails/rails/blob/7-2-stable/actionpack/lib/action_dispatch/testing/test_response.rb `ActionDispatch::TestResponse`
241
237
  class GenericStatus < RSpec::Rails::Matchers::BaseMatcher
242
238
  include HaveHttpStatus
243
239
 
@@ -305,7 +301,7 @@ module RSpec
305
301
 
306
302
  private
307
303
 
308
- # @return [String] formating the expected status and associated code(s)
304
+ # @return [String] formatting the expected status and associated code(s)
309
305
  def type_message
310
306
  @type_message ||= (expected == :error ? "an error" : "a #{expected}") +
311
307
  " status code (#{type_codes})"
@@ -26,7 +26,7 @@ module RSpec
26
26
  path, query = *verb_to_path_map.values.first.split('?')
27
27
  @scope.assert_recognizes(
28
28
  @expected,
29
- {method: verb_to_path_map.keys.first, path: path},
29
+ { method: verb_to_path_map.keys.first, path: path },
30
30
  Rack::Utils.parse_nested_query(query)
31
31
  )
32
32
  end
@@ -115,7 +115,7 @@ module RSpec
115
115
  # Shorthand method for matching this type of route.
116
116
  %w[get post put patch delete options head].each do |method|
117
117
  define_method method do |path|
118
- {method.to_sym => path}
118
+ { method.to_sym => path }
119
119
  end
120
120
  end
121
121
  end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpec
4
+ module Rails
5
+ module Matchers
6
+ # @api private
7
+ #
8
+ # Matcher class for `send_email`. Should not be instantiated directly.
9
+ #
10
+ # @see RSpec::Rails::Matchers#send_email
11
+ class SendEmail < RSpec::Rails::Matchers::BaseMatcher
12
+ # @api private
13
+ # Define the email attributes that should be included in the inspection output.
14
+ INSPECT_EMAIL_ATTRIBUTES = %i[subject from to cc bcc].freeze
15
+
16
+ def initialize(criteria)
17
+ @criteria = criteria
18
+ end
19
+
20
+ # @api private
21
+ def supports_value_expectations?
22
+ false
23
+ end
24
+
25
+ # @api private
26
+ def supports_block_expectations?
27
+ true
28
+ end
29
+
30
+ def matches?(block)
31
+ define_matched_emails(block)
32
+
33
+ @matched_emails.one?
34
+ end
35
+
36
+ # @api private
37
+ # @return [String]
38
+ def failure_message
39
+ result =
40
+ if multiple_match?
41
+ "More than 1 matching emails were sent."
42
+ else
43
+ "No matching emails were sent."
44
+ end
45
+ "#{result}#{sent_emails_message}"
46
+ end
47
+
48
+ # @api private
49
+ # @return [String]
50
+ def failure_message_when_negated
51
+ "Expected not to send an email but it was sent."
52
+ end
53
+
54
+ private
55
+
56
+ def diffable?
57
+ true
58
+ end
59
+
60
+ def deliveries
61
+ ActionMailer::Base.deliveries
62
+ end
63
+
64
+ def define_matched_emails(block)
65
+ before = deliveries.dup
66
+
67
+ block.call
68
+
69
+ after = deliveries
70
+
71
+ @diff = after - before
72
+ @matched_emails = @diff.select(&method(:matched_email?))
73
+ end
74
+
75
+ def matched_email?(email)
76
+ @criteria.all? do |attr, value|
77
+ expected =
78
+ case attr
79
+ when :to, :from, :cc, :bcc then Array(value)
80
+ else
81
+ value
82
+ end
83
+
84
+ values_match?(expected, email.public_send(attr))
85
+ end
86
+ end
87
+
88
+ def multiple_match?
89
+ @matched_emails.many?
90
+ end
91
+
92
+ def sent_emails_message
93
+ if @diff.empty?
94
+ "\n\nThere were no any emails sent inside the expectation block."
95
+ else
96
+ sent_emails =
97
+ @diff.map do |email|
98
+ inspected = INSPECT_EMAIL_ATTRIBUTES.map { |attr| "#{attr}: #{email.public_send(attr)}" }.join(", ")
99
+ "- #{inspected}"
100
+ end.join("\n")
101
+ "\n\nThe following emails were sent:\n#{sent_emails}"
102
+ end
103
+ end
104
+ end
105
+
106
+ # @api public
107
+ # Check email sending with specific parameters.
108
+ #
109
+ # @example Positive expectation
110
+ # expect { action }.to send_email
111
+ #
112
+ # @example Negative expectations
113
+ # expect { action }.not_to send_email
114
+ #
115
+ # @example More precise expectation with attributes to match
116
+ # expect { action }.to send_email(to: 'test@example.com', subject: 'Confirm email')
117
+ def send_email(criteria = {})
118
+ SendEmail.new(criteria)
119
+ end
120
+ end
121
+ end
122
+ end
@@ -20,6 +20,7 @@ require 'rspec/rails/matchers/be_a_new'
20
20
  require 'rspec/rails/matchers/relation_match_array'
21
21
  require 'rspec/rails/matchers/be_valid'
22
22
  require 'rspec/rails/matchers/have_http_status'
23
+ require 'rspec/rails/matchers/send_email'
23
24
 
24
25
  if RSpec::Rails::FeatureCheck.has_active_job?
25
26
  require 'rspec/rails/matchers/active_job'
@@ -5,7 +5,9 @@ end
5
5
 
6
6
  task default: :spec
7
7
 
8
- task stats: "spec:statsetup"
8
+ if ::Rails::VERSION::STRING < "8.0.0"
9
+ task stats: "spec:statsetup"
10
+ end
9
11
 
10
12
  desc "Run all specs in spec directory (excluding plugin specs)"
11
13
  RSpec::Core::RakeTask.new(spec: "spec:prepare")
@@ -12,9 +12,7 @@ if defined?(Capybara)
12
12
  RSpec.configure do |c|
13
13
  if defined?(Capybara::DSL)
14
14
  c.include Capybara::DSL, type: :feature
15
- if defined?(ActionPack) && ActionPack::VERSION::STRING >= "5.1"
16
- c.include Capybara::DSL, type: :system
17
- end
15
+ c.include Capybara::DSL, type: :system
18
16
  end
19
17
 
20
18
  if defined?(Capybara::RSpecMatchers)
@@ -3,7 +3,7 @@ module RSpec
3
3
  # Version information for RSpec Rails.
4
4
  module Version
5
5
  # Current version of RSpec Rails, in semantic versioning format.
6
- STRING = '5.1.2'
6
+ STRING = '7.1.1'
7
7
  end
8
8
  end
9
9
  end
@@ -13,26 +13,8 @@ module RSpec
13
13
  end
14
14
 
15
15
  # Compat-shim for AbstractController::Rendering#view_assigns
16
- #
17
- # _assigns was deprecated in favor of view_assigns after
18
- # Rails-3.0.0 was released. Since we are not able to predict when
19
- # the _assigns/view_assigns patch will be released (I thought it
20
- # would have been in 3.0.1, but 3.0.1 bypassed this change for a
21
- # security fix), this bit ensures that we do the right thing without
22
- # knowing anything about the Rails version we are dealing with.
23
- #
24
- # Once that change _is_ released, this can be changed to something
25
- # that checks for the Rails version when the module is being
26
- # interpreted, as it was before commit dd0095.
27
16
  def view_assigns
28
17
  super.merge(_encapsulated_assigns)
29
- rescue
30
- _assigns
31
- end
32
-
33
- # @private
34
- def _assigns
35
- super.merge(_encapsulated_assigns)
36
18
  end
37
19
 
38
20
  private
@@ -62,14 +62,8 @@ module RSpec
62
62
  end
63
63
  end
64
64
 
65
- if ::Rails::VERSION::STRING >= '6'
66
- def self.template_format(template)
67
- template.format
68
- end
69
- else
70
- def self.template_format(template)
71
- template.formats
72
- end
65
+ def self.template_format(template)
66
+ template.format
73
67
  end
74
68
 
75
69
  # Delegates all methods to the submitted resolver and for all methods
@@ -77,7 +71,15 @@ module RSpec
77
71
  # templates with modified source
78
72
  #
79
73
  # @private
80
- class ResolverDecorator
74
+ class ResolverDecorator < ::ActionView::Resolver
75
+ (::ActionView::Resolver.instance_methods - Object.instance_methods).each do |method|
76
+ undef_method method
77
+ end
78
+
79
+ (::ActionView::Resolver.methods - Object.methods).each do |method|
80
+ singleton_class.undef_method method
81
+ end
82
+
81
83
  def initialize(resolver)
82
84
  @resolver = resolver
83
85
  end
@@ -125,11 +127,11 @@ module RSpec
125
127
  # @private
126
128
  module EmptyTemplates
127
129
  def prepend_view_path(new_path)
128
- lookup_context.view_paths.unshift(*_path_decorator(*new_path))
130
+ super(_path_decorator(*new_path))
129
131
  end
130
132
 
131
133
  def append_view_path(new_path)
132
- lookup_context.view_paths.push(*_path_decorator(*new_path))
134
+ super(_path_decorator(*new_path))
133
135
  end
134
136
 
135
137
  private
data/lib/rspec-rails.rb CHANGED
@@ -8,11 +8,24 @@ module RSpec
8
8
  class Railtie < ::Rails::Railtie
9
9
  # As of Rails 5.1.0 you can register directories to work with `rake notes`
10
10
  require 'rails/source_annotation_extractor'
11
- if ::Rails::VERSION::STRING >= '6.0'
12
- ::Rails::SourceAnnotationExtractor::Annotation.register_directories("spec")
13
- else
14
- SourceAnnotationExtractor::Annotation.register_directories("spec")
11
+ ::Rails::SourceAnnotationExtractor::Annotation.register_directories("spec")
12
+
13
+ # As of Rails 8.0.0 you can register directories to work with `rails stats`
14
+ if ::Rails::VERSION::STRING >= "8.0.0"
15
+ require 'rails/code_statistics'
16
+
17
+ dirs = Dir['./spec/**/*_spec.rb']
18
+ .map { |f| f.sub(/^\.\/(spec\/\w+)\/.*/, '\\1') }
19
+ .uniq
20
+ .select { |f| File.directory?(f) }
21
+
22
+ Hash[dirs.map { |d| [d.split('/').last, d] }].each do |type, dir|
23
+ name = type.singularize.capitalize
24
+
25
+ ::Rails::CodeStatistics.register_directory "#{name} specs", dir, test_directory: true
26
+ end
15
27
  end
28
+
16
29
  generators = config.app_generators
17
30
  generators.integration_tool :rspec
18
31
  generators.test_framework :rspec
@@ -51,10 +64,18 @@ module RSpec
51
64
  end
52
65
  end
53
66
 
54
- def config_default_preview_path(options)
55
- return unless options.preview_path.blank?
67
+ if ::Rails::VERSION::STRING >= "7.1.0"
68
+ def config_default_preview_path(options)
69
+ return unless options.preview_paths.empty?
56
70
 
57
- options.preview_path = "#{::Rails.root}/spec/mailers/previews"
71
+ options.preview_paths << "#{::Rails.root}/spec/mailers/previews"
72
+ end
73
+ else
74
+ def config_default_preview_path(options)
75
+ return unless options.preview_path.blank?
76
+
77
+ options.preview_path = "#{::Rails.root}/spec/mailers/previews"
78
+ end
58
79
  end
59
80
 
60
81
  def supports_action_mailer_previews?(config)
data.tar.gz.sig CHANGED
Binary file