shoulda-matchers 3.0.0.rc1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -3
  3. data/Gemfile.lock +12 -41
  4. data/NEWS.md +118 -26
  5. data/README.md +34 -11
  6. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +0 -0
  7. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +4 -0
  8. data/gemfiles/4.0.0.gemfile +2 -3
  9. data/gemfiles/4.0.0.gemfile.lock +47 -77
  10. data/gemfiles/4.0.1.gemfile +2 -3
  11. data/gemfiles/4.0.1.gemfile.lock +51 -79
  12. data/gemfiles/4.1.gemfile +2 -3
  13. data/gemfiles/4.1.gemfile.lock +73 -103
  14. data/gemfiles/4.2.gemfile +2 -3
  15. data/gemfiles/4.2.gemfile.lock +90 -124
  16. data/lib/shoulda/matchers.rb +1 -0
  17. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +6 -8
  18. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +1 -3
  19. data/lib/shoulda/matchers/action_controller/flash_store.rb +1 -8
  20. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +140 -88
  21. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +2 -5
  22. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +5 -10
  23. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +2 -4
  24. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +1 -3
  25. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +3 -5
  26. data/lib/shoulda/matchers/action_controller/route_matcher.rb +5 -7
  27. data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +35 -9
  28. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +3 -3
  29. data/lib/shoulda/matchers/active_model.rb +57 -1
  30. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +2 -5
  31. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +162 -54
  32. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +5 -2
  33. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +1 -3
  34. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +24 -11
  35. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +4 -3
  36. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +0 -2
  37. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +4 -3
  38. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +2 -1
  39. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +15 -13
  40. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +3 -3
  41. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +3 -3
  42. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +4 -4
  43. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +8 -8
  44. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +8 -8
  45. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +12 -14
  46. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +10 -4
  47. data/lib/shoulda/matchers/active_model/validation_matcher.rb +0 -3
  48. data/lib/shoulda/matchers/active_model/validator.rb +0 -8
  49. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +4 -6
  50. data/lib/shoulda/matchers/active_record/association_matcher.rb +58 -43
  51. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +2 -2
  52. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +3 -5
  53. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +3 -5
  54. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +1 -4
  55. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +3 -5
  56. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +7 -7
  57. data/lib/shoulda/matchers/doublespeak/double.rb +10 -1
  58. data/lib/shoulda/matchers/doublespeak/double_collection.rb +13 -5
  59. data/lib/shoulda/matchers/doublespeak/method_call.rb +10 -1
  60. data/lib/shoulda/matchers/doublespeak/object_double.rb +2 -1
  61. data/lib/shoulda/matchers/doublespeak/world.rb +10 -0
  62. data/lib/shoulda/matchers/error.rb +4 -0
  63. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +11 -10
  64. data/lib/shoulda/matchers/integrations/libraries.rb +1 -0
  65. data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
  66. data/lib/shoulda/matchers/integrations/libraries/active_model.rb +1 -1
  67. data/lib/shoulda/matchers/integrations/libraries/active_record.rb +1 -1
  68. data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -1
  69. data/lib/shoulda/matchers/integrations/libraries/routing.rb +27 -0
  70. data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
  71. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
  72. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
  73. data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
  74. data/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb +2 -2
  75. data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
  76. data/lib/shoulda/matchers/routing.rb +10 -0
  77. data/lib/shoulda/matchers/version.rb +1 -1
  78. data/script/SUPPORTED_VERSIONS +1 -1
  79. data/spec/acceptance/independent_matchers_spec.rb +103 -42
  80. data/spec/doublespeak_spec_helper.rb +5 -1
  81. data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +34 -11
  82. data/spec/support/acceptance/helpers/rspec_helpers.rb +9 -13
  83. data/spec/support/acceptance/helpers/step_helpers.rb +13 -0
  84. data/spec/support/acceptance/matchers/have_output.rb +1 -1
  85. data/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +1 -1
  86. data/spec/support/tests/command_runner.rb +5 -1
  87. data/spec/support/unit/helpers/active_record_versions.rb +0 -4
  88. data/spec/support/unit/shared_examples/set_session_or_flash.rb +8 -3
  89. data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +198 -39
  90. data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +269 -102
  91. data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +24 -0
  92. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +118 -101
  93. data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +0 -82
  94. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +148 -121
  95. data/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +20 -8
  96. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +64 -183
  97. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +14 -0
  98. data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +60 -0
  99. data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +23 -7
  100. data/spec/unit/shoulda/matchers/routing/route_matcher_spec.rb +242 -0
  101. data/spec/unit_spec_helper.rb +4 -0
  102. data/tasks/documentation.rb +35 -0
  103. metadata +9 -8
  104. data/Guardfile +0 -5
  105. data/cucumber.yml +0 -1
  106. data/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb +0 -12
@@ -18,7 +18,7 @@ module AcceptanceTests
18
18
  "Expected command to have output, but did not.\n\n" +
19
19
  "Command: #{runner.formatted_command}\n\n" +
20
20
  "Expected output:\n" +
21
- output + "\n\n" +
21
+ output.inspect + "\n\n" +
22
22
  "Actual output:\n" +
23
23
  runner.output
24
24
  end
@@ -40,7 +40,7 @@ module AcceptanceTests
40
40
  private
41
41
 
42
42
  def expected_output
43
- /#{number} (tests|runs), #{number} assertions, 0 failures, 0 errors(, 0 skips)?/
43
+ /#{number} (?:tests?|runs?|examples?)(?:, #{number} assertions)?, 0 failures(?:, 0 errors(?:, 0 skips)?)?/
44
44
  end
45
45
 
46
46
  def actual_output
@@ -117,7 +117,11 @@ Output:
117
117
  end
118
118
 
119
119
  def has_output?(expected_output)
120
- output.include?(expected_output)
120
+ if expected_output.is_a?(Regexp)
121
+ output =~ expected_output
122
+ else
123
+ output.include?(expected_output)
124
+ end
121
125
  end
122
126
 
123
127
  protected
@@ -9,10 +9,6 @@ module UnitTests
9
9
  Tests::Version.new(ActiveRecord::VERSION::STRING)
10
10
  end
11
11
 
12
- def active_record_can_raise_range_error?
13
- active_record_version >= 4.2
14
- end
15
-
16
12
  def active_record_supports_enum?
17
13
  defined?(::ActiveRecord::Enum)
18
14
  end
@@ -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('the key' => 'any value')
61
- expect(controller).to set_store['the key']
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 permit_with_conditional_params(
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 permit_with_conditional_params(
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 permit_with_conditional_params(
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 permit_with_conditional_params(
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 permit_with_conditional_params(
57
+ expect(controller).to permit_with_conditional_slice_of_params(
63
58
  permit(*sets_of_attributes[0]).for(:create),
64
- params
59
+ all_params: [:order, :diner],
60
+ selected_param: :order
65
61
  )
66
62
 
67
- expect(controller).to permit_with_conditional_params(
63
+ expect(controller).to permit_with_conditional_slice_of_params(
68
64
  permit(*sets_of_attributes[1]).for(:create),
69
- params
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 permit_with_conditional_params(permit, _params = {})
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 permit_with_conditional_params(permit, params = nil)
107
- params ||= { user: { some: 'value' } }
108
- permit.add_params(params)
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 passed to the action if it requires them' do
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
- '(on POST #create) restrict parameters to :name, :age, and :height'
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
- '(on PUT #some_action) restrict parameters to :name'
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
- it 'includes all missing attributes' do
286
- define_controller_with_strong_parameters(action: :create) do
287
- params.permit(:name, :age)
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
- assertion = lambda do
291
- expect(@controller).
292
- to permit(:name, :age, :city, :country).
293
- for(:create)
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
- message =
297
- "Expected POST #create to restrict parameters to " +
298
- ":name, :age, :city, and :country,\n" +
299
- "but the restricted parameters were :name and :age instead."
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
- expect(&assertion).to fail_with_message(message)
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 'includes all attributes that should not have been permitted but were' do
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).not_to permit(:name, :age).for(:create)
441
+ expect(@controller).
442
+ not_to permit(:name, :age, :city, :country).
443
+ for(:create)
313
444
  end
314
445
 
315
446
  message =
316
- "Expected POST #create not to restrict parameters to " +
317
- ":name and :age,\n" +
318
- "but it did."
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 'a controller with a defined route' do
5
- context 'when controller and action are specified as explicit options' do
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
- expect(controller_with_defined_routes).
8
- to route(:get, "/#{controller_path}").
9
- to(action: 'index')
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
- it 'accepts a symbol controller' do
13
- expect(controller_with_defined_routes).
14
- to route(:get, "/#{controller_path}").
15
- to(controller: controller_path.to_sym, action: 'index')
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
- it 'accepts a symbol action' do
19
- expect(controller_with_defined_routes).
20
- to route(:get, "/#{controller_path}").
21
- to(action: :index)
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
- it 'rejects an undefined route' do
25
- expect(controller_with_defined_routes).
26
- not_to route(:get, '/non_existent_route').
27
- to(action: 'non_existent')
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
- it 'rejects a route for another controller' do
31
- define_controller_with_defined_routes
32
- other_controller = define_controller('Other').new
33
- expect(other_controller).
34
- not_to route(:get, "/#{controller_path}").
35
- to(action: 'index')
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
- context 'when route has parameters' do
39
- it 'accepts a non-string parameter' do
40
- expect(controller_with_defined_routes).
41
- to route(:get, "/#{controller_path}/1").
42
- to(action: 'show', id: 1)
43
- end
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
- it 'rejects a route for different parameters' do
46
- expect(controller_with_defined_routes).
47
- not_to route(:get, "/#{controller_path}/1").
48
- to(action: 'show', some: 'other', params: 'here')
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
- context 'when route has a default format' do
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
- expect(controller_with_defined_routes).
55
- to route(:post, "/#{controller_path}").
56
- to(action: 'create', format: 'json')
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
- it 'accepts when format is specified as a symbol' do
60
- expect(controller_with_defined_routes).
61
- to route(:post, "/#{controller_path}").
62
- to(action: 'create', format: :json)
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
- it 'rejects when format is unspecified' do
66
- expect(controller_with_defined_routes).
67
- not_to route(:post, "/#{controller_path}").
68
- to(action: 'create')
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 controller and action are specified as a joined string' do
74
- it 'accepts' do
75
- expect(controller_with_defined_routes).
76
- to route(:get, "/#{controller_path}").
77
- to("#{controller_path}#index")
78
- end
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
- context 'when route has parameters' do
81
- it 'accepts a non-string parameter' do
82
- expect(controller_with_defined_routes).
83
- to route(:get, "/#{controller_path}/1").
84
- to("#{controller_path}#show", id: 1)
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
- context 'when route has the format' do
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
- expect(controller_with_defined_routes).
91
- to route(:post, "/#{controller_path}").
92
- to("#{controller_path}#create", format: 'json')
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
- it 'rejects when format is unspecified' do
96
- expect(controller_with_defined_routes).
97
- not_to route(:post, "/#{controller_path}").
98
- to(action: 'create')
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
- def controller_with_defined_routes
104
- @_controller_with_defined_routes ||= begin
105
- controller_class = define_controller(controller_name)
106
- _controller_path = controller_path
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
- define_routes do
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
- controller
236
+ def add_target_to(route_matcher, params)
237
+ route_matcher.to(params)
119
238
  end
120
239
  end
121
240
 
122
- def controller_path
123
- controller_name.sub(/Controller$/, '').underscore
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
- alias_method :define_controller_with_defined_routes,
127
- :controller_with_defined_routes
128
- end
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
- context 'given a controller with a defined glob url' do
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
- define_routes do
136
- get '/examples/*id', to: 'examples#example'
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
- it_behaves_like 'a controller with a defined route' do
146
- def controller_name
147
- 'ExamplesController'
148
- end
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
- it_behaves_like 'a controller with a defined route' do
154
- before do
155
- define_module('Admin')
156
- end
279
+ def define_controller_under_test
280
+ define_module('Admin')
281
+ super
282
+ end
283
+
284
+ include_examples 'core tests'
157
285
 
158
- def controller_name
159
- 'Admin::ExamplesController'
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