richzhou-rspec-rails 1.3.4

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.
Files changed (170) hide show
  1. data/.document +7 -0
  2. data/.gitignore +8 -0
  3. data/Contribute.rdoc +4 -0
  4. data/Gemfile +4 -0
  5. data/History.rdoc +321 -0
  6. data/License.txt +33 -0
  7. data/Manifest.txt +165 -0
  8. data/README.rdoc +48 -0
  9. data/Rakefile +12 -0
  10. data/TODO.txt +17 -0
  11. data/Upgrade.rdoc +148 -0
  12. data/generators/integration_spec/integration_spec_generator.rb +10 -0
  13. data/generators/integration_spec/templates/integration_spec.rb +4 -0
  14. data/generators/rspec/CHANGES +1 -0
  15. data/generators/rspec/rspec_generator.rb +72 -0
  16. data/generators/rspec/templates/previous_failures.txt +0 -0
  17. data/generators/rspec/templates/rcov.opts +2 -0
  18. data/generators/rspec/templates/rspec.rake +146 -0
  19. data/generators/rspec/templates/script/autospec +6 -0
  20. data/generators/rspec/templates/script/spec +10 -0
  21. data/generators/rspec/templates/spec.opts +4 -0
  22. data/generators/rspec/templates/spec_helper.rb +54 -0
  23. data/generators/rspec_controller/USAGE +33 -0
  24. data/generators/rspec_controller/rspec_controller_generator.rb +47 -0
  25. data/generators/rspec_controller/templates/controller_spec.rb +25 -0
  26. data/generators/rspec_controller/templates/helper_spec.rb +11 -0
  27. data/generators/rspec_controller/templates/view_spec.rb +12 -0
  28. data/generators/rspec_default_values.rb +28 -0
  29. data/generators/rspec_model/USAGE +18 -0
  30. data/generators/rspec_model/rspec_model_generator.rb +35 -0
  31. data/generators/rspec_model/templates/model_spec.rb +13 -0
  32. data/generators/rspec_scaffold/rspec_scaffold_generator.rb +154 -0
  33. data/generators/rspec_scaffold/templates/controller_spec.rb +131 -0
  34. data/generators/rspec_scaffold/templates/edit_erb_spec.rb +25 -0
  35. data/generators/rspec_scaffold/templates/helper_spec.rb +11 -0
  36. data/generators/rspec_scaffold/templates/index_erb_spec.rb +27 -0
  37. data/generators/rspec_scaffold/templates/new_erb_spec.rb +25 -0
  38. data/generators/rspec_scaffold/templates/routing_spec.rb +33 -0
  39. data/generators/rspec_scaffold/templates/show_erb_spec.rb +22 -0
  40. data/init.rb +9 -0
  41. data/lib/autotest/discover.rb +5 -0
  42. data/lib/autotest/rails_rspec.rb +76 -0
  43. data/lib/spec/rails.rb +26 -0
  44. data/lib/spec/rails/example.rb +48 -0
  45. data/lib/spec/rails/example/assigns_hash_proxy.rb +39 -0
  46. data/lib/spec/rails/example/controller_example_group.rb +285 -0
  47. data/lib/spec/rails/example/cookies_proxy.rb +29 -0
  48. data/lib/spec/rails/example/functional_example_group.rb +106 -0
  49. data/lib/spec/rails/example/helper_example_group.rb +153 -0
  50. data/lib/spec/rails/example/integration_example_group.rb +16 -0
  51. data/lib/spec/rails/example/model_example_group.rb +15 -0
  52. data/lib/spec/rails/example/render_observer.rb +82 -0
  53. data/lib/spec/rails/example/routing_example_group.rb +16 -0
  54. data/lib/spec/rails/example/routing_helpers.rb +66 -0
  55. data/lib/spec/rails/example/view_example_group.rb +203 -0
  56. data/lib/spec/rails/extensions.rb +11 -0
  57. data/lib/spec/rails/extensions/action_controller/rescue.rb +42 -0
  58. data/lib/spec/rails/extensions/action_controller/test_case.rb +16 -0
  59. data/lib/spec/rails/extensions/action_controller/test_response.rb +21 -0
  60. data/lib/spec/rails/extensions/action_view/base.rb +35 -0
  61. data/lib/spec/rails/extensions/active_record/base.rb +45 -0
  62. data/lib/spec/rails/extensions/active_support/test_case.rb +7 -0
  63. data/lib/spec/rails/extensions/spec/matchers/have.rb +23 -0
  64. data/lib/spec/rails/extensions/spec/runner/configuration.rb +45 -0
  65. data/lib/spec/rails/interop/testcase.rb +14 -0
  66. data/lib/spec/rails/matchers.rb +32 -0
  67. data/lib/spec/rails/matchers/ar_be_valid.rb +27 -0
  68. data/lib/spec/rails/matchers/assert_select.rb +180 -0
  69. data/lib/spec/rails/matchers/change.rb +13 -0
  70. data/lib/spec/rails/matchers/have_text.rb +57 -0
  71. data/lib/spec/rails/matchers/include_text.rb +54 -0
  72. data/lib/spec/rails/matchers/redirect_to.rb +126 -0
  73. data/lib/spec/rails/matchers/render_template.rb +129 -0
  74. data/lib/spec/rails/matchers/route_to.rb +149 -0
  75. data/lib/spec/rails/mocks.rb +140 -0
  76. data/lib/spec/rails/version.rb +16 -0
  77. data/rspec-rails.gemspec +25 -0
  78. data/spec/autotest/mappings_spec.rb +86 -0
  79. data/spec/rails_suite.rb +7 -0
  80. data/spec/resources/controllers/action_view_base_spec_controller.rb +2 -0
  81. data/spec/resources/controllers/application.rb +9 -0
  82. data/spec/resources/controllers/controller_spec_controller.rb +127 -0
  83. data/spec/resources/controllers/example.txt +1 -0
  84. data/spec/resources/controllers/redirect_spec_controller.rb +70 -0
  85. data/spec/resources/controllers/render_spec_controller.rb +34 -0
  86. data/spec/resources/controllers/rjs_spec_controller.rb +58 -0
  87. data/spec/resources/helpers/addition_helper.rb +5 -0
  88. data/spec/resources/helpers/explicit_helper.rb +46 -0
  89. data/spec/resources/helpers/more_explicit_helper.rb +5 -0
  90. data/spec/resources/helpers/plugin_application_helper.rb +6 -0
  91. data/spec/resources/helpers/view_spec_helper.rb +13 -0
  92. data/spec/resources/models/animal.rb +4 -0
  93. data/spec/resources/models/person.rb +18 -0
  94. data/spec/resources/models/thing.rb +3 -0
  95. data/spec/resources/views/controller_spec/_partial.html.erb +0 -0
  96. data/spec/resources/views/controller_spec/action_setting_flash_after_session_reset.html.erb +1 -0
  97. data/spec/resources/views/controller_spec/action_setting_flash_before_session_reset.html.erb +1 -0
  98. data/spec/resources/views/controller_spec/action_setting_the_assigns_hash.html.erb +0 -0
  99. data/spec/resources/views/controller_spec/action_with_errors_in_template.html.erb +1 -0
  100. data/spec/resources/views/controller_spec/action_with_template.html.erb +1 -0
  101. data/spec/resources/views/controller_spec/non_existent_action_with_existent_template.html.erb +1 -0
  102. data/spec/resources/views/layouts/application.html.erb +0 -0
  103. data/spec/resources/views/layouts/simple.html.erb +0 -0
  104. data/spec/resources/views/objects/_object.html.erb +1 -0
  105. data/spec/resources/views/render_spec/_a_partial.html.erb +0 -0
  106. data/spec/resources/views/render_spec/action_with_alternate_layout.html.erb +0 -0
  107. data/spec/resources/views/render_spec/some_action.html.erb +0 -0
  108. data/spec/resources/views/render_spec/some_action.js.rjs +1 -0
  109. data/spec/resources/views/rjs_spec/_replacement_partial.html.erb +1 -0
  110. data/spec/resources/views/rjs_spec/hide_div.js.rjs +1 -0
  111. data/spec/resources/views/rjs_spec/hide_page_element.js.rjs +1 -0
  112. data/spec/resources/views/rjs_spec/insert_html.js.rjs +1 -0
  113. data/spec/resources/views/rjs_spec/replace.js.rjs +1 -0
  114. data/spec/resources/views/rjs_spec/replace_html.js.rjs +1 -0
  115. data/spec/resources/views/rjs_spec/replace_html_with_partial.js.rjs +1 -0
  116. data/spec/resources/views/rjs_spec/visual_effect.js.rjs +1 -0
  117. data/spec/resources/views/rjs_spec/visual_toggle_effect.js.rjs +1 -0
  118. data/spec/resources/views/tag_spec/no_tags.html.erb +1 -0
  119. data/spec/resources/views/tag_spec/single_div_with_no_attributes.html.erb +1 -0
  120. data/spec/resources/views/tag_spec/single_div_with_one_attribute.html.erb +1 -0
  121. data/spec/resources/views/view_spec/_partial.html.erb +2 -0
  122. data/spec/resources/views/view_spec/_partial_used_twice.html.erb +0 -0
  123. data/spec/resources/views/view_spec/_partial_with_local_variable.html.erb +1 -0
  124. data/spec/resources/views/view_spec/_partial_with_sub_partial.html.erb +1 -0
  125. data/spec/resources/views/view_spec/_spacer.html.erb +1 -0
  126. data/spec/resources/views/view_spec/accessor.html.erb +6 -0
  127. data/spec/resources/views/view_spec/block_helper.html.erb +3 -0
  128. data/spec/resources/views/view_spec/entry_form.html.erb +2 -0
  129. data/spec/resources/views/view_spec/explicit_helper.html.erb +2 -0
  130. data/spec/resources/views/view_spec/foo/show.html.erb +1 -0
  131. data/spec/resources/views/view_spec/implicit_helper.html.erb +2 -0
  132. data/spec/resources/views/view_spec/multiple_helpers.html.erb +3 -0
  133. data/spec/resources/views/view_spec/path_params.html.erb +1 -0
  134. data/spec/resources/views/view_spec/should_not_receive.html.erb +3 -0
  135. data/spec/resources/views/view_spec/template_with_partial.html.erb +5 -0
  136. data/spec/resources/views/view_spec/template_with_partial_using_collection.html.erb +3 -0
  137. data/spec/resources/views/view_spec/template_with_partial_with_array.html.erb +1 -0
  138. data/spec/resources/views/view_spec/view_helpers.html.erb +1 -0
  139. data/spec/spec/rails/example/assigns_hash_proxy_spec.rb +109 -0
  140. data/spec/spec/rails/example/configuration_spec.rb +67 -0
  141. data/spec/spec/rails/example/controller_example_group_spec.rb +307 -0
  142. data/spec/spec/rails/example/controller_isolation_spec.rb +75 -0
  143. data/spec/spec/rails/example/cookies_proxy_spec.rb +87 -0
  144. data/spec/spec/rails/example/error_handling_spec.rb +90 -0
  145. data/spec/spec/rails/example/example_group_factory_spec.rb +112 -0
  146. data/spec/spec/rails/example/helper_example_group_spec.rb +247 -0
  147. data/spec/spec/rails/example/model_example_group_spec.rb +32 -0
  148. data/spec/spec/rails/example/routing_example_group_spec.rb +9 -0
  149. data/spec/spec/rails/example/shared_routing_example_group_examples.rb +241 -0
  150. data/spec/spec/rails/example/test_unit_assertion_accessibility_spec.rb +33 -0
  151. data/spec/spec/rails/example/view_example_group_spec.rb +346 -0
  152. data/spec/spec/rails/extensions/action_view_base_spec.rb +79 -0
  153. data/spec/spec/rails/extensions/active_record_spec.rb +14 -0
  154. data/spec/spec/rails/interop/testcase_spec.rb +70 -0
  155. data/spec/spec/rails/matchers/ar_be_valid_spec.rb +19 -0
  156. data/spec/spec/rails/matchers/assert_select_spec.rb +835 -0
  157. data/spec/spec/rails/matchers/errors_on_spec.rb +37 -0
  158. data/spec/spec/rails/matchers/have_text_spec.rb +69 -0
  159. data/spec/spec/rails/matchers/include_text_spec.rb +62 -0
  160. data/spec/spec/rails/matchers/redirect_to_spec.rb +253 -0
  161. data/spec/spec/rails/matchers/render_template_spec.rb +208 -0
  162. data/spec/spec/rails/matchers/should_change_spec.rb +15 -0
  163. data/spec/spec/rails/mocks/ar_classes.rb +10 -0
  164. data/spec/spec/rails/mocks/mock_model_spec.rb +112 -0
  165. data/spec/spec/rails/mocks/stub_model_spec.rb +80 -0
  166. data/spec/spec/rails/sample_modified_fixture.rb +8 -0
  167. data/spec/spec/rails/sample_spec.rb +8 -0
  168. data/spec/spec/rails/spec_spec.rb +11 -0
  169. data/spec/spec_helper.rb +78 -0
  170. metadata +363 -0
@@ -0,0 +1,13 @@
1
+ if defined?(ActiveRecord::Base)
2
+ module Spec
3
+ module Matchers
4
+ class Change
5
+ def evaluate_value_proc_with_ensured_evaluation_of_proxy
6
+ value = evaluate_value_proc_without_ensured_evaluation_of_proxy
7
+ ActiveRecord::Associations::AssociationProxy === value ? value.dup : value
8
+ end
9
+ alias_method_chain :evaluate_value_proc, :ensured_evaluation_of_proxy
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,57 @@
1
+ module Spec
2
+ module Rails
3
+ module Matchers
4
+
5
+ class HaveText #:nodoc:
6
+
7
+ def initialize(expected)
8
+ @expected = expected
9
+ end
10
+
11
+ def matches?(response_or_text)
12
+ @actual = response_or_text.respond_to?(:body) ? response_or_text.body : response_or_text
13
+ return actual =~ expected if Regexp === expected
14
+ return actual == expected unless Regexp === expected
15
+ end
16
+
17
+ def failure_message_for_should
18
+ "expected #{expected.inspect}, got #{actual.inspect}"
19
+ end
20
+
21
+ def failure_message_for_should_not
22
+ "expected not to have text #{expected.inspect}"
23
+ end
24
+
25
+ def description
26
+ "have text #{expected.inspect}"
27
+ end
28
+
29
+ private
30
+ attr_reader :expected
31
+ attr_reader :actual
32
+
33
+ end
34
+
35
+ # :call-seq:
36
+ # response.should have_text(expected)
37
+ # response.should_not have_text(expected)
38
+ #
39
+ # Accepts a String or a Regexp, matching a String using ==
40
+ # and a Regexp using =~.
41
+ #
42
+ # If response_or_text has a #body, then that is used as to match against
43
+ # else it uses response_or_text
44
+ #
45
+ # Use this instead of <tt>response.should have_tag()</tt>
46
+ # when you want to match the whole string or whole body
47
+ #
48
+ # == Examples
49
+ #
50
+ # response.should have_text("This is the expected text")
51
+ def have_text(text)
52
+ HaveText.new(text)
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,54 @@
1
+ module Spec
2
+ module Rails
3
+ module Matchers
4
+
5
+ class IncludeText #:nodoc:
6
+
7
+ def initialize(expected)
8
+ @expected = expected
9
+ end
10
+
11
+ def matches?(response_or_text)
12
+ @actual = response_or_text.respond_to?(:body) ? response_or_text.body : response_or_text
13
+ return actual.include?(expected)
14
+ end
15
+
16
+ def failure_message_for_should
17
+ "expected to find #{expected.inspect} in #{actual.inspect}"
18
+ end
19
+
20
+ def failure_message_for_should_not
21
+ "expected not to include text #{expected.inspect}"
22
+ end
23
+
24
+ def description
25
+ "include text #{expected.inspect}"
26
+ end
27
+
28
+ private
29
+ attr_reader :expected
30
+ attr_reader :actual
31
+
32
+ end
33
+
34
+
35
+ # :call-seq:
36
+ # response.should include_text(expected)
37
+ # response.should_not include_text(expected)
38
+ #
39
+ # Accepts a String, matching using include?
40
+ #
41
+ # Use this instead of <tt>response.should have_text()</tt>
42
+ # when you either don't know or don't care where on the page
43
+ # this text appears.
44
+ #
45
+ # == Examples
46
+ #
47
+ # response.should include_text("This text will be in the actual string")
48
+ def include_text(text)
49
+ IncludeText.new(text)
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,126 @@
1
+ module Spec
2
+ module Rails
3
+ module Matchers
4
+
5
+ class RedirectTo #:nodoc:
6
+
7
+ include ActionController::StatusCodes
8
+
9
+ def initialize(request, expected)
10
+ @expected = expected
11
+ @request = request
12
+ end
13
+
14
+ def matches?(response_or_controller)
15
+ response = response_or_controller.respond_to?(:response) ?
16
+ response_or_controller.response :
17
+ response_or_controller
18
+
19
+ @redirected = response.redirect?
20
+ @actual = response.redirect_url
21
+ return false unless @redirected
22
+
23
+ if @expected_status
24
+ @actual_status = interpret_status(response.code.to_i)
25
+ @status_matched = @expected_status == @actual_status
26
+ else
27
+ @status_matched = true
28
+ end
29
+
30
+ if @expected.instance_of? Hash
31
+ return false unless @actual =~ %r{^\w+://#{@request.host}}
32
+ return false unless actual_redirect_to_valid_route
33
+ return actual_hash == expected_hash && @status_matched
34
+ else
35
+ return @actual == expected_url && @status_matched
36
+ end
37
+ end
38
+
39
+ def actual_hash
40
+ hash_from_url @actual
41
+ end
42
+
43
+ def expected_hash
44
+ hash_from_url expected_url
45
+ end
46
+
47
+ def actual_redirect_to_valid_route
48
+ actual_hash
49
+ end
50
+
51
+ def hash_from_url(url)
52
+ query_hash(url).merge(path_hash(url)).with_indifferent_access
53
+ end
54
+
55
+ def path_hash(url)
56
+ path = url.sub(%r{^\w+://#{@request.host}(?::\d+)?}, "").split("?", 2)[0]
57
+ ActionController::Routing::Routes.recognize_path path, { :method => :get }
58
+ end
59
+
60
+ def query_hash(url)
61
+ query = url.split("?", 2)[1] || ""
62
+ Rack::Utils.parse_query(query)
63
+ end
64
+
65
+ def with(options)
66
+ @expected_status = interpret_status(options[:status])
67
+ self
68
+ end
69
+
70
+ def expected_url
71
+ case @expected
72
+ when Hash
73
+ return ActionController::UrlRewriter.new(@request, {}).rewrite(@expected)
74
+ when :back
75
+ return @request.env['HTTP_REFERER']
76
+ when %r{^\w+://.*}
77
+ return @expected
78
+ else
79
+ return "http://#{@request.host}" + (@expected.split('')[0] == '/' ? '' : '/') + @expected
80
+ end
81
+ end
82
+
83
+ def failure_message_for_should
84
+ if @redirected
85
+ if @status_matched
86
+ return %Q{expected redirect to #{@expected.inspect}, got redirect to #{@actual.inspect}}
87
+ else
88
+ return %Q{expected redirect to #{@expected.inspect} with status #{@expected_status}, got #{@actual_status}}
89
+ end
90
+ else
91
+ return %Q{expected redirect to #{@expected.inspect}, got no redirect}
92
+ end
93
+ end
94
+
95
+ def failure_message_for_should_not
96
+ return %Q{expected not to be redirected to #{@expected.inspect}, but was} if @redirected
97
+ end
98
+
99
+ def description
100
+ "redirect to #{@expected.inspect}"
101
+ end
102
+ end
103
+
104
+ # :call-seq:
105
+ # response.should redirect_to(url)
106
+ # response.should redirect_to(:action => action_name)
107
+ # response.should redirect_to(:controller => controller_name, :action => action_name)
108
+ # response.should_not redirect_to(url)
109
+ # response.should_not redirect_to(:action => action_name)
110
+ # response.should_not redirect_to(:controller => controller_name, :action => action_name)
111
+ #
112
+ # Passes if the response is a redirect to the url, action or controller/action.
113
+ # Useful in controller specs (integration or isolation mode).
114
+ #
115
+ # == Examples
116
+ #
117
+ # response.should redirect_to("path/to/action")
118
+ # response.should redirect_to("http://test.host/path/to/action")
119
+ # response.should redirect_to(:action => 'list')
120
+ def redirect_to(opts)
121
+ RedirectTo.new(request, opts)
122
+ end
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,129 @@
1
+ module Spec
2
+ module Rails
3
+ module Matchers
4
+
5
+ class RenderTemplate #:nodoc:
6
+
7
+ def initialize(expected, controller)
8
+ @controller = controller
9
+ @expected = expected
10
+ end
11
+
12
+ def matches?(response_or_controller)
13
+ response = response_or_controller.respond_to?(:response) ?
14
+ response_or_controller.response :
15
+ response_or_controller
16
+
17
+ if response.respond_to?(:redirect?) && response.redirect?
18
+ @redirect_url = response.redirect_url
19
+ elsif response.respond_to?(:rendered_file)
20
+ @actual = response.rendered_file
21
+ elsif response.respond_to?(:rendered)
22
+ case template = response.rendered[:template]
23
+ when nil
24
+ unless response.rendered[:partials].empty?
25
+ @actual = path_and_file(response.rendered[:partials].keys.first).join("/_")
26
+ end
27
+ when ActionView::Template
28
+ @actual = template.path
29
+ when String
30
+ @actual = template
31
+ end
32
+ else
33
+ @actual = response.rendered_template.to_s
34
+ end
35
+ return false if @actual.blank?
36
+ given_controller_path, given_file = path_and_file(@actual)
37
+ expected_controller_path, expected_file = path_and_file(@expected)
38
+ given_controller_path == expected_controller_path && match_files(given_file, expected_file)
39
+ end
40
+
41
+ def match_files(actual, expected)
42
+ actual_parts = actual.split('.')
43
+ expected_parts = expected.split('.')
44
+ expected_parts.each_with_index do |expected_part, index|
45
+ return false unless expected_part == actual_parts[index]
46
+ end
47
+ true
48
+ end
49
+
50
+ def failure_message_for_should
51
+ if @redirect_url
52
+ "expected #{@expected.inspect}, got redirected to #{@redirect_url.inspect}"
53
+ else
54
+ "expected #{@expected.inspect}, got #{@actual.inspect}"
55
+ end
56
+ end
57
+
58
+ def failure_message_for_should_not
59
+ "expected not to render #{@expected.inspect}, but did"
60
+ end
61
+
62
+ def description
63
+ "render template #{@expected.inspect}"
64
+ end
65
+
66
+ private
67
+ def path_and_file(path)
68
+ parts = path.split('/')
69
+ file = parts.pop
70
+ controller = parts.empty? ? current_controller_path : parts.join('/')
71
+ return controller, file
72
+ end
73
+
74
+ def controller_path_from(path)
75
+ parts = path.split('/')
76
+ parts.pop
77
+ parts.join('/')
78
+ end
79
+
80
+ def current_controller_path
81
+ @controller.class.to_s.underscore.gsub(/_controller$/,'')
82
+ end
83
+
84
+ end
85
+
86
+ # :call-seq:
87
+ # response.should render_template(template)
88
+ # response.should_not render_template(template)
89
+ #
90
+ # For use in controller code examples (integration or isolation mode).
91
+ #
92
+ # Passes if the specified template (view file) is rendered by the
93
+ # response. This file can be any view file, including a partial. However
94
+ # if it is a partial it must be rendered directly i.e. you can't detect
95
+ # that a partial has been rendered as part of a view using
96
+ # render_template. For that you should use a message expectation
97
+ # (mock) instead:
98
+ #
99
+ # controller.should_receive(:render).with(:partial => 'path/to/partial')
100
+ #
101
+ # <code>template</code> can include the controller path. It can also
102
+ # include an optional extension, which you only need to use when there
103
+ # is ambiguity.
104
+ #
105
+ # Note that partials must be spelled with the preceding underscore.
106
+ #
107
+ # == Examples
108
+ #
109
+ # response.should render_template('list')
110
+ # response.should render_template('same_controller/list')
111
+ # response.should render_template('other_controller/list')
112
+ #
113
+ # # with extensions
114
+ # response.should render_template('list.rjs')
115
+ # response.should render_template('list.haml')
116
+ # response.should render_template('same_controller/list.rjs')
117
+ # response.should render_template('other_controller/list.rjs')
118
+ #
119
+ # # partials
120
+ # response.should render_template('_a_partial')
121
+ # response.should render_template('same_controller/_a_partial')
122
+ # response.should render_template('other_controller/_a_partial')
123
+ def render_template(path)
124
+ RenderTemplate.new(path.to_s, @controller)
125
+ end
126
+
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,149 @@
1
+ require 'rack/utils'
2
+
3
+ module Spec
4
+ module Rails
5
+ module Matchers
6
+ USAGE = ArgumentError.new( 'usage: { :method => "path" }.should route_to( :controller => "controller", :action => "action", [ args ] )' )
7
+
8
+ class PathDecomposer
9
+ def self.decompose_path(path)
10
+ method, path = if Hash === path
11
+ raise USAGE if path.keys.size > 1
12
+ path.entries.first
13
+ else
14
+ [:get, path]
15
+ end
16
+ path, querystring = path.split('?')
17
+ return method, path, querystring
18
+ end
19
+ end
20
+
21
+ class RouteTo #:nodoc:
22
+ def initialize(expected, example)
23
+ @route, @example = expected,example
24
+ end
25
+
26
+ def matches?(path)
27
+ begin
28
+ @actual = path
29
+ method, path, querystring = PathDecomposer.decompose_path(path)
30
+ params = querystring.blank? ? {} : Rack::Utils.parse_query(querystring).symbolize_keys!
31
+ @example.assert_routing({ :method => method, :path => path }, @route, {}, params)
32
+ true
33
+ rescue ActionController::RoutingError, ::Test::Unit::AssertionFailedError, ActionController::MethodNotAllowed => e
34
+ raise e.class, "#{e}\nIf you're expecting this failure, we suggest { :#{method} => \"#{path}\" }.should_not be_routable"
35
+ rescue Exception => e
36
+ raise e.class, "#{e}\n#{e.backtrace.join( "\n" )}"
37
+ end
38
+ end
39
+
40
+ def does_not_match(path)
41
+ raise ArgumentError, "Don't test a negative route like this."
42
+ end
43
+
44
+ def failure_message_for_should
45
+ "Expected #{@expected.inspect} to route to #{@actual.inspect}, but it didn't.\n"+
46
+ "In this case, we expected you to get an exception. So this message probably means something weird happened."
47
+ end
48
+
49
+ def failure_message_for_should_not
50
+ "Expected a routing error, but the route passed instead. \nNote, when expecting routes to fail, you should use 'should_not be_routable' instead."
51
+ end
52
+
53
+ def description
54
+ "route to #{@expected.inspect}"
55
+ end
56
+
57
+ private
58
+ attr_reader :expected
59
+ attr_reader :actual
60
+
61
+ end
62
+
63
+ # :call-seq:
64
+ # "path".should route_to(expected) # assumes GET
65
+ # { :get => "path" }.should route_to(expected)
66
+ # { :put => "path" }.should route_to(expected)
67
+ #
68
+ # Uses ActionController::Routing::Routes to verify that
69
+ # the path-and-method routes to a given set of options.
70
+ # Also verifies route-generation, so that the expected options
71
+ # do generate a pathname consisten with the indicated path/method.
72
+ #
73
+ # For negative tests, only the route recognition failure can be
74
+ # tested; since route generation via path_to() will always generate
75
+ # a path as requested. Use .should_not be_routable() in this case.
76
+ #
77
+ # == Examples
78
+ # { :get => '/registrations/1/edit' }.
79
+ # should route_to(:controller => 'registrations', :action => 'edit', :id => '1')
80
+ # { :put => "/registrations/1" }.should
81
+ # route_to(:controller => 'registrations', :action => 'update', :id => 1)
82
+ # { :post => "/registrations/" }.should
83
+ # route_to(:controller => 'registrations', :action => 'create')
84
+
85
+ def route_to(expected)
86
+ RouteTo.new(expected, self)
87
+ end
88
+
89
+ class BeRoutable
90
+ def initialize(example)
91
+ @example = example
92
+ end
93
+
94
+ def matches?(path)
95
+ begin
96
+ @actual = path
97
+ method, path = PathDecomposer.decompose_path(path)
98
+ @example.assert_recognizes({}, { :method => method, :path => path }, {} )
99
+ true
100
+ rescue ActionController::RoutingError, ActionController::MethodNotAllowed
101
+ false
102
+ rescue ::Test::Unit::AssertionFailedError => e
103
+ # the second thingy will always be "<{}>" becaues of the way we called assert_recognizes({}...) above.
104
+ e.to_s =~ /<(.*)> did not match <\{\}>/m and @actual_place = $1 or raise
105
+ true
106
+ end
107
+ end
108
+ def failure_message_for_should
109
+ "Expected '#{@actual.keys.first.to_s.upcase} #{@actual.values.first}' to be routable, but it wasn't.\n"+
110
+ "To really test routability, we recommend #{@actual.inspect}.\n"+
111
+ " should route_to( :action => 'action', :controller => 'controller' )\n\n"+
112
+
113
+ "That way, you'll verify where your route goes to. Plus, we'll verify\n"+
114
+ "the generation of the expected path from the action/controller, as in\n"+
115
+ "the url_for() helper."
116
+ end
117
+
118
+ def failure_message_for_should_not
119
+ "Expected '#{@actual.keys.first.to_s.upcase} #{@actual.values.first}' to fail, but it routed to #{@actual_place} instead"
120
+ end
121
+
122
+ end
123
+ # :call-seq:
124
+ # { "path" }.should_not be_routable # assumes GET
125
+ # { :get => "path" }.should_not be_routable
126
+ # { :put => "path" }.should_not be_routable
127
+ #
128
+ # Uses ActionController::Routing::Routes to verify that
129
+ # the path-and-method cannot be routed to a controller.
130
+ # Since url_for() will always generate a path, even if that
131
+ # path is not routable, the negative test only needs to be
132
+ # performed on the route recognition.
133
+ #
134
+ # Don't use this matcher for testing expected routability -
135
+ # use .should route_to( :controller => "controller", :action => "action" ) instead
136
+ #
137
+ # == Examples
138
+ # { :get => '/registrations/1/attendees/3/edit' }.should_not be_routable
139
+ # { :get => '/attendees/3/edit' }.should route_to( ...<controller/action>... )
140
+
141
+ def be_routable
142
+ BeRoutable.new(self)
143
+ end
144
+
145
+ alias_method :be_routeable, :be_routable
146
+ end
147
+ end
148
+ end
149
+