shoulda-matchers 3.0.0.rc1 → 3.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
- data/Gemfile +2 -3
- data/Gemfile.lock +12 -41
- data/NEWS.md +118 -26
- data/README.md +34 -11
- data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +0 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/style.css +4 -0
- data/gemfiles/4.0.0.gemfile +2 -3
- data/gemfiles/4.0.0.gemfile.lock +47 -77
- data/gemfiles/4.0.1.gemfile +2 -3
- data/gemfiles/4.0.1.gemfile.lock +51 -79
- data/gemfiles/4.1.gemfile +2 -3
- data/gemfiles/4.1.gemfile.lock +73 -103
- data/gemfiles/4.2.gemfile +2 -3
- data/gemfiles/4.2.gemfile.lock +90 -124
- data/lib/shoulda/matchers.rb +1 -0
- data/lib/shoulda/matchers/action_controller/callback_matcher.rb +6 -8
- data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +1 -3
- data/lib/shoulda/matchers/action_controller/flash_store.rb +1 -8
- data/lib/shoulda/matchers/action_controller/permit_matcher.rb +140 -88
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +2 -5
- data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +5 -10
- data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +2 -4
- data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +1 -3
- data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +3 -5
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +5 -7
- data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +35 -9
- data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +3 -3
- data/lib/shoulda/matchers/active_model.rb +57 -1
- data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +2 -5
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +162 -54
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +5 -2
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +1 -3
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +24 -11
- data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +4 -3
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +0 -2
- data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +4 -3
- data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +2 -1
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +15 -13
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +3 -3
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +3 -3
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +4 -4
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +8 -8
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +8 -8
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +12 -14
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +10 -4
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +0 -3
- data/lib/shoulda/matchers/active_model/validator.rb +0 -8
- data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +4 -6
- data/lib/shoulda/matchers/active_record/association_matcher.rb +58 -43
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +2 -2
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +3 -5
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +3 -5
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +1 -4
- data/lib/shoulda/matchers/active_record/serialize_matcher.rb +3 -5
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +7 -7
- data/lib/shoulda/matchers/doublespeak/double.rb +10 -1
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +13 -5
- data/lib/shoulda/matchers/doublespeak/method_call.rb +10 -1
- data/lib/shoulda/matchers/doublespeak/object_double.rb +2 -1
- data/lib/shoulda/matchers/doublespeak/world.rb +10 -0
- data/lib/shoulda/matchers/error.rb +4 -0
- data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +11 -10
- data/lib/shoulda/matchers/integrations/libraries.rb +1 -0
- data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
- data/lib/shoulda/matchers/integrations/libraries/active_model.rb +1 -1
- data/lib/shoulda/matchers/integrations/libraries/active_record.rb +1 -1
- data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -1
- data/lib/shoulda/matchers/integrations/libraries/routing.rb +27 -0
- data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
- data/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb +2 -2
- data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
- data/lib/shoulda/matchers/routing.rb +10 -0
- data/lib/shoulda/matchers/version.rb +1 -1
- data/script/SUPPORTED_VERSIONS +1 -1
- data/spec/acceptance/independent_matchers_spec.rb +103 -42
- data/spec/doublespeak_spec_helper.rb +5 -1
- data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +34 -11
- data/spec/support/acceptance/helpers/rspec_helpers.rb +9 -13
- data/spec/support/acceptance/helpers/step_helpers.rb +13 -0
- data/spec/support/acceptance/matchers/have_output.rb +1 -1
- data/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +1 -1
- data/spec/support/tests/command_runner.rb +5 -1
- data/spec/support/unit/helpers/active_record_versions.rb +0 -4
- data/spec/support/unit/shared_examples/set_session_or_flash.rb +8 -3
- data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +198 -39
- data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +269 -102
- data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +24 -0
- data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +118 -101
- data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +0 -82
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +148 -121
- data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +20 -8
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +64 -183
- data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +14 -0
- data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +60 -0
- data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +23 -7
- data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +242 -0
- data/spec/unit_spec_helper.rb +4 -0
- data/tasks/documentation.rb +35 -0
- metadata +9 -8
- data/Guardfile +0 -5
- data/cucumber.yml +0 -1
- data/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb +0 -12
@@ -40,7 +40,7 @@ module AcceptanceTests
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def expected_output
|
43
|
-
/#{number} (tests
|
43
|
+
/#{number} (?:tests?|runs?|examples?)(?:, #{number} assertions)?, 0 failures(?:, 0 errors(?:, 0 skips)?)?/
|
44
44
|
end
|
45
45
|
|
46
46
|
def actual_output
|
@@ -56,9 +56,14 @@ shared_examples_for 'set session or flash matcher' do
|
|
56
56
|
|
57
57
|
context 'in the positive' do
|
58
58
|
context 'if the given key is present in the store' do
|
59
|
-
it 'accepts' do
|
60
|
-
controller = controller_with_store('
|
61
|
-
expect(controller).to set_store['
|
59
|
+
it 'accepts the param as a string' do
|
60
|
+
controller = controller_with_store('the_key' => 'any value')
|
61
|
+
expect(controller).to set_store['the_key']
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'accepts the param as a symbol' do
|
65
|
+
controller = controller_with_store('the_key' => 'any value')
|
66
|
+
expect(controller).to set_store[:the_key]
|
62
67
|
end
|
63
68
|
end
|
64
69
|
|
@@ -7,7 +7,7 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
7
7
|
params_with_conditional_require(ctrl.params).permit(:name, :age)
|
8
8
|
end
|
9
9
|
|
10
|
-
expect(controller).to
|
10
|
+
expect(controller).to permit_with_conditional_slice_of_params(
|
11
11
|
permit(:name).for(:create)
|
12
12
|
)
|
13
13
|
end
|
@@ -17,7 +17,7 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
17
17
|
params_with_conditional_require(ctrl.params).permit(:name, :age)
|
18
18
|
end
|
19
19
|
|
20
|
-
expect(controller).to
|
20
|
+
expect(controller).to permit_with_conditional_slice_of_params(
|
21
21
|
permit(:name, :age).for(:create)
|
22
22
|
)
|
23
23
|
end
|
@@ -27,7 +27,7 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
27
27
|
params_with_conditional_require(ctrl.params).permit(:name)
|
28
28
|
end
|
29
29
|
|
30
|
-
expect(controller).not_to
|
30
|
+
expect(controller).not_to permit_with_conditional_slice_of_params(
|
31
31
|
permit(:name, :admin).for(:create)
|
32
32
|
)
|
33
33
|
end
|
@@ -35,22 +35,17 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
35
35
|
it 'rejects when #permit has not been called' do
|
36
36
|
define_controller_with_strong_parameters(action: :create)
|
37
37
|
|
38
|
-
expect(controller).not_to
|
38
|
+
expect(controller).not_to permit_with_conditional_slice_of_params(
|
39
39
|
permit(:name).for(:create)
|
40
40
|
)
|
41
41
|
end
|
42
42
|
|
43
|
-
it 'tracks multiple calls to #permit' do
|
43
|
+
it 'tracks multiple calls to #permit for different subparameters' do
|
44
44
|
sets_of_attributes = [
|
45
45
|
[:eta, :diner_id],
|
46
46
|
[:phone_number, :address_1, :address_2, :city, :state, :zip]
|
47
47
|
]
|
48
48
|
|
49
|
-
params = {
|
50
|
-
order: { some: 'value' },
|
51
|
-
diner: { some: 'value' }
|
52
|
-
}
|
53
|
-
|
54
49
|
define_controller_with_strong_parameters(action: :create) do |ctrl|
|
55
50
|
params_with_conditional_require(ctrl.params, :order).
|
56
51
|
permit(sets_of_attributes[0])
|
@@ -59,14 +54,16 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
59
54
|
permit(sets_of_attributes[1])
|
60
55
|
end
|
61
56
|
|
62
|
-
expect(controller).to
|
57
|
+
expect(controller).to permit_with_conditional_slice_of_params(
|
63
58
|
permit(*sets_of_attributes[0]).for(:create),
|
64
|
-
|
59
|
+
all_params: [:order, :diner],
|
60
|
+
selected_param: :order
|
65
61
|
)
|
66
62
|
|
67
|
-
expect(controller).to
|
63
|
+
expect(controller).to permit_with_conditional_slice_of_params(
|
68
64
|
permit(*sets_of_attributes[1]).for(:create),
|
69
|
-
|
65
|
+
all_params: [:order, :diner],
|
66
|
+
selected_param: :diner
|
70
67
|
)
|
71
68
|
end
|
72
69
|
end
|
@@ -91,7 +88,7 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
91
88
|
|
92
89
|
context 'when operating on the entire params hash' do
|
93
90
|
include_context 'basic tests' do
|
94
|
-
def
|
91
|
+
def permit_with_conditional_slice_of_params(permit, options = {})
|
95
92
|
permit
|
96
93
|
end
|
97
94
|
|
@@ -103,9 +100,16 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
103
100
|
|
104
101
|
context 'when operating on a slice of the params hash' do
|
105
102
|
include_context 'basic tests' do
|
106
|
-
def
|
107
|
-
|
108
|
-
|
103
|
+
def permit_with_conditional_slice_of_params(
|
104
|
+
permit,
|
105
|
+
all_params: [:user],
|
106
|
+
selected_param: :user
|
107
|
+
)
|
108
|
+
params = all_params.reduce({}) do |hash, param|
|
109
|
+
hash.merge(param => { any: 'value' })
|
110
|
+
end
|
111
|
+
|
112
|
+
permit.add_params(params).on(selected_param)
|
109
113
|
end
|
110
114
|
|
111
115
|
def params_with_conditional_require(params, *filters)
|
@@ -127,6 +131,28 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
127
131
|
for(:create, params: { order: { some: 'value' } }).
|
128
132
|
on(:something_else)
|
129
133
|
end
|
134
|
+
|
135
|
+
it 'tracks multiple calls to #permit for the same subparameter' do
|
136
|
+
define_controller_with_strong_parameters(action: :create) do
|
137
|
+
params.require(:foo).permit(:bar)
|
138
|
+
params.require(:foo).permit(:baz)
|
139
|
+
end
|
140
|
+
|
141
|
+
params = {
|
142
|
+
foo: {
|
143
|
+
bar: 'some value',
|
144
|
+
baz: 'some value'
|
145
|
+
}
|
146
|
+
}
|
147
|
+
expect(controller).
|
148
|
+
to permit(:bar).
|
149
|
+
on(:foo).
|
150
|
+
for(:create, params: params)
|
151
|
+
expect(controller).
|
152
|
+
to permit(:baz).
|
153
|
+
on(:foo).
|
154
|
+
for(:create, params: params)
|
155
|
+
end
|
130
156
|
end
|
131
157
|
|
132
158
|
it 'can be used more than once in the same test' do
|
@@ -138,7 +164,7 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
138
164
|
expect(controller).not_to permit(:admin).for(:create)
|
139
165
|
end
|
140
166
|
|
141
|
-
it 'allows extra parameters to be
|
167
|
+
it 'allows extra parameters to be provided if the route requires them' do
|
142
168
|
options = {
|
143
169
|
controller_name: 'Posts',
|
144
170
|
action: :show,
|
@@ -259,7 +285,7 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
259
285
|
|
260
286
|
matcher = described_class.new([:name, :age, :height]).for(:create)
|
261
287
|
expect(matcher.description).to eq(
|
262
|
-
'(
|
288
|
+
'(for POST #create) restrict parameters to :name, :age, and :height'
|
263
289
|
)
|
264
290
|
end
|
265
291
|
|
@@ -275,50 +301,183 @@ describe Shoulda::Matchers::ActionController::PermitMatcher, type: :controller d
|
|
275
301
|
new([:name]).
|
276
302
|
for(:some_action, verb: :put)
|
277
303
|
expect(matcher.description).to eq(
|
278
|
-
'(
|
304
|
+
'(for PUT #some_action) restrict parameters to :name'
|
279
305
|
)
|
280
306
|
end
|
281
307
|
end
|
282
308
|
end
|
283
309
|
|
284
310
|
describe 'positive failure message' do
|
285
|
-
|
286
|
-
|
287
|
-
|
311
|
+
context 'when no parameters were permitted' do
|
312
|
+
it 'returns the correct message' do
|
313
|
+
define_controller_with_strong_parameters(action: :create)
|
314
|
+
|
315
|
+
assertion = lambda do
|
316
|
+
expect(@controller).
|
317
|
+
to permit(:name, :age, :city, :country).
|
318
|
+
for(:create)
|
319
|
+
end
|
320
|
+
|
321
|
+
message =
|
322
|
+
'Expected POST #create to restrict parameters to ' +
|
323
|
+
":name, :age, :city, and :country,\n" +
|
324
|
+
'but it did not restrict any parameters.'
|
325
|
+
|
326
|
+
expect(&assertion).to fail_with_message(message)
|
288
327
|
end
|
328
|
+
end
|
289
329
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
330
|
+
context 'when some, but not all, parameters were permitted' do
|
331
|
+
it 'returns the correct message, including missing attributes' do
|
332
|
+
define_controller_with_strong_parameters(action: :create) do
|
333
|
+
params.permit(:name, :age)
|
334
|
+
end
|
335
|
+
|
336
|
+
assertion = lambda do
|
337
|
+
expect(@controller).
|
338
|
+
to permit(:name, :age, :city, :country).
|
339
|
+
for(:create)
|
340
|
+
end
|
341
|
+
|
342
|
+
message =
|
343
|
+
'Expected POST #create to restrict parameters to ' +
|
344
|
+
":name, :age, :city, and :country,\n" +
|
345
|
+
'but the restricted parameters were :name and :age instead.'
|
346
|
+
|
347
|
+
expect(&assertion).to fail_with_message(message)
|
294
348
|
end
|
349
|
+
end
|
295
350
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
351
|
+
context 'qualified with #on' do
|
352
|
+
context 'when the subparameter was never required' do
|
353
|
+
it 'returns the correct message' do
|
354
|
+
define_controller_with_strong_parameters(action: :create) do
|
355
|
+
params.permit(:name, :age)
|
356
|
+
end
|
300
357
|
|
301
|
-
|
358
|
+
assertion = lambda do
|
359
|
+
expect(@controller).
|
360
|
+
to permit(:name, :age, :city, :country).
|
361
|
+
for(:create).
|
362
|
+
on(:person)
|
363
|
+
end
|
364
|
+
|
365
|
+
message =
|
366
|
+
'Expected POST #create to restrict parameters on :person to ' +
|
367
|
+
":name, :age, :city, and :country,\n" +
|
368
|
+
'but it did not restrict any parameters.'
|
369
|
+
|
370
|
+
expect(&assertion).to fail_with_message(message)
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
context 'when the subparameter was required' do
|
375
|
+
context 'but no parameters were permitted' do
|
376
|
+
it 'returns the correct message' do
|
377
|
+
define_controller_with_strong_parameters(action: :create) do
|
378
|
+
params.require(:person)
|
379
|
+
end
|
380
|
+
|
381
|
+
assertion = lambda do
|
382
|
+
params = {
|
383
|
+
person: {
|
384
|
+
name: 'some name',
|
385
|
+
age: 'some age'
|
386
|
+
}
|
387
|
+
}
|
388
|
+
expect(@controller).
|
389
|
+
to permit(:name, :age, :city, :country).
|
390
|
+
for(:create, params: params).
|
391
|
+
on(:person)
|
392
|
+
end
|
393
|
+
|
394
|
+
message =
|
395
|
+
'Expected POST #create to restrict parameters on :person to ' +
|
396
|
+
":name, :age, :city, and :country,\n" +
|
397
|
+
'but it did not restrict any parameters.'
|
398
|
+
|
399
|
+
expect(&assertion).to fail_with_message(message)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
context 'but some, but not all, parameters were permitted' do
|
404
|
+
it 'returns the correct message' do
|
405
|
+
define_controller_with_strong_parameters(action: :create) do
|
406
|
+
params.require(:person).permit(:name, :age)
|
407
|
+
end
|
408
|
+
|
409
|
+
assertion = lambda do
|
410
|
+
params = {
|
411
|
+
person: {
|
412
|
+
name: 'some name',
|
413
|
+
age: 'some age'
|
414
|
+
}
|
415
|
+
}
|
416
|
+
expect(@controller).
|
417
|
+
to permit(:name, :age, :city, :country).
|
418
|
+
for(:create, params: params).
|
419
|
+
on(:person)
|
420
|
+
end
|
421
|
+
|
422
|
+
message =
|
423
|
+
'Expected POST #create to restrict parameters on :person to ' +
|
424
|
+
":name, :age, :city, and :country,\n" +
|
425
|
+
'but the restricted parameters were :name and :age instead.'
|
426
|
+
|
427
|
+
expect(&assertion).to fail_with_message(message)
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
302
431
|
end
|
303
432
|
end
|
304
433
|
|
305
434
|
describe 'negative failure message' do
|
306
|
-
it '
|
435
|
+
it 'returns the correct message' do
|
307
436
|
define_controller_with_strong_parameters(action: :create) do
|
308
|
-
params.permit(:name, :age)
|
437
|
+
params.permit(:name, :age, :city, :country)
|
309
438
|
end
|
310
439
|
|
311
440
|
assertion = lambda do
|
312
|
-
expect(controller).
|
441
|
+
expect(@controller).
|
442
|
+
not_to permit(:name, :age, :city, :country).
|
443
|
+
for(:create)
|
313
444
|
end
|
314
445
|
|
315
446
|
message =
|
316
|
-
|
317
|
-
":name and :
|
318
|
-
|
447
|
+
'Expected POST #create not to restrict parameters to ' +
|
448
|
+
":name, :age, :city, and :country,\n" +
|
449
|
+
'but it did.'
|
319
450
|
|
320
451
|
expect(&assertion).to fail_with_message(message)
|
321
452
|
end
|
453
|
+
|
454
|
+
context 'qualified with #on' do
|
455
|
+
it 'returns the correct message' do
|
456
|
+
define_controller_with_strong_parameters(action: :create) do
|
457
|
+
params.require(:person).permit(:name, :age)
|
458
|
+
end
|
459
|
+
|
460
|
+
assertion = lambda do
|
461
|
+
params = {
|
462
|
+
person: {
|
463
|
+
name: 'some name',
|
464
|
+
age: 'some age'
|
465
|
+
}
|
466
|
+
}
|
467
|
+
expect(@controller).
|
468
|
+
not_to permit(:name, :age).
|
469
|
+
for(:create, params: params).
|
470
|
+
on(:person)
|
471
|
+
end
|
472
|
+
|
473
|
+
message =
|
474
|
+
'Expected POST #create not to restrict parameters on :person to ' +
|
475
|
+
":name and :age,\n" +
|
476
|
+
'but it did.'
|
477
|
+
|
478
|
+
expect(&assertion).to fail_with_message(message)
|
479
|
+
end
|
480
|
+
end
|
322
481
|
end
|
323
482
|
|
324
483
|
describe '#for' do
|
@@ -1,163 +1,330 @@
|
|
1
1
|
require 'unit_spec_helper'
|
2
2
|
|
3
3
|
describe 'Shoulda::Matchers::ActionController::RouteMatcher', type: :controller do
|
4
|
-
shared_examples_for '
|
5
|
-
|
4
|
+
shared_examples_for 'tests involving expected route parts' do |args|
|
5
|
+
include_controller_in_expected_route_options =
|
6
|
+
args.fetch(:include_controller_in_expected_route_options)
|
7
|
+
|
8
|
+
context 'when all parts of the expected route match an existing route' do
|
6
9
|
it 'accepts' do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
+
define_route :get, '/', action: 'index'
|
11
|
+
|
12
|
+
assert_accepts add_target_to(
|
13
|
+
route(:get, '/'),
|
14
|
+
build_expected_route_options(
|
15
|
+
include_controller_in_expected_route_options,
|
16
|
+
action: 'index'
|
17
|
+
)
|
18
|
+
)
|
10
19
|
end
|
11
20
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
21
|
+
if include_controller_in_expected_route_options
|
22
|
+
context 'and the expected controller is specified as a symbol' do
|
23
|
+
it 'accepts' do
|
24
|
+
define_route :get, '/', action: 'index'
|
25
|
+
|
26
|
+
assert_accepts add_target_to(
|
27
|
+
route(:get, '/'),
|
28
|
+
build_expected_route_options(
|
29
|
+
include_controller_in_expected_route_options,
|
30
|
+
action: 'index'
|
31
|
+
)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
16
35
|
end
|
17
36
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
37
|
+
context 'and the expected action is specified as a symbol' do
|
38
|
+
it 'accepts' do
|
39
|
+
define_route :get, '/', action: 'index'
|
40
|
+
|
41
|
+
assert_accepts add_target_to(
|
42
|
+
route(:get, '/'),
|
43
|
+
build_expected_route_options(
|
44
|
+
include_controller_in_expected_route_options,
|
45
|
+
action: :index
|
46
|
+
)
|
47
|
+
)
|
48
|
+
end
|
22
49
|
end
|
50
|
+
end
|
23
51
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
52
|
+
context 'when no parts of the expected route match an existing route' do
|
53
|
+
it 'rejects' do
|
54
|
+
assert_rejects add_target_to(
|
55
|
+
route(:get, '/non_existent_route'),
|
56
|
+
controller: 'no_controller',
|
57
|
+
action: 'no_action'
|
58
|
+
)
|
28
59
|
end
|
60
|
+
end
|
29
61
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
62
|
+
context 'when all parts of the expected route but the method match an existing route' do
|
63
|
+
it 'rejects' do
|
64
|
+
define_route :post, '/', action: 'index'
|
65
|
+
|
66
|
+
assert_rejects add_target_to(
|
67
|
+
route(:get, '/'),
|
68
|
+
build_expected_route_options(
|
69
|
+
include_controller_in_expected_route_options,
|
70
|
+
action: 'index'
|
71
|
+
)
|
72
|
+
)
|
36
73
|
end
|
74
|
+
end
|
37
75
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
76
|
+
context 'when all parts of the expected route but the path match an existing route' do
|
77
|
+
it 'rejects' do
|
78
|
+
define_route :get, '/', action: 'index'
|
79
|
+
|
80
|
+
assert_rejects add_target_to(
|
81
|
+
route(:get, '/different_path'),
|
82
|
+
build_expected_route_options(
|
83
|
+
include_controller_in_expected_route_options,
|
84
|
+
action: 'index'
|
85
|
+
)
|
86
|
+
)
|
87
|
+
end
|
88
|
+
end
|
44
89
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
90
|
+
if include_controller_in_expected_route_options
|
91
|
+
context 'when all parts of the expected route but the controller match an existing route' do
|
92
|
+
it 'rejects' do
|
93
|
+
define_route :get, '/', controller: 'another_controller', action: 'index'
|
94
|
+
|
95
|
+
assert_rejects add_target_to(
|
96
|
+
route(:get, '/'),
|
97
|
+
build_expected_route_options(
|
98
|
+
include_controller_in_expected_route_options,
|
99
|
+
action: 'index'
|
100
|
+
)
|
101
|
+
)
|
49
102
|
end
|
50
103
|
end
|
104
|
+
end
|
51
105
|
|
52
|
-
|
106
|
+
context 'when all parts of the expected route but the action match an existing route' do
|
107
|
+
it 'rejects' do
|
108
|
+
define_route :get, '/', action: 'index'
|
109
|
+
|
110
|
+
assert_rejects add_target_to(
|
111
|
+
route(:get, '/'),
|
112
|
+
build_expected_route_options(
|
113
|
+
include_controller_in_expected_route_options,
|
114
|
+
action: 'another_action'
|
115
|
+
)
|
116
|
+
)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
shared_examples_for 'tests involving params' do
|
122
|
+
context 'when the actual route has a param' do
|
123
|
+
context 'and the expected params include that param' do
|
53
124
|
it 'accepts' do
|
54
|
-
|
55
|
-
|
56
|
-
|
125
|
+
define_route :get, "/#{controller_name}/:id", action: 'show'
|
126
|
+
|
127
|
+
assert_accepts add_target_to(
|
128
|
+
route(:get, "/#{controller_name}/1"),
|
129
|
+
controller: controller_name,
|
130
|
+
action: 'show',
|
131
|
+
id: '1'
|
132
|
+
)
|
57
133
|
end
|
58
134
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
135
|
+
context 'but its value was not specified as a string' do
|
136
|
+
it 'accepts, treating it as a string' do
|
137
|
+
define_route :get, "/#{controller_name}/:id", action: 'show'
|
138
|
+
|
139
|
+
assert_accepts add_target_to(
|
140
|
+
route(:get, "/#{controller_name}/1"),
|
141
|
+
controller: controller_name,
|
142
|
+
action: 'show',
|
143
|
+
id: 1
|
144
|
+
)
|
145
|
+
end
|
63
146
|
end
|
147
|
+
end
|
64
148
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
149
|
+
context 'and the expected params do not match the actual params' do
|
150
|
+
it 'rejects' do
|
151
|
+
define_route :get, "/#{controller_name}/:id", action: 'show'
|
152
|
+
|
153
|
+
params = {
|
154
|
+
controller: controller_name,
|
155
|
+
action: 'show',
|
156
|
+
some: 'other',
|
157
|
+
params: 'here'
|
158
|
+
}
|
159
|
+
assert_rejects add_target_to(
|
160
|
+
route(:get, "/#{controller_name}/:id"),
|
161
|
+
params
|
162
|
+
)
|
69
163
|
end
|
70
164
|
end
|
71
165
|
end
|
72
166
|
|
73
|
-
context 'when
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
167
|
+
context 'when the actual route has a default param whose value is a symbol' do
|
168
|
+
context 'and the expected params include a value for it' do
|
169
|
+
context 'as a symbol' do
|
170
|
+
it 'accepts' do
|
171
|
+
define_route :post, "/#{controller_name}/(.:format)",
|
172
|
+
action: 'create',
|
173
|
+
defaults: { format: :json }
|
174
|
+
|
175
|
+
assert_accepts add_target_to(
|
176
|
+
route(:post, "/#{controller_name}"),
|
177
|
+
controller: controller_name,
|
178
|
+
action: 'create',
|
179
|
+
format: :json
|
180
|
+
)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context 'as a string' do
|
185
|
+
it 'accepts' do
|
186
|
+
define_route :post, "/#{controller_name}/(.:format)",
|
187
|
+
action: 'create',
|
188
|
+
defaults: { format: :json }
|
79
189
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
190
|
+
assert_accepts add_target_to(
|
191
|
+
route(:post, "/#{controller_name}"),
|
192
|
+
controller: controller_name,
|
193
|
+
action: 'create',
|
194
|
+
format: 'json'
|
195
|
+
)
|
196
|
+
end
|
85
197
|
end
|
86
198
|
end
|
199
|
+
end
|
87
200
|
|
88
|
-
|
201
|
+
context 'when the existing route has a glob segment' do
|
202
|
+
context 'and a param is given which represents the segment' do
|
89
203
|
it 'accepts' do
|
90
|
-
|
91
|
-
|
92
|
-
|
204
|
+
define_route :get, "/#{controller_name}/*id", action: 'whatever'
|
205
|
+
|
206
|
+
assert_accepts add_target_to(
|
207
|
+
route(:get, "/#{controller_name}/foo/bar"),
|
208
|
+
controller: controller_name,
|
209
|
+
action: 'whatever',
|
210
|
+
id: 'foo/bar'
|
211
|
+
)
|
93
212
|
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'and no param is given which represents the segment' do
|
216
|
+
it 'rejects' do
|
217
|
+
define_route :get, "/#{controller_name}/*id", action: 'whatever'
|
94
218
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
219
|
+
assert_rejects add_target_to(
|
220
|
+
route(:get, "/#{controller_name}"),
|
221
|
+
controller: controller_name,
|
222
|
+
action: 'whatever'
|
223
|
+
)
|
99
224
|
end
|
100
225
|
end
|
101
226
|
end
|
227
|
+
end
|
102
228
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
setup_rails_controller_test(controller_class)
|
229
|
+
shared_examples_for 'core tests' do
|
230
|
+
context 'given a controller and action specified as individual options' do
|
231
|
+
include_examples 'tests involving expected route parts',
|
232
|
+
include_controller_in_expected_route_options: true
|
109
233
|
|
110
|
-
|
111
|
-
get "/#{_controller_path}", to: "#{_controller_path}#index"
|
112
|
-
get "/#{_controller_path}/:id", to: "#{_controller_path}#show"
|
113
|
-
post "/#{_controller_path}",
|
114
|
-
to: "#{_controller_path}#create",
|
115
|
-
defaults: { format: :json }
|
116
|
-
end
|
234
|
+
include_examples 'tests involving params'
|
117
235
|
|
118
|
-
|
236
|
+
def add_target_to(route_matcher, params)
|
237
|
+
route_matcher.to(params)
|
119
238
|
end
|
120
239
|
end
|
121
240
|
|
122
|
-
|
123
|
-
|
241
|
+
context 'given a controller and action joined together in a string' do
|
242
|
+
include_examples 'tests involving expected route parts',
|
243
|
+
include_controller_in_expected_route_options: true
|
244
|
+
|
245
|
+
include_examples 'tests involving params'
|
246
|
+
|
247
|
+
def add_target_to(route_matcher, args)
|
248
|
+
controller = args.fetch(:controller)
|
249
|
+
action = args.fetch(:action)
|
250
|
+
route_matcher.to("#{controller}##{action}", args)
|
251
|
+
end
|
124
252
|
end
|
125
253
|
|
126
|
-
|
127
|
-
|
128
|
-
|
254
|
+
context 'given just an action' do
|
255
|
+
include_examples 'tests involving expected route parts',
|
256
|
+
include_controller_in_expected_route_options: false
|
129
257
|
|
130
|
-
|
131
|
-
it 'accepts glob route' do
|
132
|
-
controller_class = define_controller('Examples')
|
133
|
-
setup_rails_controller_test(controller_class)
|
258
|
+
include_examples 'tests involving params'
|
134
259
|
|
135
|
-
|
136
|
-
|
260
|
+
def add_target_to(route_matcher, params)
|
261
|
+
route_matcher.to(params)
|
137
262
|
end
|
138
|
-
|
139
|
-
expect(controller).to route(:get, '/examples/foo/bar').
|
140
|
-
to(action: 'example', id: 'foo/bar')
|
141
263
|
end
|
142
264
|
end
|
143
265
|
|
266
|
+
before do
|
267
|
+
setup_rails_controller_test(controller_class)
|
268
|
+
end
|
269
|
+
|
144
270
|
context 'given a controller that is not namespaced' do
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
271
|
+
include_examples 'core tests'
|
272
|
+
|
273
|
+
def controller_class_name
|
274
|
+
'ExamplesController'
|
149
275
|
end
|
150
276
|
end
|
151
277
|
|
152
278
|
context 'given a controller that is namespaced' do
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
279
|
+
def define_controller_under_test
|
280
|
+
define_module('Admin')
|
281
|
+
super
|
282
|
+
end
|
283
|
+
|
284
|
+
include_examples 'core tests'
|
157
285
|
|
158
|
-
|
159
|
-
|
286
|
+
def controller_class_name
|
287
|
+
'Admin::ExamplesController'
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
let(:controller_class) do
|
292
|
+
define_controller_under_test
|
293
|
+
end
|
294
|
+
|
295
|
+
def define_controller_under_test
|
296
|
+
define_controller(controller_class_name)
|
297
|
+
end
|
298
|
+
|
299
|
+
def controller_name
|
300
|
+
controller_class_name.sub(/Controller$/, '').underscore
|
301
|
+
end
|
302
|
+
|
303
|
+
def define_route(method, path, args)
|
304
|
+
action = args.fetch(:action)
|
305
|
+
controller = args.fetch(:controller) { controller_name }
|
306
|
+
define_routes do
|
307
|
+
public_send(
|
308
|
+
method,
|
309
|
+
path,
|
310
|
+
args.merge(controller: controller, action: action)
|
311
|
+
)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def build_expected_route_options(include_controller_in_expected_route_options, default_options)
|
316
|
+
default_options.dup.tap do |options|
|
317
|
+
if include_controller_in_expected_route_options
|
318
|
+
options[:controller] = controller_name
|
160
319
|
end
|
161
320
|
end
|
162
321
|
end
|
322
|
+
|
323
|
+
def assert_accepts(matcher)
|
324
|
+
expect(controller).to matcher
|
325
|
+
end
|
326
|
+
|
327
|
+
def assert_rejects(matcher)
|
328
|
+
expect(controller).not_to matcher
|
329
|
+
end
|
163
330
|
end
|