rspec-rails 3.9.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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 +167 -80
  5. data/README.md +4 -5
  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 +1 -1
  45. data/lib/rspec/rails/example/rails_example_group.rb +1 -1
  46. data/lib/rspec/rails/example/system_example_group.rb +24 -8
  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 +142 -20
  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 +9 -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 +42 -30
  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,7 +26,7 @@ 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
 
@@ -67,7 +67,7 @@ module RSpec
67
67
  end
68
68
 
69
69
  def failure_message
70
- "expected to enqueue #{base_message}".tap do |msg|
70
+ "expected to #{self.class::FAILURE_MESSAGE_EXPECTATION_ACTION} #{base_message}".tap do |msg|
71
71
  if @unmatching_jobs.any?
72
72
  msg << "\nQueued jobs:"
73
73
  @unmatching_jobs.each do |job|
@@ -78,7 +78,7 @@ module RSpec
78
78
  end
79
79
 
80
80
  def failure_message_when_negated
81
- "expected not to enqueue #{base_message}"
81
+ "expected not to #{self.class::FAILURE_MESSAGE_EXPECTATION_ACTION} #{base_message}"
82
82
  end
83
83
 
84
84
  def message_expectation_modifier
@@ -97,7 +97,7 @@ module RSpec
97
97
 
98
98
  def check(jobs)
99
99
  @matching_jobs, @unmatching_jobs = jobs.partition do |job|
100
- if arguments_match?(job) && other_attributes_match?(job)
100
+ if job_match?(job) && arguments_match?(job) && queue_match?(job) && at_match?(job)
101
101
  args = deserialize_arguments(job)
102
102
  @block.call(*args)
103
103
  true
@@ -119,7 +119,7 @@ module RSpec
119
119
  msg << " with #{@args}," if @args.any?
120
120
  msg << " on queue #{@queue}," if @queue
121
121
  msg << " at #{@at.inspect}," if @at
122
- msg << " but enqueued #{@matching_jobs_count}"
122
+ msg << " but #{self.class::MESSAGE_EXPECTATION_ACTION} #{@matching_jobs_count}"
123
123
  end
124
124
  end
125
125
 
@@ -134,29 +134,32 @@ module RSpec
134
134
  end
135
135
  end
136
136
 
137
+ def job_match?(job)
138
+ @job ? @job == job[:job] : true
139
+ end
140
+
137
141
  def arguments_match?(job)
138
142
  if @args.any?
143
+ args = serialize_and_deserialize_arguments(@args)
139
144
  deserialized_args = deserialize_arguments(job)
140
- RSpec::Mocks::ArgumentListMatcher.new(*@args).args_match?(*deserialized_args)
145
+ RSpec::Mocks::ArgumentListMatcher.new(*args).args_match?(*deserialized_args)
141
146
  else
142
147
  true
143
148
  end
144
149
  end
145
150
 
146
- def other_attributes_match?(job)
147
- serialized_attributes.all? { |key, value| value == job[key] }
148
- end
151
+ def queue_match?(job)
152
+ return true unless @queue
149
153
 
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
154
+ @queue == job[:queue]
156
155
  end
157
156
 
158
- def serialized_at
159
- @at == :no_wait ? nil : @at.to_f
157
+ def at_match?(job)
158
+ return true unless @at
159
+ return job[:at].nil? if @at == :no_wait
160
+ return false unless job[:at]
161
+
162
+ values_match?(@at, Time.at(job[:at]))
160
163
  end
161
164
 
162
165
  def set_expected_number(relativity, count)
@@ -169,6 +172,13 @@ module RSpec
169
172
  end
170
173
  end
171
174
 
175
+ def serialize_and_deserialize_arguments(args)
176
+ serialized = ::ActiveJob::Arguments.serialize(args)
177
+ ::ActiveJob::Arguments.deserialize(serialized)
178
+ rescue ::ActiveJob::SerializationError
179
+ args
180
+ end
181
+
172
182
  def deserialize_arguments(job)
173
183
  ::ActiveJob::Arguments.deserialize(job[:args])
174
184
  rescue ::ActiveJob::DeserializationError
@@ -179,10 +189,13 @@ module RSpec
179
189
  ::ActiveJob::Base.queue_adapter
180
190
  end
181
191
  end
182
- # rubocop: enable Style/ClassLength
192
+ # rubocop: enable Metrics/ClassLength
183
193
 
184
194
  # @private
185
195
  class HaveEnqueuedJob < Base
196
+ FAILURE_MESSAGE_EXPECTATION_ACTION = 'enqueue'.freeze
197
+ MESSAGE_EXPECTATION_ACTION = 'enqueued'.freeze
198
+
186
199
  def initialize(job)
187
200
  super()
188
201
  @job = job
@@ -207,6 +220,9 @@ module RSpec
207
220
 
208
221
  # @private
209
222
  class HaveBeenEnqueued < Base
223
+ FAILURE_MESSAGE_EXPECTATION_ACTION = 'enqueue'.freeze
224
+ MESSAGE_EXPECTATION_ACTION = 'enqueued'.freeze
225
+
210
226
  def matches?(job)
211
227
  @job = job
212
228
  check(queue_adapter.enqueued_jobs)
@@ -218,6 +234,38 @@ module RSpec
218
234
  !matches?(proc)
219
235
  end
220
236
  end
237
+
238
+ # @private
239
+ class HavePerformedJob < Base
240
+ FAILURE_MESSAGE_EXPECTATION_ACTION = 'perform'.freeze
241
+ MESSAGE_EXPECTATION_ACTION = 'performed'.freeze
242
+
243
+ def initialize(job)
244
+ super()
245
+ @job = job
246
+ end
247
+
248
+ def matches?(proc)
249
+ raise ArgumentError, "have_performed_job only supports block expectations" unless Proc === proc
250
+
251
+ original_performed_jobs_count = queue_adapter.performed_jobs.count
252
+ proc.call
253
+ in_block_jobs = queue_adapter.performed_jobs.drop(original_performed_jobs_count)
254
+
255
+ check(in_block_jobs)
256
+ end
257
+ end
258
+
259
+ # @private
260
+ class HaveBeenPerformed < Base
261
+ FAILURE_MESSAGE_EXPECTATION_ACTION = 'perform'.freeze
262
+ MESSAGE_EXPECTATION_ACTION = 'performed'.freeze
263
+
264
+ def matches?(job)
265
+ @job = job
266
+ check(queue_adapter.performed_jobs)
267
+ end
268
+ end
221
269
  end
222
270
 
223
271
  # @api public
@@ -305,11 +353,85 @@ module RSpec
305
353
  ActiveJob::HaveBeenEnqueued.new
306
354
  end
307
355
 
356
+ # @api public
357
+ # Passes if a job has been performed inside block. May chain at_least, at_most or exactly to specify a number of times.
358
+ #
359
+ # @example
360
+ # expect {
361
+ # perform_jobs { HeavyLiftingJob.perform_later }
362
+ # }.to have_performed_job
363
+ #
364
+ # expect {
365
+ # perform_jobs {
366
+ # HelloJob.perform_later
367
+ # HeavyLiftingJob.perform_later
368
+ # }
369
+ # }.to have_performed_job(HelloJob).exactly(:once)
370
+ #
371
+ # expect {
372
+ # perform_jobs { 3.times { HelloJob.perform_later } }
373
+ # }.to have_performed_job(HelloJob).at_least(2).times
374
+ #
375
+ # expect {
376
+ # perform_jobs { HelloJob.perform_later }
377
+ # }.to have_performed_job(HelloJob).at_most(:twice)
378
+ #
379
+ # expect {
380
+ # perform_jobs {
381
+ # HelloJob.perform_later
382
+ # HeavyLiftingJob.perform_later
383
+ # }
384
+ # }.to have_performed_job(HelloJob).and have_performed_job(HeavyLiftingJob)
385
+ #
386
+ # expect {
387
+ # perform_jobs {
388
+ # HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42)
389
+ # }
390
+ # }.to have_performed_job.with(42).on_queue("low").at(Date.tomorrow.noon)
391
+ def have_performed_job(job = nil)
392
+ check_active_job_adapter
393
+ ActiveJob::HavePerformedJob.new(job)
394
+ end
395
+ alias_method :perform_job, :have_performed_job
396
+
397
+ # @api public
398
+ # Passes if a job has been performed. May chain at_least, at_most or exactly to specify a number of times.
399
+ #
400
+ # @example
401
+ # before do
402
+ # ActiveJob::Base.queue_adapter.performed_jobs.clear
403
+ # ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
404
+ # ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true
405
+ # end
406
+ #
407
+ # HeavyLiftingJob.perform_later
408
+ # expect(HeavyLiftingJob).to have_been_performed
409
+ #
410
+ # HelloJob.perform_later
411
+ # HeavyLiftingJob.perform_later
412
+ # expect(HeavyLiftingJob).to have_been_performed.exactly(:once)
413
+ #
414
+ # 3.times { HelloJob.perform_later }
415
+ # expect(HelloJob).to have_been_performed.at_least(2).times
416
+ #
417
+ # HelloJob.perform_later
418
+ # HeavyLiftingJob.perform_later
419
+ # expect(HelloJob).to have_been_performed
420
+ # expect(HeavyLiftingJob).to have_been_performed
421
+ #
422
+ # HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42)
423
+ # expect(HelloJob).to have_been_performed.with(42).on_queue("low").at(Date.tomorrow.noon)
424
+ def have_been_performed
425
+ check_active_job_adapter
426
+ ActiveJob::HaveBeenPerformed.new
427
+ end
428
+
308
429
  private
309
430
 
310
431
  # @private
311
432
  def check_active_job_adapter
312
433
  return if ::ActiveJob::QueueAdapters::TestAdapter === ::ActiveJob::Base.queue_adapter
434
+
313
435
  raise StandardError, "To use ActiveJob matchers set `ActiveJob::Base.queue_adapter = :test`"
314
436
  end
315
437
  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,7 +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'
25
26
  require 'rspec/rails/matchers/have_enqueued_mail'
26
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'
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|