rspec-rails 4.0.0.beta2 → 4.0.0.beta3

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 (32) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Changelog.md +105 -83
  5. data/README.md +1 -1
  6. data/lib/generators/rspec/channel/channel_generator.rb +12 -0
  7. data/lib/generators/rspec/channel/templates/channel_spec.rb.erb +7 -0
  8. data/lib/generators/rspec/controller/controller_generator.rb +11 -2
  9. data/lib/generators/rspec/controller/templates/routing_spec.rb +13 -0
  10. data/lib/generators/rspec/mailbox/mailbox_generator.rb +14 -0
  11. data/lib/generators/rspec/mailbox/templates/mailbox_spec.rb.erb +7 -0
  12. data/lib/generators/rspec/model/templates/fixtures.yml +1 -1
  13. data/lib/rspec/rails/configuration.rb +15 -5
  14. data/lib/rspec/rails/example.rb +2 -0
  15. data/lib/rspec/rails/example/channel_example_group.rb +93 -0
  16. data/lib/rspec/rails/example/feature_example_group.rb +1 -1
  17. data/lib/rspec/rails/example/mailbox_example_group.rb +80 -0
  18. data/lib/rspec/rails/example/mailer_example_group.rb +1 -1
  19. data/lib/rspec/rails/example/system_example_group.rb +14 -2
  20. data/lib/rspec/rails/example/view_example_group.rb +29 -8
  21. data/lib/rspec/rails/feature_check.rb +16 -0
  22. data/lib/rspec/rails/matchers.rb +10 -0
  23. data/lib/rspec/rails/matchers/action_cable.rb +65 -0
  24. data/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +170 -0
  25. data/lib/rspec/rails/matchers/action_cable/have_streams.rb +58 -0
  26. data/lib/rspec/rails/matchers/action_mailbox.rb +64 -0
  27. data/lib/rspec/rails/matchers/active_job.rb +16 -5
  28. data/lib/rspec/rails/matchers/have_enqueued_mail.rb +44 -22
  29. data/lib/rspec/rails/matchers/routing_matchers.rb +1 -1
  30. data/lib/rspec/rails/version.rb +1 -1
  31. metadata +15 -4
  32. metadata.gz.sig +0 -0
data/README.md CHANGED
@@ -12,7 +12,7 @@ Use **[`rspec-rails` 1.x][]** for Rails 2.x.
12
12
 
13
13
  [Build Status]: https://secure.travis-ci.org/rspec/rspec-rails.svg?branch=master
14
14
  [travis-ci]: https://travis-ci.org/rspec/rspec-rails
15
- [Code Climate]: https://img.shields.io/codeclimate/github/rspec/rspec-rails.svg
15
+ [Code Climate]: https://codeclimate.com/github/rspec/rspec-rails.svg
16
16
  [code-climate]: https://codeclimate.com/github/rspec/rspec-rails
17
17
  [Gem Version]: https://badge.fury.io/rb/rspec-rails.svg
18
18
  [gem-version]: https://badge.fury.io/rb/rspec-rails
@@ -0,0 +1,12 @@
1
+ require 'generators/rspec'
2
+
3
+ module Rspec
4
+ module Generators
5
+ # @private
6
+ class ChannelGenerator < Base
7
+ def create_channel_spec
8
+ template 'channel_spec.rb.erb', File.join('spec/channels', class_path, "#{file_name}_channel_spec.rb")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ require 'rails_helper'
2
+
3
+ <% module_namespacing do -%>
4
+ RSpec.describe <%= class_name %>Channel, <%= type_metatag(:channel) %> do
5
+ pending "add some examples to (or delete) #{__FILE__}"
6
+ end
7
+ <% end -%>
@@ -7,8 +7,9 @@ module Rspec
7
7
  argument :actions, :type => :array, :default => [], :banner => "action action"
8
8
 
9
9
  class_option :template_engine, :desc => "Template engine to generate view files"
10
- class_option :controller_specs, :type => :boolean, :default => true
11
- class_option :view_specs, :type => :boolean, :default => true
10
+ class_option :controller_specs, :type => :boolean, :default => true, :desc => "Generate controller specs"
11
+ class_option :view_specs, :type => :boolean, :default => true, :desc => "Generate view specs"
12
+ class_option :routing_specs, :type => :boolean, :default => false, :desc => "Generate routing specs"
12
13
 
13
14
  def generate_controller_spec
14
15
  return unless options[:controller_specs]
@@ -29,6 +30,14 @@ module Rspec
29
30
  File.join("spec", "views", file_path, "#{@action}.html.#{options[:template_engine]}_spec.rb")
30
31
  end
31
32
  end
33
+
34
+ def generate_routing_spec
35
+ return if actions.empty?
36
+ return unless options[:routing_specs]
37
+
38
+ template 'routing_spec.rb',
39
+ File.join('spec/routing', class_path, "#{file_name}_routing_spec.rb")
40
+ end
32
41
  end
33
42
  end
34
43
  end
@@ -0,0 +1,13 @@
1
+ require 'rails_helper'
2
+
3
+ <% module_namespacing do -%>
4
+ RSpec.describe '<%= class_name %>Controller', <%= type_metatag(:routing) %> do
5
+ describe 'routing' do
6
+ <% for action in actions -%>
7
+ it 'routes to #<%= action %>' do
8
+ expect(:get => "/<%= class_name.underscore %>/<%= action %>").to route_to("<%= class_name.underscore %>#<%= action %>")
9
+ end
10
+ <% end -%>
11
+ end
12
+ end
13
+ <% end -%>
@@ -0,0 +1,14 @@
1
+ require 'generators/rspec'
2
+
3
+ module Rspec
4
+ module Generators
5
+ # @private
6
+ class MailboxGenerator < Base
7
+ def create_mailbox_spec
8
+ template('mailbox_spec.rb.erb',
9
+ File.join('spec/mailboxes', class_path, "#{file_name}_mailbox_spec.rb")
10
+ )
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ require 'rails_helper'
2
+
3
+ <% module_namespacing do -%>
4
+ RSpec.describe <%= class_name %>Mailbox, <%= type_metatag(:mailbox) %> do
5
+ pending "add some examples to (or delete) #{__FILE__}"
6
+ end
7
+ <% end -%>
@@ -1,4 +1,4 @@
1
- # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
1
+ # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2
2
 
3
3
  <% unless attributes.empty? -%>
4
4
  one:
@@ -25,6 +25,7 @@ module RSpec
25
25
  #
26
26
  # @api private
27
27
  DIRECTORY_MAPPINGS = {
28
+ :channel => %w[spec channels],
28
29
  :controller => %w[spec controllers],
29
30
  :helper => %w[spec helpers],
30
31
  :job => %w[spec jobs],
@@ -34,7 +35,8 @@ module RSpec
34
35
  :routing => %w[spec routing],
35
36
  :view => %w[spec views],
36
37
  :feature => %w[spec features],
37
- :system => %w[spec system]
38
+ :system => %w[spec system],
39
+ :mailbox => %w[spec mailboxes]
38
40
  }
39
41
 
40
42
  # Sets up the different example group modules for the different spec types
@@ -53,7 +55,7 @@ module RSpec
53
55
  end
54
56
 
55
57
  # @private
56
- # rubocop:disable Style/MethodLength
58
+ # rubocop:disable Metrics/MethodLength
57
59
  def self.initialize_configuration(config)
58
60
  config.backtrace_exclusion_patterns << /vendor\//
59
61
  config.backtrace_exclusion_patterns << %r{lib/rspec/rails}
@@ -133,15 +135,23 @@ module RSpec
133
135
  end
134
136
  end
135
137
 
136
- if defined?(ActionMailer)
138
+ if RSpec::Rails::FeatureCheck.has_action_mailer?
137
139
  config.include RSpec::Rails::MailerExampleGroup, :type => :mailer
138
140
  end
139
141
 
140
- if defined?(ActiveJob)
142
+ if RSpec::Rails::FeatureCheck.has_active_job?
141
143
  config.include RSpec::Rails::JobExampleGroup, :type => :job
142
144
  end
145
+
146
+ if RSpec::Rails::FeatureCheck.has_action_cable_testing?
147
+ config.include RSpec::Rails::ChannelExampleGroup, :type => :channel
148
+ end
149
+
150
+ if RSpec::Rails::FeatureCheck.has_action_mailbox?
151
+ config.include RSpec::Rails::MailboxExampleGroup, :type => :mailbox
152
+ end
143
153
  end
144
- # rubocop:enable Style/MethodLength
154
+ # rubocop:enable Metrics/MethodLength
145
155
 
146
156
  initialize_configuration RSpec.configuration
147
157
  end
@@ -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
@@ -40,7 +40,7 @@ unless RSpec.respond_to?(:feature)
40
40
  :capybara_feature => true,
41
41
  :type => :feature,
42
42
  :skip => <<-EOT.squish
43
- Feature specs require the Capybara (http://github.com/jnicklas/capybara)
43
+ Feature specs require the Capybara (https://github.com/jnicklas/capybara)
44
44
  gem, version 2.2.0 or later. We recommend version 2.4.0 or later to avoid
45
45
  some deprecation warnings and have support for
46
46
  `config.expose_dsl_globally = false`.
@@ -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
@@ -22,7 +22,7 @@ if defined?(ActionMailer)
22
22
  included do
23
23
  include ::Rails.application.routes.url_helpers
24
24
  options = ::Rails.configuration.action_mailer.default_url_options
25
- options.each { |key, value| default_url_options[key] = value } if options
25
+ options&.each { |key, value| default_url_options[key] = value }
26
26
  end
27
27
 
28
28
  # Class-level DSL for mailer specs.
@@ -15,7 +15,11 @@ module RSpec
15
15
  CHARS_TO_TRANSLATE = ['/', '.', ':', ',', "'", '"', " "].freeze
16
16
 
17
17
  # @private
18
- module BlowAwayAfterTeardownHook
18
+ module BlowAwayTeardownHooks
19
+ # @private
20
+ def before_teardown
21
+ end
22
+
19
23
  # @private
20
24
  def after_teardown
21
25
  end
@@ -59,13 +63,18 @@ module RSpec
59
63
  """.gsub(/\s+/, ' ').strip
60
64
  end
61
65
 
66
+ if ::Rails::VERSION::STRING >= '6.0'
67
+ original_before_teardown =
68
+ ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.instance_method(:before_teardown)
69
+ end
70
+
62
71
  original_after_teardown =
63
72
  ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown.instance_method(:after_teardown)
64
73
 
65
74
  other.include ActionDispatch::IntegrationTest::Behavior
66
75
  other.include ::ActionDispatch::SystemTesting::TestHelpers::SetupAndTeardown
67
76
  other.include ::ActionDispatch::SystemTesting::TestHelpers::ScreenshotHelper
68
- other.include BlowAwayAfterTeardownHook
77
+ other.include BlowAwayTeardownHooks
69
78
 
70
79
  attr_reader :driver
71
80
 
@@ -93,6 +102,9 @@ module RSpec
93
102
  orig_stdout = $stdout
94
103
  $stdout = StringIO.new
95
104
  begin
105
+ if ::Rails::VERSION::STRING >= '6.0'
106
+ original_before_teardown.bind(self).call
107
+ end
96
108
  original_after_teardown.bind(self).call
97
109
  ensure
98
110
  myio = $stdout
@@ -129,14 +129,35 @@ module RSpec
129
129
 
130
130
  def _default_render_options
131
131
  if ::Rails::VERSION::STRING >= '3.2'
132
- # pluck the handler, format, and locale out of, eg, posts/index.de.html.haml
133
- template, *components = _default_file_to_render.split('.')
134
- handler, format, locale = *components.reverse
135
-
136
- render_options = { :template => template }
137
- render_options[:handlers] = [handler] if handler
138
- render_options[:formats] = [format.to_sym] if format
139
- render_options[:locales] = [locale] if locale
132
+ formats = if ActionView::Template::Types.respond_to?(:symbols)
133
+ ActionView::Template::Types.symbols
134
+ else
135
+ [:html, :text, :js, :css, :xml, :json].map(&:to_s)
136
+ end.map { |x| Regexp.escape(x) }.join("|")
137
+
138
+ handlers = ActionView::Template::Handlers.extensions.map { |x| Regexp.escape(x) }.join("|")
139
+ locales = "[a-z]{2}(?:-[A-Z]{2})?"
140
+ variants = "[^.]*"
141
+ path_regex = %r{
142
+ \A
143
+ (?<template>.*?)
144
+ (?:\.(?<locale>#{locales}))??
145
+ (?:\.(?<format>#{formats}))??
146
+ (?:\+(?<variant>#{variants}))??
147
+ (?:\.(?<handler>#{handlers}))?
148
+ \z
149
+ }x
150
+
151
+ # This regex should always find a match.
152
+ # Worst case, everything will be nil, and :template will just be
153
+ # the original string.
154
+ match = path_regex.match(_default_file_to_render)
155
+
156
+ render_options = { :template => match[:template] }
157
+ render_options[:handlers] = [match[:handler]] if match[:handler]
158
+ render_options[:formats] = [match[:format].to_sym] if match[:format]
159
+ render_options[:locales] = [match[:locale]] if match[:locale]
160
+ render_options[:variants] = [match[:variant]] if match[:variant]
140
161
 
141
162
  render_options
142
163
  else