rspec-rails 3.9.1 → 5.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Capybara.md +5 -54
  5. data/Changelog.md +207 -77
  6. data/README.md +27 -21
  7. data/lib/generators/rspec.rb +0 -6
  8. data/lib/generators/rspec/channel/channel_generator.rb +12 -0
  9. data/lib/generators/rspec/{observer/templates/observer_spec.rb → channel/templates/channel_spec.rb.erb} +1 -1
  10. data/lib/generators/rspec/controller/controller_generator.rb +22 -5
  11. data/lib/generators/rspec/controller/templates/request_spec.rb +19 -0
  12. data/lib/generators/rspec/controller/templates/routing_spec.rb +13 -0
  13. data/lib/generators/rspec/feature/feature_generator.rb +2 -2
  14. data/lib/generators/rspec/{generators → generator}/generator_generator.rb +2 -2
  15. data/lib/generators/rspec/{generators → generator}/templates/generator_spec.rb +0 -0
  16. data/lib/generators/rspec/helper/helper_generator.rb +1 -1
  17. data/lib/generators/rspec/install/install_generator.rb +4 -4
  18. data/lib/generators/rspec/install/templates/spec/rails_helper.rb +17 -16
  19. data/lib/generators/rspec/integration/integration_generator.rb +3 -3
  20. data/lib/generators/rspec/mailbox/mailbox_generator.rb +14 -0
  21. data/lib/generators/rspec/mailbox/templates/mailbox_spec.rb.erb +7 -0
  22. data/lib/generators/rspec/mailer/mailer_generator.rb +2 -1
  23. data/lib/generators/rspec/mailer/templates/mailer_spec.rb +2 -2
  24. data/lib/generators/rspec/mailer/templates/preview.rb +1 -1
  25. data/lib/generators/rspec/model/model_generator.rb +5 -4
  26. data/lib/generators/rspec/model/templates/fixtures.yml +1 -1
  27. data/lib/generators/rspec/request/request_generator.rb +1 -1
  28. data/lib/generators/rspec/scaffold/scaffold_generator.rb +29 -19
  29. data/lib/generators/rspec/scaffold/templates/api_controller_spec.rb +0 -36
  30. data/lib/generators/rspec/scaffold/templates/api_request_spec.rb +131 -0
  31. data/lib/generators/rspec/scaffold/templates/controller_spec.rb +0 -48
  32. data/lib/generators/rspec/scaffold/templates/edit_spec.rb +1 -5
  33. data/lib/generators/rspec/scaffold/templates/index_spec.rb +2 -2
  34. data/lib/generators/rspec/scaffold/templates/new_spec.rb +1 -5
  35. data/lib/generators/rspec/scaffold/templates/request_spec.rb +137 -0
  36. data/lib/generators/rspec/scaffold/templates/routing_spec.rb +8 -10
  37. data/lib/generators/rspec/scaffold/templates/show_spec.rb +1 -1
  38. data/lib/generators/rspec/system/system_generator.rb +14 -16
  39. data/lib/generators/rspec/view/view_generator.rb +2 -2
  40. data/lib/rspec-rails.rb +13 -16
  41. data/lib/rspec/rails/adapters.rb +11 -76
  42. data/lib/rspec/rails/configuration.rb +81 -37
  43. data/lib/rspec/rails/example.rb +2 -0
  44. data/lib/rspec/rails/example/channel_example_group.rb +93 -0
  45. data/lib/rspec/rails/example/controller_example_group.rb +4 -4
  46. data/lib/rspec/rails/example/feature_example_group.rb +6 -26
  47. data/lib/rspec/rails/example/helper_example_group.rb +2 -9
  48. data/lib/rspec/rails/example/mailbox_example_group.rb +80 -0
  49. data/lib/rspec/rails/example/mailer_example_group.rb +2 -2
  50. data/lib/rspec/rails/example/rails_example_group.rb +1 -1
  51. data/lib/rspec/rails/example/request_example_group.rb +1 -4
  52. data/lib/rspec/rails/example/system_example_group.rb +29 -12
  53. data/lib/rspec/rails/example/view_example_group.rb +38 -27
  54. data/lib/rspec/rails/extensions/active_record/proxy.rb +5 -10
  55. data/lib/rspec/rails/feature_check.rb +12 -29
  56. data/lib/rspec/rails/file_fixture_support.rb +9 -11
  57. data/lib/rspec/rails/fixture_file_upload_support.rb +33 -17
  58. data/lib/rspec/rails/fixture_support.rb +34 -32
  59. data/lib/rspec/rails/matchers.rb +9 -0
  60. data/lib/rspec/rails/matchers/action_cable.rb +65 -0
  61. data/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +170 -0
  62. data/lib/rspec/rails/matchers/action_cable/have_streams.rb +58 -0
  63. data/lib/rspec/rails/matchers/action_mailbox.rb +73 -0
  64. data/lib/rspec/rails/matchers/active_job.rb +169 -21
  65. data/lib/rspec/rails/matchers/base_matcher.rb +5 -10
  66. data/lib/rspec/rails/matchers/have_enqueued_mail.rb +52 -28
  67. data/lib/rspec/rails/matchers/have_http_status.rb +11 -7
  68. data/lib/rspec/rails/matchers/have_rendered.rb +1 -0
  69. data/lib/rspec/rails/matchers/relation_match_array.rb +1 -1
  70. data/lib/rspec/rails/matchers/routing_matchers.rb +12 -12
  71. data/lib/rspec/rails/tasks/rspec.rake +7 -17
  72. data/lib/rspec/rails/vendor/capybara.rb +10 -15
  73. data/lib/rspec/rails/version.rb +1 -1
  74. data/lib/rspec/rails/view_path_builder.rb +1 -1
  75. data/lib/rspec/rails/view_rendering.rb +15 -4
  76. metadata +47 -35
  77. metadata.gz.sig +0 -0
  78. data/lib/generators/rspec/observer/observer_generator.rb +0 -13
@@ -1,3 +1,4 @@
1
+ # rubocop: disable Metrics/ModuleLength
1
2
  module RSpec
2
3
  module Rails
3
4
  # Fake class to document RSpec Rails configuration options. In practice,
@@ -25,44 +26,46 @@ module RSpec
25
26
  #
26
27
  # @api private
27
28
  DIRECTORY_MAPPINGS = {
28
- :controller => %w[spec controllers],
29
- :helper => %w[spec helpers],
30
- :job => %w[spec jobs],
31
- :mailer => %w[spec mailers],
32
- :model => %w[spec models],
33
- :request => %w[spec (requests|integration|api)],
34
- :routing => %w[spec routing],
35
- :view => %w[spec views],
36
- :feature => %w[spec features],
37
- :system => %w[spec system]
29
+ channel: %w[spec channels],
30
+ controller: %w[spec controllers],
31
+ helper: %w[spec helpers],
32
+ job: %w[spec jobs],
33
+ mailer: %w[spec mailers],
34
+ model: %w[spec models],
35
+ request: %w[spec (requests|integration|api)],
36
+ routing: %w[spec routing],
37
+ view: %w[spec views],
38
+ feature: %w[spec features],
39
+ system: %w[spec system],
40
+ mailbox: %w[spec mailboxes]
38
41
  }
39
42
 
40
43
  # Sets up the different example group modules for the different spec types
41
44
  #
42
45
  # @api private
43
46
  def self.add_test_type_configurations(config)
44
- config.include RSpec::Rails::ControllerExampleGroup, :type => :controller
45
- config.include RSpec::Rails::HelperExampleGroup, :type => :helper
46
- config.include RSpec::Rails::ModelExampleGroup, :type => :model
47
- config.include RSpec::Rails::RequestExampleGroup, :type => :request
48
- config.include RSpec::Rails::RoutingExampleGroup, :type => :routing
49
- config.include RSpec::Rails::ViewExampleGroup, :type => :view
50
- config.include RSpec::Rails::FeatureExampleGroup, :type => :feature
47
+ config.include RSpec::Rails::ControllerExampleGroup, type: :controller
48
+ config.include RSpec::Rails::HelperExampleGroup, type: :helper
49
+ config.include RSpec::Rails::ModelExampleGroup, type: :model
50
+ config.include RSpec::Rails::RequestExampleGroup, type: :request
51
+ config.include RSpec::Rails::RoutingExampleGroup, type: :routing
52
+ config.include RSpec::Rails::ViewExampleGroup, type: :view
53
+ config.include RSpec::Rails::FeatureExampleGroup, type: :feature
51
54
  config.include RSpec::Rails::Matchers
52
- config.include RSpec::Rails::SystemExampleGroup, :type => :system
55
+ config.include RSpec::Rails::SystemExampleGroup, type: :system
53
56
  end
54
57
 
55
58
  # @private
56
- # rubocop:disable Style/MethodLength
57
- def self.initialize_configuration(config)
59
+ def self.initialize_configuration(config) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity
58
60
  config.backtrace_exclusion_patterns << /vendor\//
59
61
  config.backtrace_exclusion_patterns << %r{lib/rspec/rails}
60
62
 
61
63
  # controller settings
62
- config.add_setting :infer_base_class_for_anonymous_controllers, :default => true
64
+ config.add_setting :infer_base_class_for_anonymous_controllers, default: true
63
65
 
64
66
  # fixture support
65
- config.add_setting :use_transactional_fixtures, :alias_with => :use_transactional_examples
67
+ config.add_setting :use_active_record, default: true
68
+ config.add_setting :use_transactional_fixtures, alias_with: :use_transactional_examples
66
69
  config.add_setting :use_instantiated_fixtures
67
70
  config.add_setting :global_fixtures
68
71
  config.add_setting :fixture_path
@@ -77,10 +80,8 @@ module RSpec
77
80
  # `RSpec::Rails::FixtureSupport` directly instead
78
81
  config.include RSpec::Rails::FixtureSupport
79
82
 
80
- if ::Rails::VERSION::STRING > '5'
81
- config.add_setting :file_fixture_path, :default => 'spec/fixtures/files'
82
- config.include RSpec::Rails::FileFixtureSupport
83
- end
83
+ config.add_setting :file_fixture_path, default: 'spec/fixtures/files'
84
+ config.include RSpec::Rails::FileFixtureSupport
84
85
 
85
86
  # Add support for fixture_path on fixture_file_upload
86
87
  config.include RSpec::Rails::FixtureFileUploadSupport
@@ -91,7 +92,7 @@ module RSpec
91
92
  # as a getter. This makes it easier for rspec-rails users because we use
92
93
  # `render_views` directly in example groups, so this aligns the two APIs,
93
94
  # but requires this workaround:
94
- config.add_setting :rendering_views, :default => false
95
+ config.add_setting :rendering_views, default: false
95
96
 
96
97
  config.instance_exec do
97
98
  def render_views=(val)
@@ -103,13 +104,47 @@ module RSpec
103
104
  end
104
105
 
105
106
  def render_views?
106
- rendering_views
107
+ rendering_views?
108
+ end
109
+
110
+ undef :rendering_views? if respond_to?(:rendering_views?)
111
+ def rendering_views?
112
+ !!rendering_views
113
+ end
114
+
115
+ # Define boolean predicates rather than relying on rspec-core due
116
+ # to the bug fix in rspec/rspec-core#2736, note some of these
117
+ # predicates are a bit nonsensical, but they exist for backwards
118
+ # compatibility, we can tidy these up in `rspec-rails` 5.
119
+ undef :fixture_path? if respond_to?(:fixture_path?)
120
+ def fixture_path?
121
+ !!fixture_path
122
+ end
123
+
124
+ undef :global_fixtures? if respond_to?(:global_fixtures?)
125
+ def global_fixtures?
126
+ !!global_fixtures
127
+ end
128
+
129
+ undef :infer_base_class_for_anonymous_controllers? if respond_to?(:infer_base_class_for_anonymous_controllers?)
130
+ def infer_base_class_for_anonymous_controllers?
131
+ !!infer_base_class_for_anonymous_controllers
132
+ end
133
+
134
+ undef :use_instantiated_fixtures? if respond_to?(:use_instantiated_fixtures?)
135
+ def use_instantiated_fixtures?
136
+ !!use_instantiated_fixtures
137
+ end
138
+
139
+ undef :use_transactional_fixtures? if respond_to?(:use_transactional_fixtures?)
140
+ def use_transactional_fixtures?
141
+ !!use_transactional_fixtures
107
142
  end
108
143
 
109
144
  def infer_spec_type_from_file_location!
110
145
  DIRECTORY_MAPPINGS.each do |type, dir_parts|
111
146
  escaped_path = Regexp.compile(dir_parts.join('[\\\/]') + '[\\\/]')
112
- define_derived_metadata(:file_path => escaped_path) do |metadata|
147
+ define_derived_metadata(file_path: escaped_path) do |metadata|
113
148
  metadata[:type] ||= type
114
149
  end
115
150
  end
@@ -127,22 +162,31 @@ module RSpec
127
162
 
128
163
  if defined?(::Rails::Controller::Testing)
129
164
  [:controller, :view, :request].each do |type|
130
- config.include ::Rails::Controller::Testing::TestProcess, :type => type
131
- config.include ::Rails::Controller::Testing::TemplateAssertions, :type => type
132
- config.include ::Rails::Controller::Testing::Integration, :type => type
165
+ config.include ::Rails::Controller::Testing::TestProcess, type: type
166
+ config.include ::Rails::Controller::Testing::TemplateAssertions, type: type
167
+ config.include ::Rails::Controller::Testing::Integration, type: type
133
168
  end
134
169
  end
135
170
 
136
- if defined?(ActionMailer)
137
- config.include RSpec::Rails::MailerExampleGroup, :type => :mailer
171
+ if RSpec::Rails::FeatureCheck.has_action_mailer?
172
+ config.include RSpec::Rails::MailerExampleGroup, type: :mailer
173
+ config.after { ActionMailer::Base.deliveries.clear }
174
+ end
175
+
176
+ if RSpec::Rails::FeatureCheck.has_active_job?
177
+ config.include RSpec::Rails::JobExampleGroup, type: :job
178
+ end
179
+
180
+ if RSpec::Rails::FeatureCheck.has_action_cable_testing?
181
+ config.include RSpec::Rails::ChannelExampleGroup, type: :channel
138
182
  end
139
183
 
140
- if defined?(ActiveJob)
141
- config.include RSpec::Rails::JobExampleGroup, :type => :job
184
+ if RSpec::Rails::FeatureCheck.has_action_mailbox?
185
+ config.include RSpec::Rails::MailboxExampleGroup, type: :mailbox
142
186
  end
143
187
  end
144
- # rubocop:enable Style/MethodLength
145
188
 
146
189
  initialize_configuration RSpec.configuration
147
190
  end
148
191
  end
192
+ # rubocop: enable Metrics/ModuleLength
@@ -9,3 +9,5 @@ require 'rspec/rails/example/model_example_group'
9
9
  require 'rspec/rails/example/job_example_group'
10
10
  require 'rspec/rails/example/feature_example_group'
11
11
  require 'rspec/rails/example/system_example_group'
12
+ require 'rspec/rails/example/channel_example_group'
13
+ require 'rspec/rails/example/mailbox_example_group'
@@ -0,0 +1,93 @@
1
+ require "rspec/rails/matchers/action_cable/have_streams"
2
+
3
+ module RSpec
4
+ module Rails
5
+ # @api public
6
+ # Container module for channel spec functionality. It is only available if
7
+ # ActionCable has been loaded before it.
8
+ module ChannelExampleGroup
9
+ # @private
10
+ module ClassMethods
11
+ # These blank modules are only necessary for YARD processing. It doesn't
12
+ # handle the conditional check below very well and reports undocumented objects.
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ if RSpec::Rails::FeatureCheck.has_action_cable_testing?
19
+ module RSpec
20
+ module Rails
21
+ # @api public
22
+ # Container module for channel spec functionality.
23
+ module ChannelExampleGroup
24
+ extend ActiveSupport::Concern
25
+ include RSpec::Rails::RailsExampleGroup
26
+ include ActionCable::Connection::TestCase::Behavior
27
+ include ActionCable::Channel::TestCase::Behavior
28
+
29
+ # Class-level DSL for channel specs.
30
+ module ClassMethods
31
+ # @private
32
+ def channel_class
33
+ (_channel_class || described_class).tap do |klass|
34
+ next if klass <= ::ActionCable::Channel::Base
35
+
36
+ raise "Described class is not a channel class.\n" \
37
+ "Specify the channel class in the `describe` statement " \
38
+ "or set it manually using `tests MyChannelClass`"
39
+ end
40
+ end
41
+
42
+ # @private
43
+ def connection_class
44
+ (_connection_class || described_class).tap do |klass|
45
+ next if klass <= ::ActionCable::Connection::Base
46
+
47
+ raise "Described class is not a connection class.\n" \
48
+ "Specify the connection class in the `describe` statement " \
49
+ "or set it manually using `tests MyConnectionClass`"
50
+ end
51
+ end
52
+ end
53
+
54
+ # Checks that the connection attempt has been rejected.
55
+ #
56
+ # @example
57
+ # expect { connect }.to have_rejected_connection
58
+ def have_rejected_connection
59
+ raise_error(::ActionCable::Connection::Authorization::UnauthorizedError)
60
+ end
61
+
62
+ # Checks that the subscription is subscribed to at least one stream.
63
+ #
64
+ # @example
65
+ # expect(subscription).to have_streams
66
+ def have_streams
67
+ check_subscribed!
68
+
69
+ RSpec::Rails::Matchers::ActionCable::HaveStream.new
70
+ end
71
+
72
+ # Checks that the channel has been subscribed to the given stream
73
+ #
74
+ # @example
75
+ # expect(subscription).to have_stream_from("chat_1")
76
+ def have_stream_from(stream)
77
+ check_subscribed!
78
+
79
+ RSpec::Rails::Matchers::ActionCable::HaveStream.new(stream)
80
+ end
81
+
82
+ # Checks that the channel has been subscribed to a stream for the given model
83
+ #
84
+ # @example
85
+ # expect(subscription).to have_stream_for(user)
86
+ def have_stream_for(object)
87
+ check_subscribed!
88
+ RSpec::Rails::Matchers::ActionCable::HaveStream.new(broadcasting_for(object))
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -94,9 +94,9 @@ module RSpec
94
94
  self.routes = ActionDispatch::Routing::RouteSet.new.tap do |r|
95
95
  r.draw do
96
96
  resources resource_name,
97
- :as => resource_as,
98
- :module => resource_module,
99
- :path => resource_path
97
+ as: resource_as,
98
+ module: resource_module,
99
+ path: resource_path
100
100
  end
101
101
  end
102
102
  end
@@ -159,7 +159,7 @@ module RSpec
159
159
  #
160
160
  # expect do
161
161
  # bypass_rescue
162
- # get :show, :id => profile.id + 1
162
+ # get :show, id: profile.id + 1
163
163
  # end.to raise_error(/403 Forbidden/)
164
164
  # end
165
165
  # end
@@ -37,37 +37,17 @@ end
37
37
 
38
38
  unless RSpec.respond_to?(:feature)
39
39
  opts = {
40
- :capybara_feature => true,
41
- :type => :feature,
42
- :skip => <<-EOT.squish
43
- Feature specs require the Capybara (http://github.com/jnicklas/capybara)
44
- gem, version 2.2.0 or later. We recommend version 2.4.0 or later to avoid
45
- some deprecation warnings and have support for
46
- `config.expose_dsl_globally = false`.
40
+ capybara_feature: true,
41
+ type: :feature,
42
+ skip: <<-EOT.squish
43
+ Feature specs require the Capybara (https://github.com/teamcapybara/capybara)
44
+ gem, version 2.13.0 or later.
47
45
  EOT
48
46
  }
49
47
 
50
- # Capybara's monkey patching causes us to have to jump through some hoops
51
- top_level = self
52
- main_feature = nil
53
- if defined?(Capybara) && ::Capybara::VERSION.to_f < 2.4
54
- # Capybara 2.2 and 2.3 do not use `alias_example_xyz`
55
- opts[:skip] = <<-EOT.squish
56
- Capybara < 2.4.0 does not support RSpec's namespace or
57
- `config.expose_dsl_globally = false`. Upgrade to Capybara >= 2.4.0.
58
- EOT
59
- main_feature = top_level.method(:feature) if top_level.respond_to?(:feature)
60
- end
61
-
62
48
  RSpec.configure do |c|
63
- main_feature = nil unless c.expose_dsl_globally?
64
49
  c.alias_example_group_to :feature, opts
65
50
  c.alias_example_to :scenario
66
- c.alias_example_to :xscenario, :skip => 'Temporarily skipped with xscenario'
51
+ c.alias_example_to :xscenario, skip: 'Temporarily skipped with xscenario'
67
52
  end
68
-
69
- # Due to load order issues and `config.expose_dsl_globally?` defaulting to
70
- # `true` we need to put Capybara's monkey patch method back. Otherwise,
71
- # app upgrades have a high likelyhood of having all feature specs skipped.
72
- top_level.define_singleton_method(:feature, &main_feature) if main_feature
73
53
  end
@@ -12,15 +12,8 @@ module RSpec
12
12
 
13
13
  # @private
14
14
  module ClassMethods
15
- if ::Rails::VERSION::MAJOR > 3
16
- def determine_constant_from_test_name(_ignore)
17
- described_class if yield(described_class)
18
- end
19
- else
20
- def determine_default_helper_class(_ignore)
21
- return unless Module === described_class && !(Class === described_class)
22
- described_class
23
- end
15
+ def determine_constant_from_test_name(_ignore)
16
+ described_class if yield(described_class)
24
17
  end
25
18
  end
26
19
 
@@ -0,0 +1,80 @@
1
+ module RSpec
2
+ module Rails
3
+ # @api public
4
+ # Container module for mailbox spec functionality.
5
+ module MailboxExampleGroup
6
+ extend ActiveSupport::Concern
7
+
8
+ if RSpec::Rails::FeatureCheck.has_action_mailbox?
9
+ require 'action_mailbox/test_helper'
10
+ extend ::ActionMailbox::TestHelper
11
+
12
+ # @private
13
+ def self.create_inbound_email(arg)
14
+ case arg
15
+ when Hash
16
+ create_inbound_email_from_mail(**arg)
17
+ else
18
+ create_inbound_email_from_source(arg.to_s)
19
+ end
20
+ end
21
+ else
22
+ def self.create_inbound_email(_arg)
23
+ raise "Could not load ActionMailer::TestHelper"
24
+ end
25
+ end
26
+
27
+ class_methods do
28
+ # @private
29
+ def mailbox_class
30
+ described_class
31
+ end
32
+ end
33
+
34
+ included do
35
+ subject { described_class }
36
+ end
37
+
38
+ # @api public
39
+ # Passes if the inbound email was delivered
40
+ #
41
+ # @example
42
+ # inbound_email = process(args)
43
+ # expect(inbound_email).to have_been_delivered
44
+ def have_been_delivered
45
+ satisfy('have been delivered', &:delivered?)
46
+ end
47
+
48
+ # @api public
49
+ # Passes if the inbound email bounced during processing
50
+ #
51
+ # @example
52
+ # inbound_email = process(args)
53
+ # expect(inbound_email).to have_bounced
54
+ def have_bounced
55
+ satisfy('have bounced', &:bounced?)
56
+ end
57
+
58
+ # @api public
59
+ # Passes if the inbound email failed to process
60
+ #
61
+ # @example
62
+ # inbound_email = process(args)
63
+ # expect(inbound_email).to have_failed
64
+ def have_failed
65
+ satisfy('have failed', &:failed?)
66
+ end
67
+
68
+ # Process an inbound email message directly, bypassing routing.
69
+ #
70
+ # @param message [Hash, Mail::Message] a mail message or hash of
71
+ # attributes used to build one
72
+ # @return [ActionMaibox::InboundMessage]
73
+ def process(message)
74
+ MailboxExampleGroup.create_inbound_email(message).tap do |mail|
75
+ self.class.mailbox_class.receive(mail)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end