rspec-rails 3.9.0 → 4.0.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 (73) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Capybara.md +5 -54
  4. data/Changelog.md +156 -78
  5. data/README.md +8 -7
  6. data/lib/generators/rspec/channel/channel_generator.rb +12 -0
  7. data/lib/generators/rspec/{observer/templates/observer_spec.rb → channel/templates/channel_spec.rb.erb} +1 -1
  8. data/lib/generators/rspec/controller/controller_generator.rb +21 -4
  9. data/lib/generators/rspec/controller/templates/request_spec.rb +14 -0
  10. data/lib/generators/rspec/controller/templates/routing_spec.rb +13 -0
  11. data/lib/generators/rspec/feature/feature_generator.rb +2 -2
  12. data/lib/generators/rspec/{generators → generator}/generator_generator.rb +2 -2
  13. data/lib/generators/rspec/{generators → generator}/templates/generator_spec.rb +0 -0
  14. data/lib/generators/rspec/helper/helper_generator.rb +1 -1
  15. data/lib/generators/rspec/install/install_generator.rb +4 -4
  16. data/lib/generators/rspec/install/templates/spec/rails_helper.rb +17 -16
  17. data/lib/generators/rspec/integration/integration_generator.rb +3 -3
  18. data/lib/generators/rspec/mailbox/mailbox_generator.rb +14 -0
  19. data/lib/generators/rspec/mailbox/templates/mailbox_spec.rb.erb +7 -0
  20. data/lib/generators/rspec/mailer/mailer_generator.rb +2 -1
  21. data/lib/generators/rspec/model/model_generator.rb +5 -4
  22. data/lib/generators/rspec/model/templates/fixtures.yml +1 -1
  23. data/lib/generators/rspec/request/request_generator.rb +1 -1
  24. data/lib/generators/rspec/scaffold/scaffold_generator.rb +29 -19
  25. data/lib/generators/rspec/scaffold/templates/api_controller_spec.rb +0 -36
  26. data/lib/generators/rspec/scaffold/templates/api_request_spec.rb +131 -0
  27. data/lib/generators/rspec/scaffold/templates/controller_spec.rb +10 -10
  28. data/lib/generators/rspec/scaffold/templates/edit_spec.rb +1 -1
  29. data/lib/generators/rspec/scaffold/templates/index_spec.rb +2 -2
  30. data/lib/generators/rspec/scaffold/templates/new_spec.rb +1 -1
  31. data/lib/generators/rspec/scaffold/templates/request_spec.rb +133 -0
  32. data/lib/generators/rspec/scaffold/templates/routing_spec.rb +8 -10
  33. data/lib/generators/rspec/scaffold/templates/show_spec.rb +1 -1
  34. data/lib/generators/rspec/system/system_generator.rb +1 -1
  35. data/lib/generators/rspec/view/view_generator.rb +2 -2
  36. data/lib/generators/rspec.rb +0 -6
  37. data/lib/rspec/rails/adapters.rb +11 -76
  38. data/lib/rspec/rails/configuration.rb +43 -33
  39. data/lib/rspec/rails/example/channel_example_group.rb +93 -0
  40. data/lib/rspec/rails/example/controller_example_group.rb +4 -4
  41. data/lib/rspec/rails/example/feature_example_group.rb +6 -26
  42. data/lib/rspec/rails/example/helper_example_group.rb +2 -9
  43. data/lib/rspec/rails/example/mailbox_example_group.rb +80 -0
  44. data/lib/rspec/rails/example/mailer_example_group.rb +2 -2
  45. data/lib/rspec/rails/example/rails_example_group.rb +1 -1
  46. data/lib/rspec/rails/example/system_example_group.rb +26 -10
  47. data/lib/rspec/rails/example/view_example_group.rb +38 -27
  48. data/lib/rspec/rails/example.rb +2 -0
  49. data/lib/rspec/rails/extensions/active_record/proxy.rb +1 -9
  50. data/lib/rspec/rails/feature_check.rb +12 -29
  51. data/lib/rspec/rails/fixture_file_upload_support.rb +1 -1
  52. data/lib/rspec/rails/fixture_support.rb +37 -31
  53. data/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +170 -0
  54. data/lib/rspec/rails/matchers/action_cable/have_streams.rb +58 -0
  55. data/lib/rspec/rails/matchers/action_cable.rb +65 -0
  56. data/lib/rspec/rails/matchers/action_mailbox.rb +64 -0
  57. data/lib/rspec/rails/matchers/active_job.rb +148 -22
  58. data/lib/rspec/rails/matchers/base_matcher.rb +5 -10
  59. data/lib/rspec/rails/matchers/have_enqueued_mail.rb +52 -28
  60. data/lib/rspec/rails/matchers/have_http_status.rb +11 -7
  61. data/lib/rspec/rails/matchers/have_rendered.rb +1 -0
  62. data/lib/rspec/rails/matchers/routing_matchers.rb +12 -12
  63. data/lib/rspec/rails/matchers.rb +10 -0
  64. data/lib/rspec/rails/tasks/rspec.rake +7 -17
  65. data/lib/rspec/rails/vendor/capybara.rb +10 -15
  66. data/lib/rspec/rails/version.rb +1 -1
  67. data/lib/rspec/rails/view_path_builder.rb +1 -1
  68. data/lib/rspec/rails/view_rendering.rb +15 -4
  69. data/lib/rspec-rails.rb +8 -9
  70. data.tar.gz.sig +0 -0
  71. metadata +46 -34
  72. metadata.gz.sig +0 -0
  73. data/lib/generators/rspec/observer/observer_generator.rb +0 -13
@@ -8,14 +8,14 @@ module RSpec
8
8
  #
9
9
  # @api private
10
10
  module ActiveJob
11
- # rubocop: disable Style/ClassLength
11
+ # rubocop: disable Metrics/ClassLength
12
12
  # @private
13
13
  class Base < RSpec::Rails::Matchers::BaseMatcher
14
14
  def initialize
15
15
  @args = []
16
16
  @queue = nil
17
17
  @at = nil
18
- @block = Proc.new {}
18
+ @block = proc { }
19
19
  set_expected_number(:exactly, 1)
20
20
  end
21
21
 
@@ -26,12 +26,16 @@ module RSpec
26
26
  end
27
27
 
28
28
  def on_queue(queue)
29
- @queue = queue
29
+ @queue = queue.to_s
30
30
  self
31
31
  end
32
32
 
33
- def at(date)
34
- @at = date
33
+ def at(time_or_date)
34
+ case time_or_date
35
+ when Time then @at = Time.at(time_or_date.to_f)
36
+ else
37
+ @at = time_or_date
38
+ end
35
39
  self
36
40
  end
37
41
 
@@ -67,7 +71,7 @@ module RSpec
67
71
  end
68
72
 
69
73
  def failure_message
70
- "expected to enqueue #{base_message}".tap do |msg|
74
+ "expected to #{self.class::FAILURE_MESSAGE_EXPECTATION_ACTION} #{base_message}".tap do |msg|
71
75
  if @unmatching_jobs.any?
72
76
  msg << "\nQueued jobs:"
73
77
  @unmatching_jobs.each do |job|
@@ -78,7 +82,7 @@ module RSpec
78
82
  end
79
83
 
80
84
  def failure_message_when_negated
81
- "expected not to enqueue #{base_message}"
85
+ "expected not to #{self.class::FAILURE_MESSAGE_EXPECTATION_ACTION} #{base_message}"
82
86
  end
83
87
 
84
88
  def message_expectation_modifier
@@ -97,7 +101,7 @@ module RSpec
97
101
 
98
102
  def check(jobs)
99
103
  @matching_jobs, @unmatching_jobs = jobs.partition do |job|
100
- if arguments_match?(job) && other_attributes_match?(job)
104
+ if job_match?(job) && arguments_match?(job) && queue_match?(job) && at_match?(job)
101
105
  args = deserialize_arguments(job)
102
106
  @block.call(*args)
103
107
  true
@@ -119,7 +123,7 @@ module RSpec
119
123
  msg << " with #{@args}," if @args.any?
120
124
  msg << " on queue #{@queue}," if @queue
121
125
  msg << " at #{@at.inspect}," if @at
122
- msg << " but enqueued #{@matching_jobs_count}"
126
+ msg << " but #{self.class::MESSAGE_EXPECTATION_ACTION} #{@matching_jobs_count}"
123
127
  end
124
128
  end
125
129
 
@@ -134,29 +138,32 @@ module RSpec
134
138
  end
135
139
  end
136
140
 
141
+ def job_match?(job)
142
+ @job ? @job == job[:job] : true
143
+ end
144
+
137
145
  def arguments_match?(job)
138
146
  if @args.any?
147
+ args = serialize_and_deserialize_arguments(@args)
139
148
  deserialized_args = deserialize_arguments(job)
140
- RSpec::Mocks::ArgumentListMatcher.new(*@args).args_match?(*deserialized_args)
149
+ RSpec::Mocks::ArgumentListMatcher.new(*args).args_match?(*deserialized_args)
141
150
  else
142
151
  true
143
152
  end
144
153
  end
145
154
 
146
- def other_attributes_match?(job)
147
- serialized_attributes.all? { |key, value| value == job[key] }
148
- end
155
+ def queue_match?(job)
156
+ return true unless @queue
149
157
 
150
- def serialized_attributes
151
- {}.tap do |attributes|
152
- attributes[:at] = serialized_at if @at
153
- attributes[:queue] = @queue if @queue
154
- attributes[:job] = @job if @job
155
- end
158
+ @queue == job[:queue]
156
159
  end
157
160
 
158
- def serialized_at
159
- @at == :no_wait ? nil : @at.to_f
161
+ def at_match?(job)
162
+ return true unless @at
163
+ return job[:at].nil? if @at == :no_wait
164
+ return false unless job[:at]
165
+
166
+ values_match?(@at, Time.at(job[:at]))
160
167
  end
161
168
 
162
169
  def set_expected_number(relativity, count)
@@ -169,6 +176,13 @@ module RSpec
169
176
  end
170
177
  end
171
178
 
179
+ def serialize_and_deserialize_arguments(args)
180
+ serialized = ::ActiveJob::Arguments.serialize(args)
181
+ ::ActiveJob::Arguments.deserialize(serialized)
182
+ rescue ::ActiveJob::SerializationError
183
+ args
184
+ end
185
+
172
186
  def deserialize_arguments(job)
173
187
  ::ActiveJob::Arguments.deserialize(job[:args])
174
188
  rescue ::ActiveJob::DeserializationError
@@ -179,10 +193,13 @@ module RSpec
179
193
  ::ActiveJob::Base.queue_adapter
180
194
  end
181
195
  end
182
- # rubocop: enable Style/ClassLength
196
+ # rubocop: enable Metrics/ClassLength
183
197
 
184
198
  # @private
185
199
  class HaveEnqueuedJob < Base
200
+ FAILURE_MESSAGE_EXPECTATION_ACTION = 'enqueue'.freeze
201
+ MESSAGE_EXPECTATION_ACTION = 'enqueued'.freeze
202
+
186
203
  def initialize(job)
187
204
  super()
188
205
  @job = job
@@ -207,6 +224,9 @@ module RSpec
207
224
 
208
225
  # @private
209
226
  class HaveBeenEnqueued < Base
227
+ FAILURE_MESSAGE_EXPECTATION_ACTION = 'enqueue'.freeze
228
+ MESSAGE_EXPECTATION_ACTION = 'enqueued'.freeze
229
+
210
230
  def matches?(job)
211
231
  @job = job
212
232
  check(queue_adapter.enqueued_jobs)
@@ -218,6 +238,38 @@ module RSpec
218
238
  !matches?(proc)
219
239
  end
220
240
  end
241
+
242
+ # @private
243
+ class HavePerformedJob < Base
244
+ FAILURE_MESSAGE_EXPECTATION_ACTION = 'perform'.freeze
245
+ MESSAGE_EXPECTATION_ACTION = 'performed'.freeze
246
+
247
+ def initialize(job)
248
+ super()
249
+ @job = job
250
+ end
251
+
252
+ def matches?(proc)
253
+ raise ArgumentError, "have_performed_job only supports block expectations" unless Proc === proc
254
+
255
+ original_performed_jobs_count = queue_adapter.performed_jobs.count
256
+ proc.call
257
+ in_block_jobs = queue_adapter.performed_jobs.drop(original_performed_jobs_count)
258
+
259
+ check(in_block_jobs)
260
+ end
261
+ end
262
+
263
+ # @private
264
+ class HaveBeenPerformed < Base
265
+ FAILURE_MESSAGE_EXPECTATION_ACTION = 'perform'.freeze
266
+ MESSAGE_EXPECTATION_ACTION = 'performed'.freeze
267
+
268
+ def matches?(job)
269
+ @job = job
270
+ check(queue_adapter.performed_jobs)
271
+ end
272
+ end
221
273
  end
222
274
 
223
275
  # @api public
@@ -305,11 +357,85 @@ module RSpec
305
357
  ActiveJob::HaveBeenEnqueued.new
306
358
  end
307
359
 
360
+ # @api public
361
+ # Passes if a job has been performed inside block. May chain at_least, at_most or exactly to specify a number of times.
362
+ #
363
+ # @example
364
+ # expect {
365
+ # perform_jobs { HeavyLiftingJob.perform_later }
366
+ # }.to have_performed_job
367
+ #
368
+ # expect {
369
+ # perform_jobs {
370
+ # HelloJob.perform_later
371
+ # HeavyLiftingJob.perform_later
372
+ # }
373
+ # }.to have_performed_job(HelloJob).exactly(:once)
374
+ #
375
+ # expect {
376
+ # perform_jobs { 3.times { HelloJob.perform_later } }
377
+ # }.to have_performed_job(HelloJob).at_least(2).times
378
+ #
379
+ # expect {
380
+ # perform_jobs { HelloJob.perform_later }
381
+ # }.to have_performed_job(HelloJob).at_most(:twice)
382
+ #
383
+ # expect {
384
+ # perform_jobs {
385
+ # HelloJob.perform_later
386
+ # HeavyLiftingJob.perform_later
387
+ # }
388
+ # }.to have_performed_job(HelloJob).and have_performed_job(HeavyLiftingJob)
389
+ #
390
+ # expect {
391
+ # perform_jobs {
392
+ # HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42)
393
+ # }
394
+ # }.to have_performed_job.with(42).on_queue("low").at(Date.tomorrow.noon)
395
+ def have_performed_job(job = nil)
396
+ check_active_job_adapter
397
+ ActiveJob::HavePerformedJob.new(job)
398
+ end
399
+ alias_method :perform_job, :have_performed_job
400
+
401
+ # @api public
402
+ # Passes if a job has been performed. May chain at_least, at_most or exactly to specify a number of times.
403
+ #
404
+ # @example
405
+ # before do
406
+ # ActiveJob::Base.queue_adapter.performed_jobs.clear
407
+ # ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
408
+ # ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true
409
+ # end
410
+ #
411
+ # HeavyLiftingJob.perform_later
412
+ # expect(HeavyLiftingJob).to have_been_performed
413
+ #
414
+ # HelloJob.perform_later
415
+ # HeavyLiftingJob.perform_later
416
+ # expect(HeavyLiftingJob).to have_been_performed.exactly(:once)
417
+ #
418
+ # 3.times { HelloJob.perform_later }
419
+ # expect(HelloJob).to have_been_performed.at_least(2).times
420
+ #
421
+ # HelloJob.perform_later
422
+ # HeavyLiftingJob.perform_later
423
+ # expect(HelloJob).to have_been_performed
424
+ # expect(HeavyLiftingJob).to have_been_performed
425
+ #
426
+ # HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42)
427
+ # expect(HelloJob).to have_been_performed.with(42).on_queue("low").at(Date.tomorrow.noon)
428
+ def have_been_performed
429
+ check_active_job_adapter
430
+ ActiveJob::HaveBeenPerformed.new
431
+ end
432
+
308
433
  private
309
434
 
310
435
  # @private
311
436
  def check_active_job_adapter
312
437
  return if ::ActiveJob::QueueAdapters::TestAdapter === ::ActiveJob::Base.queue_adapter
438
+
313
439
  raise StandardError, "To use ActiveJob matchers set `ActiveJob::Base.queue_adapter = :test`"
314
440
  end
315
441
  end
@@ -1,7 +1,9 @@
1
1
  module RSpec
2
2
  module Rails
3
3
  module Matchers
4
- # @ api private
4
+ # @api private
5
+ #
6
+ # Base class to build matchers. Should not be instantiated directly.
5
7
  class BaseMatcher
6
8
  include RSpec::Matchers::Composable
7
9
 
@@ -114,19 +116,12 @@ module RSpec
114
116
 
115
117
  def assert_ivars(*expected_ivars)
116
118
  return unless (expected_ivars - present_ivars).any?
119
+
117
120
  ivar_list = RSpec::Matchers::EnglishPhrasing.list(expected_ivars)
118
121
  raise "#{self.class.name} needs to supply#{ivar_list}"
119
122
  end
120
123
 
121
- if RUBY_VERSION.to_f < 1.9
122
- # :nocov:
123
- def present_ivars
124
- instance_variables.map(&:to_sym)
125
- end
126
- # :nocov:
127
- else
128
- alias present_ivars instance_variables
129
- end
124
+ alias present_ivars instance_variables
130
125
 
131
126
  # @private
132
127
  module HashFormatting
@@ -1,4 +1,7 @@
1
- require "rspec/mocks"
1
+ # We require the minimum amount of rspec-mocks possible to avoid
2
+ # conflicts with other mocking frameworks.
3
+ # See: https://github.com/rspec/rspec-rails/issues/2252
4
+ require "rspec/mocks/argument_matchers"
2
5
  require "rspec/rails/matchers/active_job"
3
6
 
4
7
  module RSpec
@@ -6,33 +9,32 @@ module RSpec
6
9
  module Matchers
7
10
  # Matcher class for `have_enqueued_mail`. Should not be instantiated directly.
8
11
  #
9
- # rubocop: disable Style/ClassLength
10
12
  # @private
11
13
  # @see RSpec::Rails::Matchers#have_enqueued_mail
12
14
  class HaveEnqueuedMail < ActiveJob::HaveEnqueuedJob
13
15
  MAILER_JOB_METHOD = 'deliver_now'.freeze
14
16
 
15
- include RSpec::Mocks::ExampleMethods
17
+ include RSpec::Mocks::ArgumentMatchers
16
18
 
17
19
  def initialize(mailer_class, method_name)
18
- super(mailer_job)
20
+ super(nil)
19
21
  @mailer_class = mailer_class
20
22
  @method_name = method_name
21
23
  @mail_args = []
22
- @args = mailer_args
23
24
  end
24
25
 
25
26
  def description
26
- "enqueues #{@mailer_class.name}.#{@method_name}"
27
+ "enqueues #{mailer_class_name}.#{@method_name}"
27
28
  end
28
29
 
29
30
  def with(*args, &block)
30
31
  @mail_args = args
31
- block.nil? ? super(*mailer_args) : super(*mailer_args, &yield_mail_args(block))
32
+ block.nil? ? super : super(&yield_mail_args(block))
32
33
  end
33
34
 
34
35
  def matches?(block)
35
36
  raise ArgumentError, 'have_enqueued_mail and enqueue_mail only work with block arguments' unless block.respond_to?(:call)
37
+
36
38
  check_active_job_adapter
37
39
  super
38
40
  end
@@ -50,7 +52,7 @@ module RSpec
50
52
  private
51
53
 
52
54
  def base_message
53
- "#{@mailer_class.name}.#{@method_name}".tap do |msg|
55
+ [mailer_class_name, @method_name].compact.join('.').tap do |msg|
54
56
  msg << " #{expected_count_message}"
55
57
  msg << " with #{@mail_args}," if @mail_args.any?
56
58
  msg << " on queue #{@queue}," if @queue
@@ -63,38 +65,46 @@ module RSpec
63
65
  "#{message_expectation_modifier} #{@expected_number} #{@expected_number == 1 ? 'time' : 'times'}"
64
66
  end
65
67
 
66
- def mailer_args
67
- if @mail_args.any?
68
- base_mailer_args + @mail_args
69
- else
70
- mailer_method_arity = @mailer_class.instance_method(@method_name).arity
68
+ def mailer_class_name
69
+ @mailer_class ? @mailer_class.name : 'ActionMailer::Base'
70
+ end
71
71
 
72
- number_of_args = if mailer_method_arity < 0
73
- (mailer_method_arity + 1).abs
74
- else
75
- mailer_method_arity
76
- end
72
+ def job_match?(job)
73
+ legacy_mail?(job) || parameterized_mail?(job) || unified_mail?(job)
74
+ end
77
75
 
78
- base_mailer_args + Array.new(number_of_args) { anything }
79
- end
76
+ def arguments_match?(job)
77
+ @args =
78
+ if @mail_args.any?
79
+ base_mailer_args + @mail_args
80
+ elsif @mailer_class && @method_name
81
+ base_mailer_args + [any_args]
82
+ elsif @mailer_class
83
+ [mailer_class_name, any_args]
84
+ else
85
+ []
86
+ end
87
+
88
+ super(job)
80
89
  end
81
90
 
82
91
  def base_mailer_args
83
- [@mailer_class.name, @method_name.to_s, MAILER_JOB_METHOD]
92
+ [mailer_class_name, @method_name.to_s, MAILER_JOB_METHOD]
84
93
  end
85
94
 
86
95
  def yield_mail_args(block)
87
- Proc.new { |*job_args| block.call(*(job_args - base_mailer_args)) }
96
+ proc { |*job_args| block.call(*(job_args - base_mailer_args)) }
88
97
  end
89
98
 
90
99
  def check_active_job_adapter
91
100
  return if ::ActiveJob::QueueAdapters::TestAdapter === ::ActiveJob::Base.queue_adapter
101
+
92
102
  raise StandardError, "To use HaveEnqueuedMail matcher set `ActiveJob::Base.queue_adapter = :test`"
93
103
  end
94
104
 
95
105
  def unmatching_mail_jobs
96
106
  @unmatching_jobs.select do |job|
97
- job[:job] == mailer_job
107
+ job_match?(job)
98
108
  end
99
109
  end
100
110
 
@@ -120,12 +130,18 @@ module RSpec
120
130
  "#{mailer_method} #{msg_parts.join(', ')}".strip
121
131
  end
122
132
 
123
- def mailer_job
124
- ActionMailer::DeliveryJob
133
+ def legacy_mail?(job)
134
+ job[:job] <= ActionMailer::DeliveryJob
135
+ end
136
+
137
+ def parameterized_mail?(job)
138
+ RSpec::Rails::FeatureCheck.has_action_mailer_parameterized? && job[:job] <= ActionMailer::Parameterized::DeliveryJob
125
139
  end
126
- end
127
- # rubocop: enable Style/ClassLength
128
140
 
141
+ def unified_mail?(job)
142
+ RSpec::Rails::FeatureCheck.has_action_mailer_unified_delivery? && job[:job] <= ActionMailer::MailDeliveryJob
143
+ end
144
+ end
129
145
  # @api public
130
146
  # Passes if an email has been enqueued inside block.
131
147
  # May chain with to specify expected arguments.
@@ -136,6 +152,14 @@ module RSpec
136
152
  # @example
137
153
  # expect {
138
154
  # MyMailer.welcome(user).deliver_later
155
+ # }.to have_enqueued_mail
156
+ #
157
+ # expect {
158
+ # MyMailer.welcome(user).deliver_later
159
+ # }.to have_enqueued_mail(MyMailer)
160
+ #
161
+ # expect {
162
+ # MyMailer.welcome(user).deliver_later
139
163
  # }.to have_enqueued_mail(MyMailer, :welcome)
140
164
  #
141
165
  # # Using alias
@@ -163,7 +187,7 @@ module RSpec
163
187
  # expect {
164
188
  # MyMailer.welcome(user).deliver_later(queue: :urgent_mail)
165
189
  # }.to have_enqueued_mail(MyMailer, :welcome).on_queue(:urgent_mail)
166
- def have_enqueued_mail(mailer_class, mail_method_name)
190
+ def have_enqueued_mail(mailer_class = nil, mail_method_name = nil)
167
191
  HaveEnqueuedMail.new(mailer_class, mail_method_name)
168
192
  end
169
193
  alias_method :have_enqueued_email, :have_enqueued_mail
@@ -59,6 +59,7 @@ module RSpec
59
59
  # `@invalid_response` is present, `nil` otherwise
60
60
  def invalid_response_type_message
61
61
  return unless @invalid_response
62
+
62
63
  "expected a response object, but an instance of " \
63
64
  "#{@invalid_response.class} was received"
64
65
  end
@@ -72,7 +73,7 @@ module RSpec
72
73
  # @example
73
74
  # expect(response).to have_http_status(404)
74
75
  #
75
- # @see RSpec::Rails::Matchers.have_http_status
76
+ # @see RSpec::Rails::Matchers#have_http_status
76
77
  class NumericCode < RSpec::Rails::Matchers::BaseMatcher
77
78
  include HaveHttpStatus
78
79
 
@@ -122,7 +123,7 @@ module RSpec
122
123
  # @example
123
124
  # expect(response).to have_http_status(:created)
124
125
  #
125
- # @see RSpec::Rails::Matchers.have_http_status
126
+ # @see RSpec::Rails::Matchers#have_http_status
126
127
  # @see https://github.com/rack/rack/blob/master/lib/rack/utils.rb `Rack::Utils::SYMBOL_TO_STATUS_CODE`
127
128
  class SymbolicStatus < RSpec::Rails::Matchers::BaseMatcher
128
129
  include HaveHttpStatus
@@ -174,6 +175,7 @@ module RSpec
174
175
  # @return [Symbol] representing the actual http numeric code
175
176
  def actual_status
176
177
  return unless actual
178
+
177
179
  @actual_status ||= compute_status_from(actual)
178
180
  end
179
181
 
@@ -234,8 +236,8 @@ module RSpec
234
236
  # expect(response).to have_http_status(:missing)
235
237
  # expect(response).to have_http_status(:redirect)
236
238
  #
237
- # @see RSpec::Rails::Matchers.have_http_status
238
- # @see ActionDispatch::TestResponse
239
+ # @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`
239
241
  class GenericStatus < RSpec::Rails::Matchers::BaseMatcher
240
242
  include HaveHttpStatus
241
243
 
@@ -254,6 +256,7 @@ module RSpec
254
256
  unless self.class.valid_statuses.include?(type)
255
257
  raise ArgumentError, "Invalid generic HTTP status: #{type.inspect}"
256
258
  end
259
+
257
260
  @expected = type
258
261
  @actual = nil
259
262
  @invalid_response = nil
@@ -290,9 +293,9 @@ module RSpec
290
293
  protected
291
294
 
292
295
  RESPONSE_METHODS = {
293
- :success => 'successful',
294
- :error => 'server_error',
295
- :missing => 'not_found'
296
+ success: 'successful',
297
+ error: 'server_error',
298
+ missing: 'not_found'
296
299
  }.freeze
297
300
 
298
301
  def check_expected_status(test_response, expected)
@@ -374,6 +377,7 @@ module RSpec
374
377
  # @see https://github.com/rack/rack/blob/master/lib/rack/utils.rb `Rack::Utils::SYMBOL_TO_STATUS_CODE`
375
378
  def have_http_status(target)
376
379
  raise ArgumentError, "Invalid HTTP status: nil" unless target
380
+
377
381
  HaveHttpStatus.matcher_for_status(target)
378
382
  end
379
383
  end
@@ -29,6 +29,7 @@ module RSpec
29
29
  def check_redirect
30
30
  response = @scope.response
31
31
  return unless response.respond_to?(:redirect?) && response.redirect?
32
+
32
33
  @redirect_is = @scope.send(:normalize_argument_to_redirection, response.location)
33
34
  end
34
35
 
@@ -14,7 +14,7 @@ module RSpec
14
14
  @expected.merge!(expected[0])
15
15
  else
16
16
  controller, action = expected[0].split('#')
17
- @expected.merge!(:controller => controller, :action => action)
17
+ @expected.merge!(controller: controller, action: action)
18
18
  end
19
19
  end
20
20
 
@@ -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
@@ -50,14 +50,14 @@ module RSpec
50
50
  #
51
51
  # @example
52
52
  #
53
- # expect(:get => "/things/special").to route_to(
54
- # :controller => "things",
55
- # :action => "special"
53
+ # expect(get: "/things/special").to route_to(
54
+ # controller: "things",
55
+ # action: "special"
56
56
  # )
57
57
  #
58
- # expect(:get => "/things/special").to route_to("things#special")
58
+ # expect(get: "/things/special").to route_to("things#special")
59
59
  #
60
- # @see http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_recognizes
60
+ # @see https://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_recognizes
61
61
  def route_to(*expected)
62
62
  RouteToMatcher.new(self, *expected)
63
63
  end
@@ -72,7 +72,7 @@ module RSpec
72
72
  @actual = path
73
73
  match_unless_raises ActionController::RoutingError do
74
74
  @routing_options = @scope.routes.recognize_path(
75
- path.values.first, :method => path.keys.first
75
+ path.values.first, method: path.keys.first
76
76
  )
77
77
  end
78
78
  end
@@ -95,9 +95,9 @@ module RSpec
95
95
  # `RouteSet#recognize_path`.
96
96
  #
97
97
  # @example You can use route helpers provided by rspec-rails.
98
- # expect(:get => "/a/path").to be_routable
99
- # expect(:post => "/another/path").to be_routable
100
- # expect(:put => "/yet/another/path").to be_routable
98
+ # expect(get: "/a/path").to be_routable
99
+ # expect(post: "/another/path").to be_routable
100
+ # expect(put: "/yet/another/path").to be_routable
101
101
  def be_routable
102
102
  BeRoutableMatcher.new(self)
103
103
  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
@@ -20,6 +20,16 @@ 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
+
23
24
  if RSpec::Rails::FeatureCheck.has_active_job?
24
25
  require 'rspec/rails/matchers/active_job'
26
+ require 'rspec/rails/matchers/have_enqueued_mail'
27
+ end
28
+
29
+ if RSpec::Rails::FeatureCheck.has_action_cable_testing?
30
+ require 'rspec/rails/matchers/action_cable'
31
+ end
32
+
33
+ if RSpec::Rails::FeatureCheck.has_action_mailbox?
34
+ require 'rspec/rails/matchers/action_mailbox'
25
35
  end
@@ -3,19 +3,19 @@ if default = Rake.application.instance_variable_get('@tasks')['default']
3
3
  default.prerequisites.delete('test')
4
4
  end
5
5
 
6
- task :default => :spec
6
+ task default: :spec
7
7
 
8
- task :stats => "spec:statsetup"
8
+ task stats: "spec:statsetup"
9
9
 
10
10
  desc "Run all specs in spec directory (excluding plugin specs)"
11
- RSpec::Core::RakeTask.new(:spec => "spec:prepare")
11
+ RSpec::Core::RakeTask.new(spec: "spec:prepare")
12
12
 
13
13
  namespace :spec do
14
14
  types = begin
15
- dirs = Dir['./spec/**/*_spec.rb'].
16
- map { |f| f.sub(/^\.\/(spec\/\w+)\/.*/, '\\1') }.
17
- uniq.
18
- select { |f| File.directory?(f) }
15
+ dirs = Dir['./spec/**/*_spec.rb']
16
+ .map { |f| f.sub(/^\.\/(spec\/\w+)\/.*/, '\\1') }
17
+ .uniq
18
+ .select { |f| File.directory?(f) }
19
19
  Hash[dirs.map { |d| [d.split('/').last, d] }]
20
20
  end
21
21
 
@@ -35,16 +35,6 @@ namespace :spec do
35
35
  end
36
36
  end
37
37
 
38
- # RCov task only enabled for Ruby 1.8
39
- if RUBY_VERSION < '1.9'
40
- desc "Run all specs with rcov"
41
- RSpec::Core::RakeTask.new(:rcov => "spec:prepare") do |t|
42
- t.rcov = true
43
- t.pattern = "./spec/**/*_spec.rb"
44
- t.rcov_opts = '--exclude /gems/,/Library/,/usr/,lib/tasks,.bundle,config,/lib/rspec/,/lib/rspec-,spec'
45
- end
46
- end
47
-
48
38
  task :statsetup do
49
39
  require 'rails/code_statistics'
50
40
  types.each do |type, dir|