rspec-rails 4.0.0.beta2 → 4.0.0.beta3

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