rspec-rails 6.0.3 → 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 (37) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Changelog.md +309 -181
  4. data/README.md +31 -31
  5. data/lib/generators/rspec/generator/generator_generator.rb +2 -2
  6. data/lib/generators/rspec/generator/templates/generator_spec.rb +1 -2
  7. data/lib/generators/rspec/install/templates/spec/rails_helper.rb +25 -12
  8. data/lib/generators/rspec/mailer/mailer_generator.rb +4 -2
  9. data/lib/generators/rspec/mailer/templates/preview.rb +3 -3
  10. data/lib/generators/rspec/scaffold/templates/controller_spec.rb +0 -15
  11. data/lib/generators/rspec/scaffold/templates/edit_spec.rb +3 -3
  12. data/lib/generators/rspec/scaffold/templates/index_spec.rb +1 -1
  13. data/lib/generators/rspec/scaffold/templates/new_spec.rb +1 -1
  14. data/lib/generators/rspec/scaffold/templates/request_spec.rb +0 -15
  15. data/lib/generators/rspec/scaffold/templates/show_spec.rb +1 -1
  16. data/lib/rspec/rails/configuration.rb +31 -2
  17. data/lib/rspec/rails/example/mailbox_example_group.rb +1 -1
  18. data/lib/rspec/rails/example/rails_example_group.rb +6 -1
  19. data/lib/rspec/rails/example/routing_example_group.rb +0 -2
  20. data/lib/rspec/rails/example/system_example_group.rb +55 -1
  21. data/lib/rspec/rails/example/view_example_group.rb +2 -1
  22. data/lib/rspec/rails/fixture_file_upload_support.rb +7 -1
  23. data/lib/rspec/rails/fixture_support.rb +39 -17
  24. data/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +11 -4
  25. data/lib/rspec/rails/matchers/action_cable.rb +6 -1
  26. data/lib/rspec/rails/matchers/active_job.rb +69 -8
  27. data/lib/rspec/rails/matchers/have_enqueued_mail.rb +37 -5
  28. data/lib/rspec/rails/matchers/have_http_status.rb +3 -7
  29. data/lib/rspec/rails/matchers/send_email.rb +122 -0
  30. data/lib/rspec/rails/matchers.rb +1 -0
  31. data/lib/rspec/rails/tasks/rspec.rake +3 -1
  32. data/lib/rspec/rails/version.rb +1 -1
  33. data/lib/rspec-rails.rb +28 -3
  34. data.tar.gz.sig +0 -0
  35. metadata +39 -43
  36. metadata.gz.sig +0 -0
  37. data/lib/generators/rspec/integration/integration_generator.rb +0 -29
@@ -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)
@@ -23,10 +22,11 @@ module RSpec
23
22
 
24
23
  # TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2
25
24
  if respond_to?(:fixture_paths=)
26
- fixture_paths << RSpec.configuration.fixture_path
25
+ self.fixture_paths = RSpec.configuration.fixture_paths
27
26
  else
28
27
  self.fixture_path = RSpec.configuration.fixture_path
29
28
  end
29
+
30
30
  self.use_transactional_tests = RSpec.configuration.use_transactional_fixtures
31
31
  self.use_instantiated_fixtures = RSpec.configuration.use_instantiated_fixtures
32
32
 
@@ -37,28 +37,50 @@ module RSpec
37
37
  module Fixtures
38
38
  extend ActiveSupport::Concern
39
39
 
40
+ # rubocop:disable Metrics/BlockLength
40
41
  class_methods do
41
- def fixtures(*args)
42
- orig_methods = private_instance_methods
43
- super.tap do
44
- new_methods = private_instance_methods - orig_methods
45
- new_methods.each do |method_name|
46
- 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
47
68
  end
48
69
  end
49
- end
50
70
 
51
- def proxy_method_warning_if_called_in_before_context_scope(method_name)
52
- orig_implementation = instance_method(method_name)
53
- define_method(method_name) do |*args, &blk|
54
- if RSpec.current_scope == :before_context_hook
55
- RSpec.warn_with("Calling fixture method in before :context ")
56
- else
57
- 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
58
79
  end
59
80
  end
60
81
  end
61
82
  end
83
+ # rubocop:enable Metrics/BlockLength
62
84
  end
63
85
  end
64
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?
@@ -112,7 +116,7 @@ module RSpec
112
116
  decoded = ActiveSupport::JSON.decode(msg)
113
117
  decoded = decoded.with_indifferent_access if decoded.is_a?(Hash)
114
118
 
115
- if @data.nil? || @data === decoded
119
+ if @data.nil? || values_match?(@data, decoded)
116
120
  @block.call(decoded)
117
121
  true
118
122
  else
@@ -140,18 +144,21 @@ module RSpec
140
144
  end
141
145
  end
142
146
 
143
- def base_message
147
+ def base_description
144
148
  "#{message_expectation_modifier} #{@expected_number} messages to #{stream}".tap do |msg|
145
149
  msg << " with #{data_description(@data)}" unless @data.nil?
146
- msg << ", but broadcast #{@matching_msgs_count}"
147
150
  end
148
151
  end
149
152
 
153
+ def base_message
154
+ "#{base_description}, but broadcast #{@matching_msgs_count}"
155
+ end
156
+
150
157
  def data_description(data)
151
158
  if data.is_a?(RSpec::Matchers::Composable)
152
159
  data.description
153
160
  else
154
- data
161
+ data.inspect
155
162
  end
156
163
  end
157
164
 
@@ -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
 
@@ -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
@@ -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)
@@ -157,6 +176,19 @@ 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
193
  RSpec::Rails::FeatureCheck.has_action_mailer_legacy_delivery_job? && job[:job] <= ActionMailer::DeliveryJob
162
194
  end
@@ -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
 
@@ -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")
@@ -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 = '6.0.3'
6
+ STRING = '7.1.1'
7
7
  end
8
8
  end
9
9
  end
data/lib/rspec-rails.rb CHANGED
@@ -9,6 +9,23 @@ module RSpec
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
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
27
+ end
28
+
12
29
  generators = config.app_generators
13
30
  generators.integration_tool :rspec
14
31
  generators.test_framework :rspec
@@ -47,10 +64,18 @@ module RSpec
47
64
  end
48
65
  end
49
66
 
50
- def config_default_preview_path(options)
51
- 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?
52
70
 
53
- 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
54
79
  end
55
80
 
56
81
  def supports_action_mailer_previews?(config)
data.tar.gz.sig CHANGED
Binary file