mini-quick-sys 0.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.
- checksums.yaml +7 -0
- data/mini-quick-sys.gemspec +12 -0
- data/rspec-rails-8.0.4/Capybara.md +28 -0
- data/rspec-rails-8.0.4/Changelog.md +1408 -0
- data/rspec-rails-8.0.4/LICENSE.md +25 -0
- data/rspec-rails-8.0.4/README.md +386 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/authentication/authentication_generator.rb +25 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/authentication/templates/user_spec.rb +5 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/authentication/templates/users.yml +11 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/channel/channel_generator.rb +12 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/channel/templates/channel_spec.rb.erb +7 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/controller/controller_generator.rb +51 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/controller/templates/controller_spec.rb +16 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/controller/templates/request_spec.rb +19 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/controller/templates/routing_spec.rb +13 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/controller/templates/view_spec.rb +5 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/feature/feature_generator.rb +29 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/feature/templates/feature_singular_spec.rb +5 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/feature/templates/feature_spec.rb +5 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/generator/generator_generator.rb +24 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/generator/templates/generator_spec.rb +5 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/helper/helper_generator.rb +16 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/helper/templates/helper_spec.rb +17 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/install/install_generator.rb +80 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/install/templates/spec/rails_helper.rb +91 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/job/job_generator.rb +13 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/job/templates/job_spec.rb.erb +7 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/mailbox/mailbox_generator.rb +14 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/mailbox/templates/mailbox_spec.rb.erb +7 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/mailer/mailer_generator.rb +30 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/mailer/templates/fixture +3 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/mailer/templates/mailer_spec.rb +25 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/mailer/templates/preview.rb +13 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/model/model_generator.rb +37 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/model/templates/fixtures.yml +19 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/model/templates/model_spec.rb +7 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/request/request_generator.rb +17 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/request/templates/request_spec.rb +10 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/scaffold/scaffold_generator.rb +136 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/scaffold/templates/api_controller_spec.rb +129 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/scaffold/templates/api_request_spec.rb +131 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/scaffold/templates/controller_spec.rb +145 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/scaffold/templates/edit_spec.rb +27 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/scaffold/templates/index_spec.rb +26 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/scaffold/templates/new_spec.rb +22 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/scaffold/templates/request_spec.rb +138 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/scaffold/templates/routing_spec.rb +46 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/scaffold/templates/show_spec.rb +21 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/system/system_generator.rb +24 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/system/templates/system_spec.rb +9 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/view/templates/view_spec.rb +5 -0
- data/rspec-rails-8.0.4/lib/generators/rspec/view/view_generator.rb +22 -0
- data/rspec-rails-8.0.4/lib/generators/rspec.rb +56 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/active_record.rb +25 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/adapters.rb +196 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/configuration.rb +158 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/channel_example_group.rb +93 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/controller_example_group.rb +217 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/feature_example_group.rb +53 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/helper_example_group.rb +42 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/job_example_group.rb +23 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/mailbox_example_group.rb +80 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/mailer_example_group.rb +38 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/model_example_group.rb +11 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/rails_example_group.rb +23 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/request_example_group.rb +27 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/routing_example_group.rb +61 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/system_example_group.rb +177 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example/view_example_group.rb +214 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/example.rb +13 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/extensions/active_record/proxy.rb +11 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/extensions.rb +1 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/feature_check.rb +51 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/file_fixture_support.rb +18 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/fixture_file_upload_support.rb +39 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/fixture_support.rb +58 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +180 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/action_cable/have_streams.rb +58 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/action_cable.rb +70 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/action_mailbox.rb +73 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/active_job.rb +534 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/base_matcher.rb +179 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/be_a_new.rb +83 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/be_new_record.rb +30 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/be_valid.rb +49 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/have_enqueued_mail.rb +259 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/have_http_status.rb +381 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/have_rendered.rb +64 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/redirect_to.rb +38 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/relation_match_array.rb +3 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/routing_matchers.rb +125 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers/send_email.rb +122 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/matchers.rb +36 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/tasks/rspec.rake +49 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/vendor/capybara.rb +32 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/version.rb +9 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/view_assigns.rb +27 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/view_path_builder.rb +29 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/view_rendering.rb +166 -0
- data/rspec-rails-8.0.4/lib/rspec/rails/view_spec_methods.rb +56 -0
- data/rspec-rails-8.0.4/lib/rspec/rails.rb +18 -0
- data/rspec-rails-8.0.4/lib/rspec-rails.rb +91 -0
- metadata +142 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
# The following code inspired and modified from Rails' `assert_response`:
|
|
2
|
+
#
|
|
3
|
+
# https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/testing/assertions/response.rb#L22-L38
|
|
4
|
+
#
|
|
5
|
+
# Thank you to all the Rails devs who did the heavy lifting on this!
|
|
6
|
+
|
|
7
|
+
module RSpec
|
|
8
|
+
module Rails
|
|
9
|
+
module Matchers
|
|
10
|
+
# Namespace for various implementations of `have_http_status`.
|
|
11
|
+
#
|
|
12
|
+
# @api private
|
|
13
|
+
module HaveHttpStatus
|
|
14
|
+
# Instantiates an instance of the proper matcher based on the provided
|
|
15
|
+
# `target`.
|
|
16
|
+
#
|
|
17
|
+
# @param target [Object] expected http status or code
|
|
18
|
+
# @return response matcher instance
|
|
19
|
+
def self.matcher_for_status(target)
|
|
20
|
+
if GenericStatus.valid_statuses.include?(target)
|
|
21
|
+
GenericStatus.new(target)
|
|
22
|
+
elsif Symbol === target
|
|
23
|
+
SymbolicStatus.new(target)
|
|
24
|
+
else
|
|
25
|
+
NumericCode.new(target)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @api private
|
|
30
|
+
# Conversion function to coerce the provided object into an
|
|
31
|
+
# `ActionDispatch::TestResponse`.
|
|
32
|
+
#
|
|
33
|
+
# @param obj [Object] object to convert to a response
|
|
34
|
+
# @return [ActionDispatch::TestResponse]
|
|
35
|
+
def as_test_response(obj)
|
|
36
|
+
if ::ActionDispatch::Response === obj || ::Rack::MockResponse === obj
|
|
37
|
+
::ActionDispatch::TestResponse.from_response(obj)
|
|
38
|
+
elsif ::ActionDispatch::TestResponse === obj
|
|
39
|
+
obj
|
|
40
|
+
elsif obj.respond_to?(:status_code) && obj.respond_to?(:response_headers)
|
|
41
|
+
# Acts As Capybara Session
|
|
42
|
+
# Hack to support `Capybara::Session` without having to load
|
|
43
|
+
# Capybara or catch `NameError`s for the undefined constants
|
|
44
|
+
obj = ActionDispatch::Response.new.tap do |resp|
|
|
45
|
+
resp.status = obj.status_code
|
|
46
|
+
resp.headers.clear
|
|
47
|
+
resp.headers.merge!(obj.response_headers)
|
|
48
|
+
resp.body = obj.body
|
|
49
|
+
resp.request = ActionDispatch::Request.new({})
|
|
50
|
+
end
|
|
51
|
+
::ActionDispatch::TestResponse.from_response(obj)
|
|
52
|
+
else
|
|
53
|
+
raise TypeError, "Invalid response type: #{obj}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
module_function :as_test_response
|
|
57
|
+
|
|
58
|
+
# @return [String, nil] a formatted failure message if
|
|
59
|
+
# `@invalid_response` is present, `nil` otherwise
|
|
60
|
+
def invalid_response_type_message
|
|
61
|
+
return unless @invalid_response
|
|
62
|
+
|
|
63
|
+
"expected a response object, but an instance of " \
|
|
64
|
+
"#{@invalid_response.class} was received"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @api private
|
|
68
|
+
# Provides an implementation for `have_http_status` matching against
|
|
69
|
+
# numeric http status codes.
|
|
70
|
+
#
|
|
71
|
+
# Not intended to be instantiated directly.
|
|
72
|
+
#
|
|
73
|
+
# @example
|
|
74
|
+
# expect(response).to have_http_status(404)
|
|
75
|
+
#
|
|
76
|
+
# @see RSpec::Rails::Matchers#have_http_status
|
|
77
|
+
class NumericCode < RSpec::Rails::Matchers::BaseMatcher
|
|
78
|
+
include HaveHttpStatus
|
|
79
|
+
|
|
80
|
+
def initialize(code)
|
|
81
|
+
@expected = code.to_i
|
|
82
|
+
@actual = nil
|
|
83
|
+
@invalid_response = nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @param [Object] response object providing an http code to match
|
|
87
|
+
# @return [Boolean] `true` if the numeric code matched the `response` code
|
|
88
|
+
def matches?(response)
|
|
89
|
+
test_response = as_test_response(response)
|
|
90
|
+
@actual = test_response.response_code.to_i
|
|
91
|
+
expected == @actual
|
|
92
|
+
rescue TypeError => _ignored
|
|
93
|
+
@invalid_response = response
|
|
94
|
+
false
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @return [String]
|
|
98
|
+
def description
|
|
99
|
+
"respond with numeric status code #{expected}"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @return [String] explaining why the match failed
|
|
103
|
+
def failure_message
|
|
104
|
+
invalid_response_type_message ||
|
|
105
|
+
"expected the response to have status code #{expected.inspect}" \
|
|
106
|
+
" but it was #{actual.inspect}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @return [String] explaining why the match failed
|
|
110
|
+
def failure_message_when_negated
|
|
111
|
+
invalid_response_type_message ||
|
|
112
|
+
"expected the response not to have status code " \
|
|
113
|
+
"#{expected.inspect} but it did"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# @api private
|
|
118
|
+
# Provides an implementation for `have_http_status` matching against
|
|
119
|
+
# Rack symbol http status codes.
|
|
120
|
+
#
|
|
121
|
+
# Not intended to be instantiated directly.
|
|
122
|
+
#
|
|
123
|
+
# @example
|
|
124
|
+
# expect(response).to have_http_status(:created)
|
|
125
|
+
#
|
|
126
|
+
# @see RSpec::Rails::Matchers#have_http_status
|
|
127
|
+
# @see https://github.com/rack/rack/blob/master/lib/rack/utils.rb `Rack::Utils::SYMBOL_TO_STATUS_CODE`
|
|
128
|
+
class SymbolicStatus < RSpec::Rails::Matchers::BaseMatcher
|
|
129
|
+
include HaveHttpStatus
|
|
130
|
+
|
|
131
|
+
def initialize(status)
|
|
132
|
+
@expected_status = status
|
|
133
|
+
@actual = nil
|
|
134
|
+
@invalid_response = nil
|
|
135
|
+
set_expected_code!
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# @param [Object] response object providing an http code to match
|
|
139
|
+
# @return [Boolean] `true` if Rack's associated numeric HTTP code matched
|
|
140
|
+
# the `response` code
|
|
141
|
+
def matches?(response)
|
|
142
|
+
test_response = as_test_response(response)
|
|
143
|
+
@actual = test_response.response_code
|
|
144
|
+
expected == @actual
|
|
145
|
+
rescue TypeError => _ignored
|
|
146
|
+
@invalid_response = response
|
|
147
|
+
false
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# @return [String]
|
|
151
|
+
def description
|
|
152
|
+
"respond with status code #{pp_expected}"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# @return [String] explaining why the match failed
|
|
156
|
+
def failure_message
|
|
157
|
+
invalid_response_type_message ||
|
|
158
|
+
"expected the response to have status code #{pp_expected} but it" \
|
|
159
|
+
" was #{pp_actual}"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# @return [String] explaining why the match failed
|
|
163
|
+
def failure_message_when_negated
|
|
164
|
+
invalid_response_type_message ||
|
|
165
|
+
"expected the response not to have status code #{pp_expected} " \
|
|
166
|
+
"but it did"
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# The initialized expected status symbol
|
|
170
|
+
attr_reader :expected_status
|
|
171
|
+
private :expected_status
|
|
172
|
+
|
|
173
|
+
private
|
|
174
|
+
|
|
175
|
+
# @return [Symbol] representing the actual http numeric code
|
|
176
|
+
def actual_status
|
|
177
|
+
return unless actual
|
|
178
|
+
|
|
179
|
+
@actual_status ||= compute_status_from(actual)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Reverse lookup of the Rack status code symbol based on the numeric
|
|
183
|
+
# http code
|
|
184
|
+
#
|
|
185
|
+
# @param code [Fixnum] http status code to look up
|
|
186
|
+
# @return [Symbol] representing the http numeric code
|
|
187
|
+
def compute_status_from(code)
|
|
188
|
+
status, _ = Rack::Utils::SYMBOL_TO_STATUS_CODE.find do |_, c|
|
|
189
|
+
c == code
|
|
190
|
+
end
|
|
191
|
+
status
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# @return [String] pretty format the actual response status
|
|
195
|
+
def pp_actual
|
|
196
|
+
pp_status(actual_status, actual)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# @return [String] pretty format the expected status and associated code
|
|
200
|
+
def pp_expected
|
|
201
|
+
pp_status(expected_status, expected)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# @return [String] pretty format the actual response status
|
|
205
|
+
def pp_status(status, code)
|
|
206
|
+
if status
|
|
207
|
+
"#{status.inspect} (#{code})"
|
|
208
|
+
else
|
|
209
|
+
code.to_s
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Sets `expected` to the numeric http code based on the Rack
|
|
214
|
+
# `expected_status` status
|
|
215
|
+
#
|
|
216
|
+
# @see Rack::Utils::SYMBOL_TO_STATUS_CODE
|
|
217
|
+
# @raise [ArgumentError] if an associated code could not be found
|
|
218
|
+
def set_expected_code!
|
|
219
|
+
@expected ||= Rack::Utils.status_code(expected_status)
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# @api private
|
|
224
|
+
# Provides an implementation for `have_http_status` matching against
|
|
225
|
+
# `ActionDispatch::TestResponse` http status category queries.
|
|
226
|
+
#
|
|
227
|
+
# Not intended to be instantiated directly.
|
|
228
|
+
#
|
|
229
|
+
# @example
|
|
230
|
+
# expect(response).to have_http_status(:success)
|
|
231
|
+
# expect(response).to have_http_status(:error)
|
|
232
|
+
# expect(response).to have_http_status(:missing)
|
|
233
|
+
# expect(response).to have_http_status(:redirect)
|
|
234
|
+
#
|
|
235
|
+
# @see RSpec::Rails::Matchers#have_http_status
|
|
236
|
+
# @see https://github.com/rails/rails/blob/7-2-stable/actionpack/lib/action_dispatch/testing/test_response.rb `ActionDispatch::TestResponse`
|
|
237
|
+
class GenericStatus < RSpec::Rails::Matchers::BaseMatcher
|
|
238
|
+
include HaveHttpStatus
|
|
239
|
+
|
|
240
|
+
# @return [Array<Symbol>] of status codes which represent a HTTP status
|
|
241
|
+
# code "group"
|
|
242
|
+
# @see https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/testing/test_response.rb `ActionDispatch::TestResponse`
|
|
243
|
+
def self.valid_statuses
|
|
244
|
+
[
|
|
245
|
+
:error, :success, :missing,
|
|
246
|
+
:server_error, :successful, :not_found,
|
|
247
|
+
:redirect
|
|
248
|
+
]
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def initialize(type)
|
|
252
|
+
unless self.class.valid_statuses.include?(type)
|
|
253
|
+
raise ArgumentError, "Invalid generic HTTP status: #{type.inspect}"
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
@expected = type
|
|
257
|
+
@actual = nil
|
|
258
|
+
@invalid_response = nil
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# @return [Boolean] `true` if Rack's associated numeric HTTP code matched
|
|
262
|
+
# the `response` code or the named response status
|
|
263
|
+
def matches?(response)
|
|
264
|
+
test_response = as_test_response(response)
|
|
265
|
+
@actual = test_response.response_code
|
|
266
|
+
check_expected_status(test_response, expected)
|
|
267
|
+
rescue TypeError => _ignored
|
|
268
|
+
@invalid_response = response
|
|
269
|
+
false
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# @return [String]
|
|
273
|
+
def description
|
|
274
|
+
"respond with #{type_message}"
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# @return [String] explaining why the match failed
|
|
278
|
+
def failure_message
|
|
279
|
+
invalid_response_type_message ||
|
|
280
|
+
"expected the response to have #{type_message} but it was #{actual}"
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# @return [String] explaining why the match failed
|
|
284
|
+
def failure_message_when_negated
|
|
285
|
+
invalid_response_type_message ||
|
|
286
|
+
"expected the response not to have #{type_message} but it was #{actual}"
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
protected
|
|
290
|
+
|
|
291
|
+
RESPONSE_METHODS = {
|
|
292
|
+
success: 'successful',
|
|
293
|
+
error: 'server_error',
|
|
294
|
+
missing: 'not_found'
|
|
295
|
+
}.freeze
|
|
296
|
+
|
|
297
|
+
def check_expected_status(test_response, expected)
|
|
298
|
+
test_response.send(
|
|
299
|
+
"#{RESPONSE_METHODS.fetch(expected, expected)}?")
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
private
|
|
303
|
+
|
|
304
|
+
# @return [String] formatting the expected status and associated code(s)
|
|
305
|
+
def type_message
|
|
306
|
+
@type_message ||= (expected == :error ? "an error" : "a #{expected}") +
|
|
307
|
+
" status code (#{type_codes})"
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# @return [String] formatting the associated code(s) for the various
|
|
311
|
+
# status code "groups"
|
|
312
|
+
# @see https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/testing/test_response.rb `ActionDispatch::TestResponse`
|
|
313
|
+
# @see https://github.com/rack/rack/blob/master/lib/rack/response.rb `Rack::Response`
|
|
314
|
+
def type_codes
|
|
315
|
+
# At the time of this commit the most recent version of
|
|
316
|
+
# `ActionDispatch::TestResponse` defines the following aliases:
|
|
317
|
+
#
|
|
318
|
+
# alias_method :success?, :successful?
|
|
319
|
+
# alias_method :missing?, :not_found?
|
|
320
|
+
# alias_method :redirect?, :redirection?
|
|
321
|
+
# alias_method :error?, :server_error?
|
|
322
|
+
#
|
|
323
|
+
# It's parent `ActionDispatch::Response` includes
|
|
324
|
+
# `Rack::Response::Helpers` which defines the aliased methods as:
|
|
325
|
+
#
|
|
326
|
+
# def successful?; status >= 200 && status < 300; end
|
|
327
|
+
# def redirection?; status >= 300 && status < 400; end
|
|
328
|
+
# def server_error?; status >= 500 && status < 600; end
|
|
329
|
+
# def not_found?; status == 404; end
|
|
330
|
+
#
|
|
331
|
+
# @see https://github.com/rails/rails/blob/ca200378/actionpack/lib/action_dispatch/testing/test_response.rb#L17-L27
|
|
332
|
+
# @see https://github.com/rails/rails/blob/ca200378/actionpack/lib/action_dispatch/http/response.rb#L74
|
|
333
|
+
# @see https://github.com/rack/rack/blob/ce4a3959/lib/rack/response.rb#L119-L122
|
|
334
|
+
@type_codes ||= case expected
|
|
335
|
+
when :error, :server_error
|
|
336
|
+
"5xx"
|
|
337
|
+
when :success, :successful
|
|
338
|
+
"2xx"
|
|
339
|
+
when :missing, :not_found
|
|
340
|
+
"404"
|
|
341
|
+
when :redirect
|
|
342
|
+
"3xx"
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# @api public
|
|
349
|
+
# Passes if `response` has a matching HTTP status code.
|
|
350
|
+
#
|
|
351
|
+
# The following symbolic status codes are allowed:
|
|
352
|
+
#
|
|
353
|
+
# - `Rack::Utils::SYMBOL_TO_STATUS_CODE`
|
|
354
|
+
# - One of the defined `ActionDispatch::TestResponse` aliases:
|
|
355
|
+
# - `:error`
|
|
356
|
+
# - `:missing`
|
|
357
|
+
# - `:redirect`
|
|
358
|
+
# - `:success`
|
|
359
|
+
#
|
|
360
|
+
# @example Accepts numeric and symbol statuses
|
|
361
|
+
# expect(response).to have_http_status(404)
|
|
362
|
+
# expect(response).to have_http_status(:created)
|
|
363
|
+
# expect(response).to have_http_status(:success)
|
|
364
|
+
# expect(response).to have_http_status(:error)
|
|
365
|
+
# expect(response).to have_http_status(:missing)
|
|
366
|
+
# expect(response).to have_http_status(:redirect)
|
|
367
|
+
#
|
|
368
|
+
# @example Works with standard `response` objects and Capybara's `page`
|
|
369
|
+
# expect(response).to have_http_status(404)
|
|
370
|
+
# expect(page).to have_http_status(:created)
|
|
371
|
+
#
|
|
372
|
+
# @see https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/testing/test_response.rb `ActionDispatch::TestResponse`
|
|
373
|
+
# @see https://github.com/rack/rack/blob/master/lib/rack/utils.rb `Rack::Utils::SYMBOL_TO_STATUS_CODE`
|
|
374
|
+
def have_http_status(target)
|
|
375
|
+
raise ArgumentError, "Invalid HTTP status: nil" unless target
|
|
376
|
+
|
|
377
|
+
HaveHttpStatus.matcher_for_status(target)
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Rails
|
|
3
|
+
module Matchers
|
|
4
|
+
# Matcher for template rendering.
|
|
5
|
+
module RenderTemplate
|
|
6
|
+
# @private
|
|
7
|
+
class RenderTemplateMatcher < RSpec::Rails::Matchers::BaseMatcher
|
|
8
|
+
def initialize(scope, expected, message = nil)
|
|
9
|
+
@expected = Symbol === expected ? expected.to_s : expected
|
|
10
|
+
@message = message
|
|
11
|
+
@scope = scope
|
|
12
|
+
@redirect_is = nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @api private
|
|
16
|
+
def matches?(*)
|
|
17
|
+
match_check = match_unless_raises ActiveSupport::TestCase::Assertion do
|
|
18
|
+
@scope.assert_template expected, @message
|
|
19
|
+
end
|
|
20
|
+
check_redirect unless match_check
|
|
21
|
+
match_check
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Uses normalize_argument_to_redirection to find and format
|
|
25
|
+
# the redirect location. normalize_argument_to_redirection is private
|
|
26
|
+
# in ActionDispatch::Assertions::ResponseAssertions so we call it
|
|
27
|
+
# here using #send. This will keep the error message format consistent
|
|
28
|
+
# @api private
|
|
29
|
+
def check_redirect
|
|
30
|
+
response = @scope.response
|
|
31
|
+
return unless response.respond_to?(:redirect?) && response.redirect?
|
|
32
|
+
|
|
33
|
+
@redirect_is = @scope.send(:normalize_argument_to_redirection, response.location)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @api private
|
|
37
|
+
def failure_message
|
|
38
|
+
if @redirect_is
|
|
39
|
+
rescued_exception.message[/(.*?)( but|$)/, 1] +
|
|
40
|
+
" but was a redirect to <#{@redirect_is}>"
|
|
41
|
+
else
|
|
42
|
+
rescued_exception.message
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @api private
|
|
47
|
+
def failure_message_when_negated
|
|
48
|
+
"expected not to render #{expected.inspect}, but did"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Delegates to `assert_template`.
|
|
53
|
+
#
|
|
54
|
+
# @example
|
|
55
|
+
# expect(response).to have_rendered("new")
|
|
56
|
+
def have_rendered(options, message = nil)
|
|
57
|
+
RenderTemplateMatcher.new(self, options, message)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
alias_method :render_template, :have_rendered
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Rails
|
|
3
|
+
module Matchers
|
|
4
|
+
# Matcher for redirects.
|
|
5
|
+
module RedirectTo
|
|
6
|
+
# @private
|
|
7
|
+
class RedirectTo < RSpec::Rails::Matchers::BaseMatcher
|
|
8
|
+
def initialize(scope, expected)
|
|
9
|
+
@expected = expected
|
|
10
|
+
@scope = scope
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def matches?(_)
|
|
14
|
+
match_unless_raises ActiveSupport::TestCase::Assertion do
|
|
15
|
+
@scope.assert_redirected_to(@expected)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def failure_message
|
|
20
|
+
rescued_exception.message
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def failure_message_when_negated
|
|
24
|
+
"expected not to redirect to #{@expected.inspect}, but did"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Delegates to `assert_redirected_to`.
|
|
29
|
+
#
|
|
30
|
+
# @example
|
|
31
|
+
# expect(response).to redirect_to(:action => "new")
|
|
32
|
+
def redirect_to(target)
|
|
33
|
+
RedirectTo.new(self, target)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Rails
|
|
3
|
+
module Matchers
|
|
4
|
+
# Matchers to help with specs for routing code.
|
|
5
|
+
module RoutingMatchers
|
|
6
|
+
extend RSpec::Matchers::DSL
|
|
7
|
+
|
|
8
|
+
# @private
|
|
9
|
+
class RouteToMatcher < RSpec::Rails::Matchers::BaseMatcher
|
|
10
|
+
def initialize(scope, *expected)
|
|
11
|
+
@scope = scope
|
|
12
|
+
@expected = expected[1] || {}
|
|
13
|
+
if Hash === expected[0]
|
|
14
|
+
@expected.merge!(expected[0])
|
|
15
|
+
else
|
|
16
|
+
controller, action = expected[0].split('#')
|
|
17
|
+
@expected.merge!(controller: controller, action: action)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def matches?(verb_to_path_map)
|
|
22
|
+
@actual = verb_to_path_map
|
|
23
|
+
# assert_recognizes does not consider ActionController::RoutingError an
|
|
24
|
+
# assertion failure, so we have to capture that and Assertion here.
|
|
25
|
+
match_unless_raises ActiveSupport::TestCase::Assertion, ActionController::RoutingError do
|
|
26
|
+
path, query = *verb_to_path_map.values.first.split('?')
|
|
27
|
+
@scope.assert_recognizes(
|
|
28
|
+
@expected,
|
|
29
|
+
{ method: verb_to_path_map.keys.first, path: path },
|
|
30
|
+
Rack::Utils.parse_nested_query(query)
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def failure_message
|
|
36
|
+
rescued_exception.message
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def failure_message_when_negated
|
|
40
|
+
"expected #{@actual.inspect} not to route to #{@expected.inspect}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def description
|
|
44
|
+
"route #{@actual.inspect} to #{@expected.inspect}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Delegates to `assert_recognizes`. Supports short-hand controller/action
|
|
49
|
+
# declarations (e.g. `"controller#action"`).
|
|
50
|
+
#
|
|
51
|
+
# @example
|
|
52
|
+
#
|
|
53
|
+
# expect(get: "/things/special").to route_to(
|
|
54
|
+
# controller: "things",
|
|
55
|
+
# action: "special"
|
|
56
|
+
# )
|
|
57
|
+
#
|
|
58
|
+
# expect(get: "/things/special").to route_to("things#special")
|
|
59
|
+
#
|
|
60
|
+
# @see https://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_recognizes
|
|
61
|
+
def route_to(*expected)
|
|
62
|
+
RouteToMatcher.new(self, *expected)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @private
|
|
66
|
+
class BeRoutableMatcher < RSpec::Rails::Matchers::BaseMatcher
|
|
67
|
+
def initialize(scope)
|
|
68
|
+
@scope = scope
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def matches?(path)
|
|
72
|
+
@actual = path
|
|
73
|
+
match_unless_raises ActionController::RoutingError do
|
|
74
|
+
@routing_options = @scope.routes.recognize_path(
|
|
75
|
+
path.values.first, method: path.keys.first
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def failure_message
|
|
81
|
+
"expected #{@actual.inspect} to be routable"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def failure_message_when_negated
|
|
85
|
+
"expected #{@actual.inspect} not to be routable, but it routes to #{@routing_options.inspect}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def description
|
|
89
|
+
"be routable"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Passes if the route expression is recognized by the Rails router based on
|
|
94
|
+
# the declarations in `config/routes.rb`. Delegates to
|
|
95
|
+
# `RouteSet#recognize_path`.
|
|
96
|
+
#
|
|
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
|
|
101
|
+
def be_routable
|
|
102
|
+
BeRoutableMatcher.new(self)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Helpers for matching different route types.
|
|
106
|
+
module RouteHelpers
|
|
107
|
+
# @!method get
|
|
108
|
+
# @!method post
|
|
109
|
+
# @!method put
|
|
110
|
+
# @!method patch
|
|
111
|
+
# @!method delete
|
|
112
|
+
# @!method options
|
|
113
|
+
# @!method head
|
|
114
|
+
#
|
|
115
|
+
# Shorthand method for matching this type of route.
|
|
116
|
+
%w[get post put patch delete options head].each do |method|
|
|
117
|
+
define_method method do |path|
|
|
118
|
+
{ method.to_sym => path }
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|