rspec-rails 3.9.1 → 4.0.0
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/Capybara.md +5 -54
- data/Changelog.md +167 -80
- data/README.md +4 -5
- data/lib/generators/rspec/channel/channel_generator.rb +12 -0
- data/lib/generators/rspec/{observer/templates/observer_spec.rb → channel/templates/channel_spec.rb.erb} +1 -1
- data/lib/generators/rspec/controller/controller_generator.rb +21 -4
- data/lib/generators/rspec/controller/templates/request_spec.rb +14 -0
- data/lib/generators/rspec/controller/templates/routing_spec.rb +13 -0
- data/lib/generators/rspec/feature/feature_generator.rb +2 -2
- data/lib/generators/rspec/{generators → generator}/generator_generator.rb +2 -2
- data/lib/generators/rspec/{generators → generator}/templates/generator_spec.rb +0 -0
- data/lib/generators/rspec/helper/helper_generator.rb +1 -1
- data/lib/generators/rspec/install/install_generator.rb +4 -4
- data/lib/generators/rspec/install/templates/spec/rails_helper.rb +17 -16
- data/lib/generators/rspec/integration/integration_generator.rb +3 -3
- data/lib/generators/rspec/mailbox/mailbox_generator.rb +14 -0
- data/lib/generators/rspec/mailbox/templates/mailbox_spec.rb.erb +7 -0
- data/lib/generators/rspec/mailer/mailer_generator.rb +2 -1
- data/lib/generators/rspec/model/model_generator.rb +5 -4
- data/lib/generators/rspec/model/templates/fixtures.yml +1 -1
- data/lib/generators/rspec/request/request_generator.rb +1 -1
- data/lib/generators/rspec/scaffold/scaffold_generator.rb +29 -19
- data/lib/generators/rspec/scaffold/templates/api_controller_spec.rb +0 -36
- data/lib/generators/rspec/scaffold/templates/api_request_spec.rb +131 -0
- data/lib/generators/rspec/scaffold/templates/controller_spec.rb +10 -10
- data/lib/generators/rspec/scaffold/templates/edit_spec.rb +1 -1
- data/lib/generators/rspec/scaffold/templates/index_spec.rb +2 -2
- data/lib/generators/rspec/scaffold/templates/new_spec.rb +1 -1
- data/lib/generators/rspec/scaffold/templates/request_spec.rb +133 -0
- data/lib/generators/rspec/scaffold/templates/routing_spec.rb +8 -10
- data/lib/generators/rspec/scaffold/templates/show_spec.rb +1 -1
- data/lib/generators/rspec/system/system_generator.rb +1 -1
- data/lib/generators/rspec/view/view_generator.rb +2 -2
- data/lib/generators/rspec.rb +0 -6
- data/lib/rspec/rails/adapters.rb +11 -76
- data/lib/rspec/rails/configuration.rb +43 -33
- data/lib/rspec/rails/example/channel_example_group.rb +93 -0
- data/lib/rspec/rails/example/controller_example_group.rb +4 -4
- data/lib/rspec/rails/example/feature_example_group.rb +6 -26
- data/lib/rspec/rails/example/helper_example_group.rb +2 -9
- data/lib/rspec/rails/example/mailbox_example_group.rb +80 -0
- data/lib/rspec/rails/example/mailer_example_group.rb +1 -1
- data/lib/rspec/rails/example/rails_example_group.rb +1 -1
- data/lib/rspec/rails/example/system_example_group.rb +24 -8
- data/lib/rspec/rails/example/view_example_group.rb +38 -27
- data/lib/rspec/rails/example.rb +2 -0
- data/lib/rspec/rails/extensions/active_record/proxy.rb +1 -9
- data/lib/rspec/rails/feature_check.rb +12 -29
- data/lib/rspec/rails/fixture_file_upload_support.rb +1 -1
- data/lib/rspec/rails/fixture_support.rb +37 -31
- data/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +170 -0
- data/lib/rspec/rails/matchers/action_cable/have_streams.rb +58 -0
- data/lib/rspec/rails/matchers/action_cable.rb +65 -0
- data/lib/rspec/rails/matchers/action_mailbox.rb +64 -0
- data/lib/rspec/rails/matchers/active_job.rb +142 -20
- data/lib/rspec/rails/matchers/base_matcher.rb +5 -10
- data/lib/rspec/rails/matchers/have_enqueued_mail.rb +52 -28
- data/lib/rspec/rails/matchers/have_http_status.rb +11 -7
- data/lib/rspec/rails/matchers/have_rendered.rb +1 -0
- data/lib/rspec/rails/matchers/routing_matchers.rb +12 -12
- data/lib/rspec/rails/matchers.rb +9 -0
- data/lib/rspec/rails/tasks/rspec.rake +7 -17
- data/lib/rspec/rails/vendor/capybara.rb +10 -15
- data/lib/rspec/rails/version.rb +1 -1
- data/lib/rspec/rails/view_path_builder.rb +1 -1
- data/lib/rspec/rails/view_rendering.rb +15 -4
- data/lib/rspec-rails.rb +8 -9
- data.tar.gz.sig +0 -0
- metadata +42 -30
- metadata.gz.sig +0 -0
- 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
|
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 =
|
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
|
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
|
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) &&
|
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
|
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(
|
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
|
147
|
-
|
148
|
-
end
|
151
|
+
def queue_match?(job)
|
152
|
+
return true unless @queue
|
149
153
|
|
150
|
-
|
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
|
159
|
-
|
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
|
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
|
-
# @
|
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
|
-
|
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
|
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::
|
17
|
+
include RSpec::Mocks::ArgumentMatchers
|
16
18
|
|
17
19
|
def initialize(mailer_class, method_name)
|
18
|
-
super(
|
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 #{
|
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
|
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
|
-
|
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
|
67
|
-
|
68
|
-
|
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
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
79
|
-
|
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
|
-
[
|
92
|
+
[mailer_class_name, @method_name.to_s, MAILER_JOB_METHOD]
|
84
93
|
end
|
85
94
|
|
86
95
|
def yield_mail_args(block)
|
87
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
-
:
|
294
|
-
:
|
295
|
-
:
|
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
|
@@ -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!(:
|
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
|
-
{
|
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(:
|
54
|
-
# :
|
55
|
-
# :
|
53
|
+
# expect(get: "/things/special").to route_to(
|
54
|
+
# controller: "things",
|
55
|
+
# action: "special"
|
56
56
|
# )
|
57
57
|
#
|
58
|
-
# expect(:
|
58
|
+
# expect(get: "/things/special").to route_to("things#special")
|
59
59
|
#
|
60
|
-
# @see
|
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, :
|
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(:
|
99
|
-
# expect(:
|
100
|
-
# expect(:
|
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
|
-
{
|
118
|
+
{method.to_sym => path}
|
119
119
|
end
|
120
120
|
end
|
121
121
|
end
|
data/lib/rspec/rails/matchers.rb
CHANGED
@@ -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 :
|
6
|
+
task default: :spec
|
7
7
|
|
8
|
-
task :
|
8
|
+
task stats: "spec:statsetup"
|
9
9
|
|
10
10
|
desc "Run all specs in spec directory (excluding plugin specs)"
|
11
|
-
RSpec::Core::RakeTask.new(:
|
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|
|