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
@@ -1,169 +1,214 @@
1
1
  require 'rspec/rails/view_assigns'
2
-
3
- module RSpec::Rails
4
- # Container class for view spec functionality.
5
- module ViewExampleGroup
6
- extend ActiveSupport::Concern
7
- include RSpec::Rails::RailsExampleGroup
8
- include ActionView::TestCase::Behavior
9
- include RSpec::Rails::ViewAssigns
10
- include RSpec::Rails::Matchers::RenderTemplate
11
-
12
- # @private
13
- module ClassMethods
14
- def _default_helper
15
- base = metadata[:description].split('/')[0..-2].join('/')
16
- (base.camelize + 'Helper').constantize if base
17
- rescue NameError
18
- nil
2
+ require 'rspec/rails/view_spec_methods'
3
+ require 'rspec/rails/view_path_builder'
4
+
5
+ module RSpec
6
+ module Rails
7
+ # @api public
8
+ # Container class for view spec functionality.
9
+ module ViewExampleGroup
10
+ extend ActiveSupport::Concern
11
+ include RSpec::Rails::RailsExampleGroup
12
+ include ActionView::TestCase::Behavior
13
+ include RSpec::Rails::ViewAssigns
14
+ include RSpec::Rails::Matchers::RenderTemplate
15
+
16
+ # @private
17
+ module StubResolverCache
18
+ def self.resolver_for(hash)
19
+ @resolvers ||= {}
20
+ @resolvers[hash] ||= ActionView::FixtureResolver.new(hash)
21
+ end
19
22
  end
20
23
 
21
- def _default_helpers
22
- helpers = [_default_helper].compact
23
- helpers << ApplicationHelper if Object.const_defined?('ApplicationHelper')
24
- helpers
25
- end
26
- end
24
+ # @private
25
+ module ClassMethods
26
+ def _default_helper
27
+ base = metadata[:description].split('/')[0..-2].join('/')
28
+ (base.camelize + 'Helper').constantize unless base.to_s.empty?
29
+ rescue NameError
30
+ nil
31
+ end
27
32
 
28
- # DSL exposed to view specs.
29
- module ExampleMethods
30
- # @overload render
31
- # @overload render({:partial => path_to_file})
32
- # @overload render({:partial => path_to_file}, {... locals ...})
33
- # @overload render({:partial => path_to_file}, {... locals ...}) do ... end
34
- #
35
- # Delegates to ActionView::Base#render, so see documentation on that
36
- # for more info.
37
- #
38
- # The only addition is that you can call render with no arguments, and RSpec
39
- # will pass the top level description to render:
40
- #
41
- # describe "widgets/new.html.erb" do
42
- # it "shows all the widgets" do
43
- # render # => view.render(:file => "widgets/new.html.erb")
44
- # # ...
45
- # end
46
- # end
47
- def render(options={}, local_assigns={}, &block)
48
- options = _default_render_options if Hash === options and options.empty?
49
- super(options, local_assigns, &block)
33
+ def _default_helpers
34
+ helpers = [_default_helper].compact
35
+ helpers << ApplicationHelper if Object.const_defined?('ApplicationHelper')
36
+ helpers
37
+ end
50
38
  end
51
39
 
52
- # The instance of `ActionView::Base` that is used to render the template.
53
- # Use this to stub methods _before_ calling `render`.
54
- #
55
- # describe "widgets/new.html.erb" do
56
- # it "shows all the widgets" do
57
- # view.stub(:foo) { "foo" }
58
- # render
59
- # # ...
60
- # end
61
- # end
62
- def view
63
- _view
64
- end
40
+ # DSL exposed to view specs.
41
+ module ExampleMethods
42
+ extend ActiveSupport::Concern
65
43
 
66
- # Simulates the presence of a template on the file system by adding a
67
- # Rails' FixtureResolver to the front of the view_paths list. Designed to
68
- # help isolate view examples from partials rendered by the view template
69
- # that is the subject of the example.
70
- #
71
- # stub_template("widgets/_widget.html.erb" => "This content.")
72
- def stub_template(hash)
73
- view.view_paths.unshift(ActionView::FixtureResolver.new(hash))
74
- end
44
+ included do
45
+ include ::Rails.application.routes.url_helpers
46
+ include ::Rails.application.routes.mounted_helpers
47
+ end
75
48
 
76
- # Provides access to the params hash that will be available within the
77
- # view.
78
- #
79
- # params[:foo] = 'bar'
80
- def params
81
- controller.params
82
- end
49
+ # @overload render
50
+ # @overload render({partial: path_to_file})
51
+ # @overload render({partial: path_to_file}, {... locals ...})
52
+ # @overload render({partial: path_to_file}, {... locals ...}) do ... end
53
+ #
54
+ # Delegates to ActionView::Base#render, so see documentation on that
55
+ # for more info.
56
+ #
57
+ # The only addition is that you can call render with no arguments, and
58
+ # RSpec will pass the top level description to render:
59
+ #
60
+ # describe "widgets/new.html.erb" do
61
+ # it "shows all the widgets" do
62
+ # render # => view.render(file: "widgets/new.html.erb")
63
+ # # ...
64
+ # end
65
+ # end
66
+ def render(options = {}, local_assigns = {}, &block)
67
+ options = _default_render_options if Hash === options && options.empty?
68
+ options = options.merge(_default_render_options) if Hash === options && options.keys == [:locals]
69
+ super(options, local_assigns, &block)
70
+ end
83
71
 
84
- # @deprecated Use `view` instead.
85
- def template
86
- RSpec.deprecate("template", :replacement => "view")
87
- view
88
- end
72
+ # The instance of `ActionView::Base` that is used to render the template.
73
+ # Use this to stub methods _before_ calling `render`.
74
+ #
75
+ # describe "widgets/new.html.erb" do
76
+ # it "shows all the widgets" do
77
+ # view.stub(:foo) { "foo" }
78
+ # render
79
+ # # ...
80
+ # end
81
+ # end
82
+ def view
83
+ _view
84
+ end
89
85
 
90
- # @deprecated Use `rendered` instead.
91
- def response
92
- # `assert_template` expects `response` to implement a #body method
93
- # like an `ActionDispatch::Response` does to force the view to render.
94
- # For backwards compatibility, we use #response as an alias for
95
- # #rendered, but it needs to implement #body to avoid `assert_template`
96
- # raising a `NoMethodError`.
97
- unless rendered.respond_to?(:body)
98
- def rendered.body; self; end;
86
+ # Simulates the presence of a template on the file system by adding a
87
+ # Rails' FixtureResolver to the front of the view_paths list. Designed to
88
+ # help isolate view examples from partials rendered by the view template
89
+ # that is the subject of the example.
90
+ #
91
+ # stub_template("widgets/_widget.html.erb" => "This content.")
92
+ def stub_template(hash)
93
+ controller.prepend_view_path(StubResolverCache.resolver_for(hash))
99
94
  end
100
95
 
101
- rendered
102
- end
96
+ # Provides access to the params hash that will be available within the
97
+ # view.
98
+ #
99
+ # params[:foo] = 'bar'
100
+ def params
101
+ controller.params
102
+ end
103
103
 
104
- private
104
+ # @deprecated Use `view` instead.
105
+ def template
106
+ RSpec.deprecate("template", replacement: "view")
107
+ view
108
+ end
105
109
 
106
- def _default_render_options
107
- if ::Rails::VERSION::STRING >= '3.2'
108
- # pluck the handler, format, and locale out of, eg, posts/index.de.html.haml
109
- template, *components = _default_file_to_render.split('.')
110
- handler, format, locale = *components.reverse
110
+ # @deprecated Use `rendered` instead.
111
+ def response
112
+ # `assert_template` expects `response` to implement a #body method
113
+ # like an `ActionDispatch::Response` does to force the view to
114
+ # render. For backwards compatibility, we use #response as an alias
115
+ # for #rendered, but it needs to implement #body to avoid
116
+ # `assert_template` raising a `NoMethodError`.
117
+ unless rendered.respond_to?(:body)
118
+ def rendered.body
119
+ self
120
+ end
121
+ end
122
+
123
+ rendered
124
+ end
111
125
 
112
- render_options = {:template => template}
113
- render_options[:handlers] = [handler] if handler
114
- render_options[:formats] = [format] if format
115
- render_options[:locales] = [locale] if locale
126
+ private
127
+
128
+ def _default_render_options
129
+ formats = if ActionView::Template::Types.respond_to?(:symbols)
130
+ ActionView::Template::Types.symbols
131
+ else
132
+ [:html, :text, :js, :css, :xml, :json].map(&:to_s)
133
+ end.map { |x| Regexp.escape(x) }.join("|")
134
+
135
+ handlers = ActionView::Template::Handlers.extensions.map { |x| Regexp.escape(x) }.join("|")
136
+ locales = "[a-z]{2}(?:-[A-Z]{2})?"
137
+ variants = "[^.]*"
138
+ path_regex = %r{
139
+ \A
140
+ (?<template>.*?)
141
+ (?:\.(?<locale>#{locales}))??
142
+ (?:\.(?<format>#{formats}))??
143
+ (?:\+(?<variant>#{variants}))??
144
+ (?:\.(?<handler>#{handlers}))?
145
+ \z
146
+ }x
147
+
148
+ # This regex should always find a match.
149
+ # Worst case, everything will be nil, and :template will just be
150
+ # the original string.
151
+ match = path_regex.match(_default_file_to_render)
152
+
153
+ render_options = { template: match[:template] }
154
+ render_options[:handlers] = [match[:handler].to_sym] if match[:handler]
155
+ render_options[:formats] = [match[:format].to_sym] if match[:format]
156
+ render_options[:locales] = [match[:locale].to_sym] if match[:locale]
157
+ render_options[:variants] = [match[:variant].to_sym] if match[:variant]
116
158
 
117
159
  render_options
118
- else
119
- {:template => _default_file_to_render}
120
160
  end
121
- end
122
161
 
123
- def _path_parts
124
- _default_file_to_render.split("/")
125
- end
162
+ def _path_parts
163
+ _default_file_to_render.split("/")
164
+ end
126
165
 
127
- def _controller_path
128
- _path_parts[0..-2].join("/")
129
- end
166
+ def _controller_path
167
+ _path_parts[0..-2].join("/")
168
+ end
130
169
 
131
- def _inferred_action
132
- _path_parts.last.split(".").first
133
- end
170
+ def _inferred_action
171
+ _path_parts.last.split(".").first
172
+ end
134
173
 
135
- def _include_controller_helpers
136
- helpers = controller._helpers
137
- view.singleton_class.class_exec do
138
- include helpers unless included_modules.include?(helpers)
174
+ def _include_controller_helpers
175
+ helpers = controller._helpers
176
+ view.singleton_class.class_exec do
177
+ include helpers unless included_modules.include?(helpers)
178
+ end
139
179
  end
140
180
  end
141
- end
142
181
 
143
- included do
144
- include ExampleMethods
182
+ included do
183
+ include ExampleMethods
145
184
 
146
- helper(*_default_helpers)
185
+ helper(*_default_helpers)
147
186
 
148
- before do
149
- _include_controller_helpers
150
- if view.lookup_context.respond_to?(:prefixes)
151
- # rails 3.1
187
+ before do
188
+ _include_controller_helpers
152
189
  view.lookup_context.prefixes << _controller_path
153
- end
154
190
 
155
- # fixes bug with differing formats
156
- view.lookup_context.view_paths.each(&:clear_cache)
191
+ controller.controller_path = _controller_path
157
192
 
158
- controller.controller_path = _controller_path
159
- controller.request.path_parameters[:controller] = _controller_path
160
- controller.request.path_parameters[:action] = _inferred_action unless _inferred_action =~ /^_/
161
- end
193
+ path_params_to_merge = {}
194
+ path_params_to_merge[:controller] = _controller_path
195
+ path_params_to_merge[:action] = _inferred_action unless _inferred_action =~ /^_/
196
+
197
+ path_params = controller.request.path_parameters
198
+
199
+ controller.request.path_parameters = path_params.reverse_merge(path_params_to_merge)
200
+ controller.request.path = ViewPathBuilder.new(::Rails.application.routes).path_for(controller.request.path_parameters)
201
+ ViewSpecMethods.add_to(::ActionView::TestCase::TestController)
202
+ end
162
203
 
163
- let(:_default_file_to_render) do |example|
164
- example.example_group.top_level_description
204
+ after do
205
+ ViewSpecMethods.remove_from(::ActionView::TestCase::TestController)
206
+ end
207
+
208
+ let(:_default_file_to_render) do |example|
209
+ example.example_group.top_level_description
210
+ end
165
211
  end
166
212
  end
167
213
  end
168
214
  end
169
-
@@ -6,4 +6,8 @@ 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/job_example_group'
9
10
  require 'rspec/rails/example/feature_example_group'
11
+ require 'rspec/rails/example/system_example_group'
12
+ require 'rspec/rails/example/channel_example_group'
13
+ require 'rspec/rails/example/mailbox_example_group'
@@ -1,17 +1,11 @@
1
1
  RSpec.configure do |rspec|
2
2
  # Delay this in order to give users a chance to configure `expect_with`...
3
3
  rspec.before(:suite) do
4
- if defined?(RSpec::Matchers) && RSpec::Matchers.configuration.syntax.include?(:should) && defined?(ActiveRecord::Associations)
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
4
+ if defined?(RSpec::Matchers) &&
5
+ RSpec::Matchers.configuration.respond_to?(:syntax) && # RSpec 4 dropped support for monkey-patching `should` syntax
6
+ RSpec::Matchers.configuration.syntax.include?(:should) &&
7
+ defined?(ActiveRecord::Associations)
8
+ RSpec::Matchers.configuration.add_should_and_should_not_to ActiveRecord::Associations::CollectionProxy
14
9
  end
15
10
  end
16
11
  end
17
-
@@ -0,0 +1,51 @@
1
+ module RSpec
2
+ module Rails
3
+ # @private
4
+ module FeatureCheck
5
+ module_function
6
+ def has_active_job?
7
+ defined?(::ActiveJob)
8
+ end
9
+
10
+ def has_active_record?
11
+ defined?(::ActiveRecord)
12
+ end
13
+
14
+ def has_active_record_migration?
15
+ has_active_record? && defined?(::ActiveRecord::Migration)
16
+ end
17
+
18
+ def has_action_mailer?
19
+ defined?(::ActionMailer)
20
+ end
21
+
22
+ def has_action_mailer_preview?
23
+ has_action_mailer? && defined?(::ActionMailer::Preview)
24
+ end
25
+
26
+ def has_action_cable_testing?
27
+ defined?(::ActionCable)
28
+ end
29
+
30
+ def has_action_mailer_parameterized?
31
+ has_action_mailer? && defined?(::ActionMailer::Parameterized::DeliveryJob)
32
+ end
33
+
34
+ def has_action_mailer_unified_delivery?
35
+ has_action_mailer? && defined?(::ActionMailer::MailDeliveryJob)
36
+ end
37
+
38
+ def has_action_mailer_legacy_delivery_job?
39
+ defined?(ActionMailer::DeliveryJob)
40
+ end
41
+
42
+ def has_action_mailbox?
43
+ defined?(::ActionMailbox)
44
+ end
45
+
46
+ def type_metatag(type)
47
+ "type: :#{type}"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,18 @@
1
+ require 'active_support/testing/file_fixtures'
2
+
3
+ module RSpec
4
+ module Rails
5
+ # @private
6
+ module FileFixtureSupport
7
+ extend ActiveSupport::Concern
8
+ include ActiveSupport::Testing::FileFixtures
9
+
10
+ included do
11
+ self.file_fixture_path = RSpec.configuration.file_fixture_path
12
+ if defined?(ActiveStorage::FixtureSet)
13
+ ActiveStorage::FixtureSet.file_fixture_path = RSpec.configuration.file_fixture_path
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,45 @@
1
+ module RSpec
2
+ module Rails
3
+ # @private
4
+ module FixtureFileUploadSupport
5
+ delegate :fixture_file_upload, to: :rails_fixture_file_wrapper
6
+
7
+ private
8
+
9
+ # In Rails 7.0 fixture file path needs to be relative to `file_fixture_path` instead, this change
10
+ # was brought in with a deprecation warning on 6.1. In Rails 7.0 expect to rework this to remove
11
+ # the old accessor.
12
+ def rails_fixture_file_wrapper
13
+ RailsFixtureFileWrapper.file_fixture_path = nil
14
+ resolved_fixture_path =
15
+ if respond_to?(:file_fixture_path) && !file_fixture_path.nil?
16
+ file_fixture_path.to_s
17
+ elsif respond_to?(:fixture_paths)
18
+ (RSpec.configuration.fixture_paths&.first || '').to_s
19
+ else
20
+ (RSpec.configuration.fixture_path || '').to_s
21
+ end
22
+ RailsFixtureFileWrapper.file_fixture_path = File.join(resolved_fixture_path, '') unless resolved_fixture_path.strip.empty?
23
+ RailsFixtureFileWrapper.instance
24
+ end
25
+
26
+ class RailsFixtureFileWrapper
27
+ include ActionDispatch::TestProcess if defined?(ActionDispatch::TestProcess)
28
+ include ActiveSupport::Testing::FileFixtures
29
+
30
+ class << self
31
+ if ::Rails::VERSION::STRING < "7.1.0"
32
+ attr_accessor :fixture_path
33
+ else
34
+ attr_accessor :fixture_paths
35
+ end
36
+
37
+ # Get instance of wrapper
38
+ def instance
39
+ @instance ||= new
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -5,26 +5,82 @@ module RSpec
5
5
  if defined?(ActiveRecord::TestFixtures)
6
6
  extend ActiveSupport::Concern
7
7
  include RSpec::Rails::SetupAndTeardownAdapter
8
- include RSpec::Rails::MinitestLifecycleAdapter if ::ActiveRecord::VERSION::STRING > '4'
8
+ include RSpec::Rails::MinitestLifecycleAdapter
9
9
  include RSpec::Rails::MinitestAssertionAdapter
10
10
  include ActiveRecord::TestFixtures
11
11
 
12
+ # @private prevent ActiveSupport::TestFixtures to start a DB transaction.
13
+ # Monkey patched to avoid collisions with 'let(:name)' since Rails 6.1
14
+ def run_in_transaction?
15
+ current_example_name = (RSpec.current_example && RSpec.current_example.metadata[:description])
16
+ use_transactional_tests && !self.class.uses_transaction?(current_example_name)
17
+ end
18
+
12
19
  included do
13
- # TODO (DC 2011-06-25) this is necessary because fixture_file_upload
14
- # accesses fixture_path directly on ActiveSupport::TestCase. This is
15
- # fixed in rails by https://github.com/rails/rails/pull/1861, which
16
- # should be part of the 3.1 release, at which point we can include
17
- # these lines for rails < 3.1.
18
- ActiveSupport::TestCase.class_exec do
19
- include ActiveRecord::TestFixtures
20
- self.fixture_path = RSpec.configuration.fixture_path
20
+ if RSpec.configuration.use_active_record?
21
+ include Fixtures
22
+
23
+ # TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2
24
+ if respond_to?(:fixture_paths=)
25
+ self.fixture_paths = RSpec.configuration.fixture_paths
26
+ else
27
+ self.fixture_path = RSpec.configuration.fixture_path
28
+ end
29
+
30
+ self.use_transactional_tests = RSpec.configuration.use_transactional_fixtures
31
+ self.use_instantiated_fixtures = RSpec.configuration.use_instantiated_fixtures
32
+
33
+ fixtures RSpec.configuration.global_fixtures if RSpec.configuration.global_fixtures
21
34
  end
22
- # /TODO
35
+ end
36
+
37
+ module Fixtures
38
+ extend ActiveSupport::Concern
39
+
40
+ # rubocop:disable Metrics/BlockLength
41
+ class_methods do
42
+ if ::Rails.version.to_f >= 7.1
43
+ def fixtures(*args)
44
+ super.tap do
45
+ fixture_sets.each_pair do |method_name, fixture_name|
46
+ proxy_method_warning_if_called_in_before_context_scope(method_name, fixture_name)
47
+ end
48
+ end
49
+ end
23
50
 
24
- self.fixture_path = RSpec.configuration.fixture_path
25
- self.use_transactional_fixtures = RSpec.configuration.use_transactional_fixtures
26
- self.use_instantiated_fixtures = RSpec.configuration.use_instantiated_fixtures
27
- fixtures RSpec.configuration.global_fixtures if RSpec.configuration.global_fixtures
51
+ def proxy_method_warning_if_called_in_before_context_scope(method_name, fixture_name)
52
+ define_method(method_name) do |*args, **kwargs, &blk|
53
+ if RSpec.current_scope == :before_context_hook
54
+ RSpec.warn_with("Calling fixture method in before :context ")
55
+ else
56
+ access_fixture(fixture_name, *args, **kwargs, &blk)
57
+ end
58
+ end
59
+ end
60
+ else
61
+ def fixtures(*args)
62
+ orig_methods = private_instance_methods
63
+ super.tap do
64
+ new_methods = private_instance_methods - orig_methods
65
+ new_methods.each do |method_name|
66
+ proxy_method_warning_if_called_in_before_context_scope(method_name)
67
+ end
68
+ end
69
+ end
70
+
71
+ def proxy_method_warning_if_called_in_before_context_scope(method_name)
72
+ orig_implementation = instance_method(method_name)
73
+ define_method(method_name) do |*args, &blk|
74
+ if RSpec.current_scope == :before_context_hook
75
+ RSpec.warn_with("Calling fixture method in before :context ")
76
+ else
77
+ orig_implementation.bind(self).call(*args, &blk)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ # rubocop:enable Metrics/BlockLength
28
84
  end
29
85
  end
30
86
  end