rspec-rails 3.0.2 → 7.1.1

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 (105) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +3 -1
  5. data/Capybara.md +6 -55
  6. data/Changelog.md +805 -47
  7. data/{License.txt → LICENSE.md} +5 -3
  8. data/README.md +278 -444
  9. data/lib/generators/rspec/channel/channel_generator.rb +12 -0
  10. data/lib/generators/rspec/{observer/templates/observer_spec.rb → channel/templates/channel_spec.rb.erb} +1 -1
  11. data/lib/generators/rspec/controller/controller_generator.rb +24 -7
  12. data/lib/generators/rspec/controller/templates/controller_spec.rb +3 -3
  13. data/lib/generators/rspec/controller/templates/request_spec.rb +19 -0
  14. data/lib/generators/rspec/controller/templates/routing_spec.rb +13 -0
  15. data/lib/generators/rspec/controller/templates/view_spec.rb +1 -1
  16. data/lib/generators/rspec/feature/feature_generator.rb +15 -2
  17. data/lib/generators/rspec/feature/templates/feature_singular_spec.rb +5 -0
  18. data/lib/generators/rspec/feature/templates/feature_spec.rb +1 -1
  19. data/lib/generators/rspec/generator/generator_generator.rb +24 -0
  20. data/lib/generators/rspec/generator/templates/generator_spec.rb +5 -0
  21. data/lib/generators/rspec/helper/helper_generator.rb +2 -2
  22. data/lib/generators/rspec/helper/templates/helper_spec.rb +1 -1
  23. data/lib/generators/rspec/install/install_generator.rb +41 -7
  24. data/lib/generators/rspec/install/templates/spec/rails_helper.rb +63 -22
  25. data/lib/generators/rspec/job/job_generator.rb +13 -0
  26. data/lib/generators/rspec/job/templates/job_spec.rb.erb +7 -0
  27. data/lib/generators/rspec/mailbox/mailbox_generator.rb +14 -0
  28. data/lib/generators/rspec/mailbox/templates/mailbox_spec.rb.erb +7 -0
  29. data/lib/generators/rspec/mailer/mailer_generator.rb +12 -3
  30. data/lib/generators/rspec/mailer/templates/mailer_spec.rb +2 -2
  31. data/lib/generators/rspec/mailer/templates/preview.rb +13 -0
  32. data/lib/generators/rspec/model/model_generator.rb +20 -6
  33. data/lib/generators/rspec/model/templates/fixtures.yml +1 -1
  34. data/lib/generators/rspec/model/templates/model_spec.rb +1 -1
  35. data/lib/generators/rspec/request/request_generator.rb +17 -0
  36. data/lib/generators/rspec/request/templates/request_spec.rb +10 -0
  37. data/lib/generators/rspec/scaffold/scaffold_generator.rb +90 -113
  38. data/lib/generators/rspec/scaffold/templates/api_controller_spec.rb +129 -0
  39. data/lib/generators/rspec/scaffold/templates/api_request_spec.rb +131 -0
  40. data/lib/generators/rspec/scaffold/templates/controller_spec.rb +46 -64
  41. data/lib/generators/rspec/scaffold/templates/edit_spec.rb +11 -7
  42. data/lib/generators/rspec/scaffold/templates/index_spec.rb +4 -3
  43. data/lib/generators/rspec/scaffold/templates/new_spec.rb +4 -4
  44. data/lib/generators/rspec/scaffold/templates/request_spec.rb +138 -0
  45. data/lib/generators/rspec/scaffold/templates/routing_spec.rb +18 -11
  46. data/lib/generators/rspec/scaffold/templates/show_spec.rb +3 -3
  47. data/lib/generators/rspec/system/system_generator.rb +24 -0
  48. data/lib/generators/rspec/system/templates/system_spec.rb +9 -0
  49. data/lib/generators/rspec/view/templates/view_spec.rb +1 -1
  50. data/lib/generators/rspec/view/view_generator.rb +4 -4
  51. data/lib/generators/rspec.rb +30 -11
  52. data/lib/rspec/rails/active_record.rb +25 -0
  53. data/lib/rspec/rails/adapters.rb +46 -29
  54. data/lib/rspec/rails/configuration.rb +165 -41
  55. data/lib/rspec/rails/example/channel_example_group.rb +93 -0
  56. data/lib/rspec/rails/example/controller_example_group.rb +185 -149
  57. data/lib/rspec/rails/example/feature_example_group.rb +43 -23
  58. data/lib/rspec/rails/example/helper_example_group.rb +28 -25
  59. data/lib/rspec/rails/example/job_example_group.rb +23 -0
  60. data/lib/rspec/rails/example/mailbox_example_group.rb +80 -0
  61. data/lib/rspec/rails/example/mailer_example_group.rb +27 -22
  62. data/lib/rspec/rails/example/model_example_group.rb +9 -6
  63. data/lib/rspec/rails/example/rails_example_group.rb +9 -2
  64. data/lib/rspec/rails/example/request_example_group.rb +21 -17
  65. data/lib/rspec/rails/example/routing_example_group.rb +47 -39
  66. data/lib/rspec/rails/example/system_example_group.rb +180 -0
  67. data/lib/rspec/rails/example/view_example_group.rb +179 -134
  68. data/lib/rspec/rails/example.rb +4 -0
  69. data/lib/rspec/rails/extensions/active_record/proxy.rb +5 -11
  70. data/lib/rspec/rails/feature_check.rb +51 -0
  71. data/lib/rspec/rails/file_fixture_support.rb +18 -0
  72. data/lib/rspec/rails/fixture_file_upload_support.rb +45 -0
  73. data/lib/rspec/rails/fixture_support.rb +70 -14
  74. data/lib/rspec/rails/matchers/action_cable/have_broadcasted_to.rb +180 -0
  75. data/lib/rspec/rails/matchers/action_cable/have_streams.rb +58 -0
  76. data/lib/rspec/rails/matchers/action_cable.rb +70 -0
  77. data/lib/rspec/rails/matchers/action_mailbox.rb +73 -0
  78. data/lib/rspec/rails/matchers/active_job.rb +526 -0
  79. data/lib/rspec/rails/matchers/base_matcher.rb +179 -0
  80. data/lib/rspec/rails/matchers/be_a_new.rb +70 -64
  81. data/lib/rspec/rails/matchers/be_new_record.rb +25 -20
  82. data/lib/rspec/rails/matchers/be_valid.rb +39 -34
  83. data/lib/rspec/rails/matchers/have_enqueued_mail.rb +259 -0
  84. data/lib/rspec/rails/matchers/have_http_status.rb +359 -333
  85. data/lib/rspec/rails/matchers/have_rendered.rb +55 -32
  86. data/lib/rspec/rails/matchers/redirect_to.rb +30 -27
  87. data/lib/rspec/rails/matchers/relation_match_array.rb +1 -1
  88. data/lib/rspec/rails/matchers/routing_matchers.rb +107 -101
  89. data/lib/rspec/rails/matchers/send_email.rb +122 -0
  90. data/lib/rspec/rails/matchers.rb +21 -12
  91. data/lib/rspec/rails/tasks/rspec.rake +9 -17
  92. data/lib/rspec/rails/vendor/capybara.rb +10 -11
  93. data/lib/rspec/rails/version.rb +1 -1
  94. data/lib/rspec/rails/view_assigns.rb +1 -20
  95. data/lib/rspec/rails/view_path_builder.rb +29 -0
  96. data/lib/rspec/rails/view_rendering.rb +89 -27
  97. data/lib/rspec/rails/view_spec_methods.rb +56 -0
  98. data/lib/rspec/rails.rb +9 -1
  99. data/lib/rspec-rails.rb +83 -3
  100. data.tar.gz.sig +0 -0
  101. metadata +108 -78
  102. metadata.gz.sig +3 -2
  103. data/lib/generators/rspec/integration/integration_generator.rb +0 -17
  104. data/lib/generators/rspec/integration/templates/request_spec.rb +0 -10
  105. data/lib/generators/rspec/observer/observer_generator.rb +0 -13
@@ -13,34 +13,15 @@ module RSpec
13
13
  end
14
14
 
15
15
  # Compat-shim for AbstractController::Rendering#view_assigns
16
- #
17
- # _assigns was deprecated in favor of view_assigns after
18
- # Rails-3.0.0 was released. Since we are not able to predict when
19
- # the _assigns/view_assigns patch will be released (I thought it
20
- # would have been in 3.0.1, but 3.0.1 bypassed this change for a
21
- # security fix), this bit ensures that we do the right thing without
22
- # knowing anything about the Rails version we are dealing with.
23
- #
24
- # Once that change _is_ released, this can be changed to something
25
- # that checks for the Rails version when the module is being
26
- # interpreted, as it was before commit dd0095.
27
16
  def view_assigns
28
17
  super.merge(_encapsulated_assigns)
29
- rescue
30
- _assigns
31
- end
32
-
33
- # @private
34
- def _assigns
35
- super.merge(_encapsulated_assigns)
36
18
  end
37
19
 
38
- private
20
+ private
39
21
 
40
22
  def _encapsulated_assigns
41
23
  @_encapsulated_assigns ||= {}
42
24
  end
43
-
44
25
  end
45
26
  end
46
27
  end
@@ -0,0 +1,29 @@
1
+ module RSpec
2
+ module Rails
3
+ # Builds paths for view specs using a particular route set.
4
+ class ViewPathBuilder
5
+ def initialize(route_set)
6
+ self.class.send(:include, route_set.url_helpers)
7
+ end
8
+
9
+ # Given a hash of parameters, build a view path, if possible.
10
+ # Returns nil if no path can be built from the given params.
11
+ #
12
+ # @example
13
+ # # path can be built because all required params are present in the hash
14
+ # view_path_builder = ViewPathBuilder.new(::Rails.application.routes)
15
+ # view_path_builder.path_for({ :controller => 'posts', :action => 'show', :id => '54' })
16
+ # # => "/post/54"
17
+ #
18
+ # @example
19
+ # # path cannot be built because the params are missing a required element (:id)
20
+ # view_path_builder.path_for({ :controller => 'posts', :action => 'delete' })
21
+ # # => ActionController::UrlGenerationError: No route matches {:action=>"delete", :controller=>"posts"}
22
+ def path_for(path_params)
23
+ url_for(path_params.merge(only_path: true))
24
+ rescue => e
25
+ e.message
26
+ end
27
+ end
28
+ end
29
+ end
@@ -2,16 +2,23 @@ require 'action_view/testing/resolvers'
2
2
 
3
3
  module RSpec
4
4
  module Rails
5
+ # @api public
5
6
  # Helpers for optionally rendering views in controller specs.
6
7
  module ViewRendering
7
8
  extend ActiveSupport::Concern
8
9
 
9
- attr_accessor :controller
10
+ # @!attribute [r]
11
+ # Returns the controller object instance under test.
12
+ attr_reader :controller
13
+
14
+ # @private
15
+ attr_writer :controller
16
+ private :controller=
10
17
 
11
18
  # DSL methods
12
19
  module ClassMethods
13
20
  # @see RSpec::Rails::ControllerExampleGroup
14
- def render_views(true_or_false=true)
21
+ def render_views(true_or_false = true)
15
22
  @render_views = true_or_false
16
23
  end
17
24
 
@@ -32,35 +39,85 @@ module RSpec
32
39
  self.class.render_views? || !controller.class.respond_to?(:view_paths)
33
40
  end
34
41
 
35
- # Delegates find_all to the submitted path set and then returns templates
36
- # with modified source
37
- #
38
42
  # @private
39
- class EmptyTemplatePathSetDecorator < ::ActionView::Resolver
40
- attr_reader :original_path_set
41
-
42
- def initialize(original_path_set)
43
- @original_path_set = original_path_set
43
+ class EmptyTemplateResolver
44
+ def self.build(path)
45
+ if path.is_a?(::ActionView::Resolver)
46
+ ResolverDecorator.new(path)
47
+ else
48
+ FileSystemResolver.new(path)
49
+ end
44
50
  end
45
51
 
46
- def find_all(*args)
47
- original_path_set.find_all(*args).collect do |template|
52
+ def self.nullify_template_rendering(templates)
53
+ templates.map do |template|
48
54
  ::ActionView::Template.new(
49
55
  "",
50
56
  template.identifier,
51
57
  EmptyTemplateHandler,
52
- {
53
- :virtual_path => template.virtual_path,
54
- :format => template.formats
55
- }
58
+ virtual_path: template.virtual_path,
59
+ format: template_format(template),
60
+ locals: []
56
61
  )
57
62
  end
58
63
  end
64
+
65
+ def self.template_format(template)
66
+ template.format
67
+ end
68
+
69
+ # Delegates all methods to the submitted resolver and for all methods
70
+ # that return a collection of `ActionView::Template` instances, return
71
+ # templates with modified source
72
+ #
73
+ # @private
74
+ class ResolverDecorator < ::ActionView::Resolver
75
+ (::ActionView::Resolver.instance_methods - Object.instance_methods).each do |method|
76
+ undef_method method
77
+ end
78
+
79
+ (::ActionView::Resolver.methods - Object.methods).each do |method|
80
+ singleton_class.undef_method method
81
+ end
82
+
83
+ def initialize(resolver)
84
+ @resolver = resolver
85
+ end
86
+
87
+ def method_missing(name, *args, &block)
88
+ result = @resolver.send(name, *args, &block)
89
+ nullify_templates(result)
90
+ end
91
+
92
+ private
93
+
94
+ def nullify_templates(collection)
95
+ return collection unless collection.is_a?(Enumerable)
96
+ return collection unless collection.all? { |element| element.is_a?(::ActionView::Template) }
97
+
98
+ EmptyTemplateResolver.nullify_template_rendering(collection)
99
+ end
100
+ end
101
+
102
+ # Delegates find_templates to the submitted path set and then returns
103
+ # templates with modified source
104
+ #
105
+ # @private
106
+ class FileSystemResolver < ::ActionView::FileSystemResolver
107
+ private
108
+
109
+ def find_templates(*args)
110
+ templates = super
111
+ EmptyTemplateResolver.nullify_template_rendering(templates)
112
+ end
113
+ end
59
114
  end
60
115
 
61
116
  # @private
62
117
  class EmptyTemplateHandler
63
- def self.call(template)
118
+ def self.call(_template, _source = nil)
119
+ ::Rails.logger.info(" Template rendering was prevented by rspec-rails. Use `render_views` to verify rendered view contents if necessary.")
120
+
64
121
  %("")
65
122
  end
66
123
  end
@@ -70,33 +127,38 @@ module RSpec
70
127
  # @private
71
128
  module EmptyTemplates
72
129
  def prepend_view_path(new_path)
73
- lookup_context.view_paths.unshift(*_path_decorator(new_path))
130
+ super(_path_decorator(*new_path))
74
131
  end
75
132
 
76
133
  def append_view_path(new_path)
77
- lookup_context.view_paths.push(*_path_decorator(new_path))
134
+ super(_path_decorator(*new_path))
78
135
  end
79
136
 
80
- private
137
+ private
81
138
 
82
- def _path_decorator(path)
83
- EmptyTemplatePathSetDecorator.new(ActionView::PathSet.new(Array.wrap(path)))
139
+ def _path_decorator(*paths)
140
+ paths.map { |path| EmptyTemplateResolver.build(path) }
84
141
  end
85
142
  end
86
143
 
144
+ # @private
145
+ RESOLVER_CACHE = Hash.new do |hash, path|
146
+ hash[path] = EmptyTemplateResolver.build(path)
147
+ end
148
+
87
149
  included do
88
150
  before do
89
151
  unless render_views?
90
- @_empty_view_path_set_delegator = EmptyTemplatePathSetDecorator.new(controller.class.view_paths)
91
- controller.class.view_paths = ::ActionView::PathSet.new.push(@_empty_view_path_set_delegator)
152
+ @_original_path_set = controller.class.view_paths
153
+ path_set = @_original_path_set.map { |resolver| RESOLVER_CACHE[resolver] }
154
+
155
+ controller.class.view_paths = path_set
92
156
  controller.extend(EmptyTemplates)
93
157
  end
94
158
  end
95
159
 
96
160
  after do
97
- unless render_views?
98
- controller.class.view_paths = @_empty_view_path_set_delegator.original_path_set
99
- end
161
+ controller.class.view_paths = @_original_path_set unless render_views?
100
162
  end
101
163
  end
102
164
  end
@@ -0,0 +1,56 @@
1
+ module RSpec
2
+ module Rails
3
+ # Adds methods (generally to ActionView::TestCase::TestController).
4
+ # Intended for use in view specs.
5
+ module ViewSpecMethods
6
+ module_function
7
+
8
+ # Adds methods `extra_params=` and `extra_params` to the indicated class.
9
+ # When class is `::ActionView::TestCase::TestController`, these methods
10
+ # are exposed in view specs on the `controller` object.
11
+ def add_to(klass)
12
+ return if klass.method_defined?(:extra_params) && klass.method_defined?(:extra_params=)
13
+
14
+ klass.module_exec do
15
+ # Set any extra parameters that rendering a URL for this view
16
+ # would require.
17
+ #
18
+ # @example
19
+ #
20
+ # # In "spec/views/widgets/show.html.erb_spec.rb":
21
+ # before do
22
+ # widget = Widget.create!(:name => "slicer")
23
+ # controller.extra_params = { :id => widget.id }
24
+ # end
25
+ def extra_params=(hash)
26
+ @extra_params = hash
27
+ request.path =
28
+ ViewPathBuilder.new(::Rails.application.routes).path_for(
29
+ extra_params.merge(request.path_parameters)
30
+ )
31
+ end
32
+
33
+ # Use to read extra parameters that are set in the view spec.
34
+ #
35
+ # @example
36
+ #
37
+ # # After the before in the above example:
38
+ # controller.extra_params
39
+ # # => { :id => 4 }
40
+ def extra_params
41
+ @extra_params ||= {}
42
+ @extra_params.dup.freeze
43
+ end
44
+ end
45
+ end
46
+
47
+ # Removes methods `extra_params=` and `extra_params` from the indicated class.
48
+ def remove_from(klass)
49
+ klass.module_exec do
50
+ undef extra_params= if klass.method_defined?(:extra_params=)
51
+ undef extra_params if klass.method_defined?(:extra_params)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
data/lib/rspec/rails.rb CHANGED
@@ -1,10 +1,18 @@
1
1
  require 'rspec/core'
2
2
  require 'rails/version'
3
+
4
+ # Load any of our adapters and extensions early in the process
5
+ require 'rspec/rails/adapters'
3
6
  require 'rspec/rails/extensions'
7
+
8
+ # Load the rspec-rails parts
4
9
  require 'rspec/rails/view_rendering'
5
- require 'rspec/rails/adapters'
6
10
  require 'rspec/rails/matchers'
7
11
  require 'rspec/rails/fixture_support'
12
+ require 'rspec/rails/file_fixture_support'
13
+ require 'rspec/rails/fixture_file_upload_support'
8
14
  require 'rspec/rails/example'
9
15
  require 'rspec/rails/vendor/capybara'
10
16
  require 'rspec/rails/configuration'
17
+ require 'rspec/rails/active_record'
18
+ require 'rspec/rails/feature_check'
data/lib/rspec-rails.rb CHANGED
@@ -1,17 +1,97 @@
1
+ require 'rspec/rails/feature_check'
2
+
1
3
  # Namespace for all core RSpec projects.
2
4
  module RSpec
3
5
  # Namespace for rspec-rails code.
4
6
  module Rails
5
7
  # Railtie to hook into Rails.
6
8
  class Railtie < ::Rails::Railtie
7
- # Rails-3.0.1 requires config.app_generators instead of 3.0.0's config.generators
8
- generators = config.respond_to?(:app_generators) ? config.app_generators : config.generators
9
+ # As of Rails 5.1.0 you can register directories to work with `rake notes`
10
+ require 'rails/source_annotation_extractor'
11
+ ::Rails::SourceAnnotationExtractor::Annotation.register_directories("spec")
12
+
13
+ # As of Rails 8.0.0 you can register directories to work with `rails stats`
14
+ if ::Rails::VERSION::STRING >= "8.0.0"
15
+ require 'rails/code_statistics'
16
+
17
+ dirs = Dir['./spec/**/*_spec.rb']
18
+ .map { |f| f.sub(/^\.\/(spec\/\w+)\/.*/, '\\1') }
19
+ .uniq
20
+ .select { |f| File.directory?(f) }
21
+
22
+ Hash[dirs.map { |d| [d.split('/').last, d] }].each do |type, dir|
23
+ name = type.singularize.capitalize
24
+
25
+ ::Rails::CodeStatistics.register_directory "#{name} specs", dir, test_directory: true
26
+ end
27
+ end
28
+
29
+ generators = config.app_generators
9
30
  generators.integration_tool :rspec
10
- generators.test_framework :rspec
31
+ generators.test_framework :rspec
32
+
33
+ generators do
34
+ ::Rails::Generators.hidden_namespaces.reject! { |namespace| namespace.to_s.start_with?("rspec") }
35
+ end
11
36
 
12
37
  rake_tasks do
13
38
  load "rspec/rails/tasks/rspec.rake"
14
39
  end
40
+
41
+ # This is called after the environment has been loaded but before Rails
42
+ # sets the default for the `preview_path`
43
+ initializer "rspec_rails.action_mailer",
44
+ before: "action_mailer.set_configs" do |app|
45
+ setup_preview_path(app)
46
+ end
47
+
48
+ private
49
+
50
+ def setup_preview_path(app)
51
+ return unless supports_action_mailer_previews?(app.config)
52
+
53
+ options = app.config.action_mailer
54
+ config_default_preview_path(options) if config_preview_path?(options)
55
+ end
56
+
57
+ def config_preview_path?(options)
58
+ # We cannot use `respond_to?(:show_previews)` here as it will always
59
+ # return `true`.
60
+ if options.show_previews.nil?
61
+ options.show_previews = ::Rails.env.development?
62
+ else
63
+ options.show_previews
64
+ end
65
+ end
66
+
67
+ if ::Rails::VERSION::STRING >= "7.1.0"
68
+ def config_default_preview_path(options)
69
+ return unless options.preview_paths.empty?
70
+
71
+ options.preview_paths << "#{::Rails.root}/spec/mailers/previews"
72
+ end
73
+ else
74
+ def config_default_preview_path(options)
75
+ return unless options.preview_path.blank?
76
+
77
+ options.preview_path = "#{::Rails.root}/spec/mailers/previews"
78
+ end
79
+ end
80
+
81
+ def supports_action_mailer_previews?(config)
82
+ # These checks avoid loading `ActionMailer`. Using `defined?` has the
83
+ # side-effect of the class getting loaded if it is available. This is
84
+ # problematic because loading `ActionMailer::Base` will cause it to
85
+ # read the config settings; this is the only time the config is read.
86
+ # If the config is loaded now, any settings declared in a config block
87
+ # in an initializer will be ignored.
88
+ #
89
+ # If the action mailer railtie has not been loaded then `config` will
90
+ # not respond to the method. However, we cannot use
91
+ # `config.action_mailer.respond_to?(:preview_path)` here as it will
92
+ # always return `true`.
93
+ config.respond_to?(:action_mailer)
94
+ end
15
95
  end
16
96
  end
17
97
  end
data.tar.gz.sig CHANGED
Binary file