rspec-rails 2.11.4 → 2.12.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.
Files changed (55) hide show
  1. data/Capybara.md +2 -2
  2. data/Changelog.md +25 -1
  3. data/README.md +61 -25
  4. data/features/controller_specs/anonymous_controller.feature +25 -25
  5. data/features/controller_specs/bypass_rescue.feature +4 -4
  6. data/features/controller_specs/controller_spec.feature +4 -4
  7. data/features/controller_specs/isolation_from_views.feature +13 -13
  8. data/features/controller_specs/render_views.feature +11 -11
  9. data/features/feature_specs/feature_spec.feature +34 -0
  10. data/features/helper_specs/helper_spec.feature +10 -10
  11. data/features/mailer_specs/url_helpers.feature +7 -7
  12. data/features/matchers/new_record_matcher.feature +20 -7
  13. data/features/matchers/redirect_to_matcher.feature +6 -6
  14. data/features/matchers/relation_match_array.feature +8 -6
  15. data/features/matchers/render_template_matcher.feature +25 -4
  16. data/features/mocks/mock_model.feature +21 -21
  17. data/features/mocks/stub_model.feature +8 -8
  18. data/features/model_specs/errors_on.feature +25 -7
  19. data/features/model_specs/transactional_examples.feature +13 -13
  20. data/features/request_specs/request_spec.feature +8 -8
  21. data/features/routing_specs/be_routable_matcher.feature +10 -10
  22. data/features/routing_specs/named_routes.feature +3 -3
  23. data/features/routing_specs/route_to_matcher.feature +17 -17
  24. data/features/view_specs/inferred_controller_path.feature +7 -6
  25. data/features/view_specs/stub_template.feature +5 -5
  26. data/features/view_specs/view_spec.feature +50 -18
  27. data/lib/autotest/rails_rspec2.rb +1 -1
  28. data/lib/generators/rspec.rb +6 -0
  29. data/lib/generators/rspec/controller/templates/controller_spec.rb +2 -0
  30. data/lib/generators/rspec/helper/templates/helper_spec.rb +2 -0
  31. data/lib/generators/rspec/mailer/templates/mailer_spec.rb +2 -0
  32. data/lib/generators/rspec/model/templates/model_spec.rb +2 -0
  33. data/lib/generators/rspec/observer/templates/observer_spec.rb +2 -0
  34. data/lib/generators/rspec/scaffold/scaffold_generator.rb +37 -3
  35. data/lib/generators/rspec/scaffold/templates/controller_spec.rb +9 -7
  36. data/lib/generators/rspec/scaffold/templates/routing_spec.rb +2 -0
  37. data/lib/rspec/rails/example.rb +5 -1
  38. data/lib/rspec/rails/example/feature_example_group.rb +30 -0
  39. data/lib/rspec/rails/example/view_example_group.rb +23 -12
  40. data/lib/rspec/rails/extensions.rb +1 -0
  41. data/lib/rspec/rails/extensions/active_record/base.rb +5 -3
  42. data/lib/rspec/rails/extensions/active_record/proxy.rb +17 -0
  43. data/lib/rspec/rails/matchers/be_new_record.rb +8 -0
  44. data/lib/rspec/rails/tasks/rspec.rake +1 -2
  45. data/lib/rspec/rails/vendor/capybara.rb +2 -8
  46. data/lib/rspec/rails/version.rb +1 -1
  47. data/spec/autotest/rails_rspec2_spec.rb +4 -4
  48. data/spec/generators/rspec/model/model_generator_spec.rb +1 -1
  49. data/spec/generators/rspec/scaffold/scaffold_generator_spec.rb +8 -0
  50. data/spec/rspec/rails/example/feature_example_group_spec.rb +56 -0
  51. data/spec/rspec/rails/example/view_example_group_spec.rb +7 -1
  52. data/spec/rspec/rails/matchers/be_new_record_spec.rb +16 -2
  53. data/spec/rspec/rails/matchers/has_spec.rb +29 -0
  54. data/spec/rspec/rails/matchers/relation_match_array_spec.rb +18 -7
  55. metadata +66 -10
@@ -18,13 +18,14 @@ require 'spec_helper'
18
18
  # Message expectations are only used when there is no simpler way to specify
19
19
  # that an instance is receiving a specific message.
20
20
 
21
+ <% module_namespacing do -%>
21
22
  describe <%= controller_class_name %>Controller do
22
23
 
23
24
  # This should return the minimal set of attributes required to create a valid
24
25
  # <%= class_name %>. As you add validations to <%= class_name %>, be sure to
25
26
  # update the return value of this method accordingly.
26
27
  def valid_attributes
27
- {}
28
+ <%= formatted_hash(example_valid_attributes) %>
28
29
  end
29
30
 
30
31
  # This should return the minimal set of values that should be in the session
@@ -91,14 +92,14 @@ describe <%= controller_class_name %>Controller do
91
92
  it "assigns a newly created but unsaved <%= ns_file_name %> as @<%= ns_file_name %>" do
92
93
  # Trigger the behavior that occurs when invalid params are submitted
93
94
  <%= class_name %>.any_instance.stub(:save).and_return(false)
94
- post :create, {:<%= ns_file_name %> => {}}, valid_session
95
+ post :create, {:<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %>}, valid_session
95
96
  assigns(:<%= ns_file_name %>).should be_a_new(<%= class_name %>)
96
97
  end
97
98
 
98
99
  it "re-renders the 'new' template" do
99
100
  # Trigger the behavior that occurs when invalid params are submitted
100
101
  <%= class_name %>.any_instance.stub(:save).and_return(false)
101
- post :create, {:<%= ns_file_name %> => {}}, valid_session
102
+ post :create, {:<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %>}, valid_session
102
103
  response.should render_template("new")
103
104
  end
104
105
  end
@@ -112,8 +113,8 @@ describe <%= controller_class_name %>Controller do
112
113
  # specifies that the <%= class_name %> created on the previous line
113
114
  # receives the :update_attributes message with whatever params are
114
115
  # submitted in the request.
115
- <%= class_name %>.any_instance.should_receive(:update_attributes).with(<%= params %>)
116
- put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= params %>}, valid_session
116
+ <%= class_name %>.any_instance.should_receive(:update_attributes).with(<%= formatted_hash(example_params_for_update) %>)
117
+ put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= formatted_hash(example_params_for_update) %>}, valid_session
117
118
  end
118
119
 
119
120
  it "assigns the requested <%= ns_file_name %> as @<%= ns_file_name %>" do
@@ -134,7 +135,7 @@ describe <%= controller_class_name %>Controller do
134
135
  <%= file_name %> = <%= class_name %>.create! valid_attributes
135
136
  # Trigger the behavior that occurs when invalid params are submitted
136
137
  <%= class_name %>.any_instance.stub(:save).and_return(false)
137
- put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => {}}, valid_session
138
+ put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %>}, valid_session
138
139
  assigns(:<%= ns_file_name %>).should eq(<%= file_name %>)
139
140
  end
140
141
 
@@ -142,7 +143,7 @@ describe <%= controller_class_name %>Controller do
142
143
  <%= file_name %> = <%= class_name %>.create! valid_attributes
143
144
  # Trigger the behavior that occurs when invalid params are submitted
144
145
  <%= class_name %>.any_instance.stub(:save).and_return(false)
145
- put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => {}}, valid_session
146
+ put :update, {:id => <%= file_name %>.to_param, :<%= ns_file_name %> => <%= formatted_hash(example_invalid_attributes) %>}, valid_session
146
147
  response.should render_template("edit")
147
148
  end
148
149
  end
@@ -164,3 +165,4 @@ describe <%= controller_class_name %>Controller do
164
165
  end
165
166
 
166
167
  end
168
+ <% end -%>
@@ -1,5 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
+ <% module_namespacing do -%>
3
4
  describe <%= controller_class_name %>Controller do
4
5
  describe "routing" do
5
6
 
@@ -35,3 +36,4 @@ describe <%= controller_class_name %>Controller do
35
36
 
36
37
  end
37
38
  end
39
+ <% end -%>
@@ -6,6 +6,7 @@ require 'rspec/rails/example/view_example_group'
6
6
  require 'rspec/rails/example/mailer_example_group'
7
7
  require 'rspec/rails/example/routing_example_group'
8
8
  require 'rspec/rails/example/model_example_group'
9
+ require 'rspec/rails/example/feature_example_group'
9
10
 
10
11
  RSpec::configure do |c|
11
12
  def c.escaped_path(*parts)
@@ -27,7 +28,7 @@ RSpec::configure do |c|
27
28
  :file_path => c.escaped_path(%w[spec models])
28
29
  }
29
30
  c.include RSpec::Rails::RequestExampleGroup, :type => :request, :example_group => {
30
- :file_path => c.escaped_path(%w[spec (requests|integration)])
31
+ :file_path => c.escaped_path(%w[spec (requests|integration|api)])
31
32
  }
32
33
  c.include RSpec::Rails::RoutingExampleGroup, :type => :routing, :example_group => {
33
34
  :file_path => c.escaped_path(%w[spec routing])
@@ -35,4 +36,7 @@ RSpec::configure do |c|
35
36
  c.include RSpec::Rails::ViewExampleGroup, :type => :view, :example_group => {
36
37
  :file_path => c.escaped_path(%w[spec views])
37
38
  }
39
+ c.include RSpec::Rails::FeatureExampleGroup, :type => :feature, :example_group => {
40
+ :file_path => c.escaped_path(%w[spec features])
41
+ }
38
42
  end
@@ -0,0 +1,30 @@
1
+ module RSpec::Rails
2
+ module FeatureExampleGroup
3
+ extend ActiveSupport::Concern
4
+ include RSpec::Rails::RailsExampleGroup
5
+
6
+ DEFAULT_HOST = "www.example.com"
7
+
8
+ included do
9
+ metadata[:type] = :feature
10
+
11
+ app = ::Rails.application
12
+ if app.respond_to?(:routes)
13
+ include app.routes.url_helpers if app.routes.respond_to?(:url_helpers)
14
+ include app.routes.mounted_helpers if app.routes.respond_to?(:mounted_helpers)
15
+
16
+ if respond_to?(:default_url_options)
17
+ default_url_options[:host] ||= ::RSpec::Rails::FeatureExampleGroup::DEFAULT_HOST
18
+ end
19
+ end
20
+ end
21
+
22
+ def visit(*)
23
+ if defined?(super)
24
+ super
25
+ else
26
+ raise "Capybara not loaded, please add it to your Gemfile:\n\ngem \"capybara\""
27
+ end
28
+ end
29
+ end
30
+ end
@@ -88,7 +88,15 @@ module RSpec::Rails
88
88
 
89
89
  # @deprecated Use `rendered` instead.
90
90
  def response
91
- RSpec.deprecate("response", "rendered")
91
+ # `assert_template` expects `response` to implement a #body method
92
+ # like an `ActionDispatch::Response` does to force the view to render.
93
+ # For backwards compatibility, we use #response as an alias for
94
+ # #rendered, but it needs to implement #body to avoid `assert_template`
95
+ # raising a `NoMethodError`.
96
+ unless rendered.respond_to?(:body)
97
+ def rendered.body; self; end;
98
+ end
99
+
92
100
  rendered
93
101
  end
94
102
 
@@ -99,16 +107,20 @@ module RSpec::Rails
99
107
  end
100
108
 
101
109
  def _default_render_options
102
- # pluck the handler, format, and locale out of, eg, posts/index.de.html.haml
103
- template, *components = _default_file_to_render.split('.')
104
- handler, format, locale = *components.reverse
110
+ if ::Rails.version >= "3.2"
111
+ # pluck the handler, format, and locale out of, eg, posts/index.de.html.haml
112
+ template, *components = _default_file_to_render.split('.')
113
+ handler, format, locale = *components.reverse
105
114
 
106
- render_options = {:template => template}
107
- render_options[:handlers] = [handler] if handler
108
- render_options[:formats] = [format] if format
109
- render_options[:locales] = [locale] if locale
115
+ render_options = {:template => template}
116
+ render_options[:handlers] = [handler] if handler
117
+ render_options[:formats] = [format] if format
118
+ render_options[:locales] = [locale] if locale
110
119
 
111
- render_options
120
+ render_options
121
+ else
122
+ {:template => _default_file_to_render}
123
+ end
112
124
  end
113
125
 
114
126
  def _path_parts
@@ -142,10 +154,9 @@ module RSpec::Rails
142
154
  if view.lookup_context.respond_to?(:prefixes)
143
155
  # rails 3.1
144
156
  view.lookup_context.prefixes << _controller_path
145
- else
146
- # rails 3.0
147
- controller.controller_path = _controller_path
148
157
  end
158
+
159
+ controller.controller_path = _controller_path
149
160
  controller.request.path_parameters[:controller] = _controller_path
150
161
  controller.request.path_parameters[:action] = _inferred_action unless _inferred_action =~ /^_/
151
162
  end
@@ -1 +1,2 @@
1
1
  require 'rspec/rails/extensions/active_record/base'
2
+ require 'rspec/rails/extensions/active_record/proxy'
@@ -26,7 +26,8 @@ end
26
26
 
27
27
  module ::ActiveModel::Validations
28
28
  # Extension to enhance `should have` on AR Model instances. Calls
29
- # model.valid? in order to prepare the object's errors object.
29
+ # model.valid? in order to prepare the object's errors object. Accepts
30
+ # a :context option to specify the validation context.
30
31
  #
31
32
  # You can also use this to specify the content of the error messages.
32
33
  #
@@ -35,10 +36,11 @@ module ::ActiveModel::Validations
35
36
  # model.should have(:no).errors_on(:attribute)
36
37
  # model.should have(1).error_on(:attribute)
37
38
  # model.should have(n).errors_on(:attribute)
39
+ # model.should have(n).errors_on(:attribute, :context => :create)
38
40
  #
39
41
  # model.errors_on(:attribute).should include("can't be blank")
40
- def errors_on(attribute)
41
- self.valid?
42
+ def errors_on(attribute, options = {})
43
+ self.valid?(options[:context])
42
44
  [self.errors[attribute]].flatten.compact
43
45
  end
44
46
  alias :error_on :errors_on
@@ -0,0 +1,17 @@
1
+ RSpec.configure do |rspec|
2
+ # Delay this in order to give users a chance to configure `expect_with`...
3
+ rspec.before(:suite) do
4
+ if defined?(RSpec::Matchers) && RSpec::Matchers.configuration.syntax.include?(:should) && defined?(ActiveRecord)
5
+ # In Rails 3.0, it was AssociationProxy.
6
+ # In 3.1+, it's CollectionProxy.
7
+ const_name = [:CollectionProxy, :AssociationProxy].find do |const|
8
+ ActiveRecord::Associations.const_defined?(const)
9
+ end
10
+
11
+ proxy_class = ActiveRecord::Associations.const_get(const_name)
12
+
13
+ RSpec::Matchers.configuration.add_should_and_should_not_to proxy_class
14
+ end
15
+ end
16
+ end
17
+
@@ -5,6 +5,14 @@ module RSpec::Rails::Matchers
5
5
  def matches?(actual)
6
6
  !actual.persisted?
7
7
  end
8
+
9
+ def failure_message_for_should
10
+ "expected #{actual.inspect} to be a new record, but was persisted"
11
+ end
12
+
13
+ def failure_message_for_should_not
14
+ "expected #{actual.inspect} to be persisted, but was a new record"
15
+ end
8
16
  end
9
17
 
10
18
  # Passes if actual returns `false` for `persisted?`.
@@ -1,4 +1,3 @@
1
- require 'rspec/core'
2
1
  require 'rspec/core/rake_task'
3
2
  if default = Rake.application.instance_variable_get('@tasks')['default']
4
3
  default.prerequisites.delete('test')
@@ -8,7 +7,7 @@ orm_setting = Rails.configuration.generators.options[:rails][:orm]
8
7
  spec_prereq = if(orm_setting == :active_record)
9
8
  Rails.configuration.active_record[:schema_format] == :sql ? "db:test:clone_structure" : "db:test:prepare"
10
9
  else
11
- :noop
10
+ :noop
12
11
  end
13
12
  task :noop do; end
14
13
  task :default => :spec
@@ -12,9 +12,7 @@ if defined?(Capybara)
12
12
  RSpec.configure do |c|
13
13
  if defined?(Capybara::DSL)
14
14
  c.include Capybara::DSL, :type => :controller
15
- c.include Capybara::DSL, :example_group => {
16
- :file_path => c.escaped_path(%w[spec features])
17
- }
15
+ c.include Capybara::DSL, :type => :feature
18
16
  end
19
17
 
20
18
  if defined?(Capybara::RSpecMatchers)
@@ -27,11 +25,7 @@ if defined?(Capybara)
27
25
  }
28
26
  end
29
27
 
30
- if defined?(Capybara::RSpecMatchers) || defined?(Capybara::DSL)
31
- c.include RSpec::Rails::RailsExampleGroup, :example_group => {
32
- :file_path => c.escaped_path(%w[spec features])
33
- }
34
- else
28
+ unless defined?(Capybara::RSpecMatchers) || defined?(Capybara::DSL)
35
29
  c.include Capybara, :type => :request
36
30
  c.include Capybara, :type => :controller
37
31
  end
@@ -1,7 +1,7 @@
1
1
  module RSpec
2
2
  module Rails
3
3
  module Version
4
- STRING = '2.11.4'
4
+ STRING = '2.12.0'
5
5
  end
6
6
  end
7
7
  end
@@ -8,19 +8,19 @@ describe Autotest::RailsRspec2 do
8
8
  describe 'exceptions' do
9
9
  let(:exceptions_regexp) { rails_rspec2_autotest.exceptions }
10
10
 
11
- it "should match './log/test.log'" do
11
+ it "matches './log/test.log'" do
12
12
  exceptions_regexp.should match('./log/test.log')
13
13
  end
14
14
 
15
- it "should match 'log/test.log'" do
15
+ it "matches 'log/test.log'" do
16
16
  exceptions_regexp.should match('log/test.log')
17
17
  end
18
18
 
19
- it "should not match './spec/models/user_spec.rb'" do
19
+ it "does not match './spec/models/user_spec.rb'" do
20
20
  exceptions_regexp.should_not match('./spec/models/user_spec.rb')
21
21
  end
22
22
 
23
- it "should not match 'spec/models/user_spec.rb'" do
23
+ it "does not match 'spec/models/user_spec.rb'" do
24
24
  exceptions_regexp.should_not match('spec/models/user_spec.rb')
25
25
  end
26
26
  end
@@ -9,7 +9,7 @@ describe Rspec::Generators::ModelGenerator do
9
9
 
10
10
  before { prepare_destination }
11
11
 
12
- it 'should run both the model and fixture tasks' do
12
+ it 'runs both the model and fixture tasks' do
13
13
  gen = generator %w(posts)
14
14
  gen.should_receive :create_model_spec
15
15
  gen.should_receive :create_fixture_file
@@ -14,6 +14,7 @@ describe Rspec::Generators::ScaffoldGenerator do
14
14
  before { run_generator %w(posts) }
15
15
  it { should contain(/require 'spec_helper'/) }
16
16
  it { should contain(/describe PostsController/) }
17
+ it { should contain(%({ "these" => "params" })) }
17
18
  end
18
19
 
19
20
  describe 'with --no-controller_specs' do
@@ -22,6 +23,13 @@ describe Rspec::Generators::ScaffoldGenerator do
22
23
  end
23
24
  end
24
25
 
26
+ describe 'controller spec with attributes specified' do
27
+ subject { file('spec/controllers/posts_controller_spec.rb') }
28
+ before { run_generator %w(posts title:string) }
29
+
30
+ it { should contain(%({ "title" => "MyString" })) }
31
+ end
32
+
25
33
  describe 'namespaced controller spec' do
26
34
  subject { file('spec/controllers/admin/posts_controller_spec.rb') }
27
35
  before { run_generator %w(admin/posts) }
@@ -0,0 +1,56 @@
1
+ require "spec_helper"
2
+
3
+ module RSpec::Rails
4
+ describe FeatureExampleGroup do
5
+ it { should be_included_in_files_in('./spec/features/') }
6
+ it { should be_included_in_files_in('.\\spec\\features\\') }
7
+
8
+ it "adds :type => :model to the metadata" do
9
+ group = RSpec::Core::ExampleGroup.describe do
10
+ include FeatureExampleGroup
11
+ end
12
+
13
+ expect(group.metadata[:type]).to eql(:feature)
14
+ end
15
+
16
+ it "includes Rails route helpers" do
17
+ Rails.application.routes.draw do
18
+ get "/foo", :as => :foo, :to => "foo#bar"
19
+ end
20
+
21
+ group = RSpec::Core::ExampleGroup.describe do
22
+ include FeatureExampleGroup
23
+ end
24
+
25
+ expect(group.new.foo_path).to eql("/foo")
26
+ expect(group.new.foo_url).to eql("http://www.example.com/foo")
27
+ end
28
+
29
+ describe "#visit" do
30
+ it "raises an error informing about missing Capybara" do
31
+ group = RSpec::Core::ExampleGroup.describe do
32
+ include FeatureExampleGroup
33
+ end
34
+
35
+ expect {
36
+ group.new.visit('/foobar')
37
+ }.to raise_error(/Capybara not loaded/)
38
+ end
39
+
40
+ it "is resistant to load order errors" do
41
+ capybara = Module.new do
42
+ def visit(url)
43
+ "success: #{url}"
44
+ end
45
+ end
46
+
47
+ group = RSpec::Core::ExampleGroup.describe do
48
+ include capybara
49
+ include FeatureExampleGroup
50
+ end
51
+
52
+ expect(group.new.visit("/foo")).to eql("success: /foo")
53
+ end
54
+ end
55
+ end
56
+ end
@@ -113,10 +113,16 @@ module RSpec::Rails
113
113
  view_spec.render
114
114
  view_spec.received.first.should == [{:template => "widgets/new"},{}, nil]
115
115
  end
116
+
116
117
  it "converts the filename components into render options" do
117
118
  view_spec.stub(:_default_file_to_render) { "widgets/new.en.html.erb" }
118
119
  view_spec.render
119
- view_spec.received.first.should == [{:template => "widgets/new", :locales=>['en'], :formats=>['html'], :handlers=>['erb']},{}, nil]
120
+
121
+ if ::Rails.version >= "3.2"
122
+ view_spec.received.first.should == [{:template => "widgets/new", :locales=>['en'], :formats=>['html'], :handlers=>['erb']}, {}, nil]
123
+ else
124
+ view_spec.received.first.should == [{:template => "widgets/new.en.html.erb"}, {}, nil]
125
+ end
120
126
  end
121
127
  end
122
128
 
@@ -4,16 +4,30 @@ describe "be_new_record" do
4
4
  include RSpec::Rails::Matchers
5
5
 
6
6
  context "un-persisted record" do
7
+ let(:record) { double('record', :persisted? => false) }
8
+
7
9
  it "passes" do
8
- record = double('record', :persisted? => false)
9
10
  record.should be_new_record
10
11
  end
12
+
13
+ it "fails with custom failure message" do
14
+ expect {
15
+ expect(record).not_to be_new_record
16
+ }.to raise_exception(/expected .* to be persisted, but was a new record/)
17
+ end
11
18
  end
12
19
 
13
20
  context "persisted record" do
21
+ let(:record) { double('record', :persisted? => true) }
22
+
14
23
  it "fails" do
15
- record = double('record', :persisted? => true)
16
24
  record.should_not be_new_record
17
25
  end
26
+
27
+ it "fails with custom failure message" do
28
+ expect {
29
+ expect(record).to be_new_record
30
+ }.to raise_exception(/expected .* to be a new record, but was persisted/)
31
+ end
18
32
  end
19
33
  end