rspec-rails 2.11.4 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
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