rails_stuff 0.5.1 → 0.6.0.rc1

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +29 -0
  4. data/Gemfile +1 -0
  5. data/README.md +37 -16
  6. data/gemfiles/rails_4.gemfile +1 -0
  7. data/gemfiles/rails_5.gemfile +1 -0
  8. data/lib/rails_stuff/engine.rb +1 -1
  9. data/lib/rails_stuff/resources_controller/actions.rb +3 -3
  10. data/lib/rails_stuff/resources_controller/basic_helpers.rb +1 -1
  11. data/lib/rails_stuff/resources_controller/resource_helper.rb +32 -14
  12. data/lib/rails_stuff/resources_controller.rb +0 -2
  13. data/lib/rails_stuff/responders/turbolinks.rb +13 -0
  14. data/lib/rails_stuff/responders.rb +19 -0
  15. data/lib/rails_stuff/rspec_helpers/concurrency.rb +45 -0
  16. data/lib/rails_stuff/rspec_helpers/groups/feature.rb +25 -0
  17. data/lib/rails_stuff/rspec_helpers/groups/request.rb +79 -0
  18. data/lib/rails_stuff/rspec_helpers/matchers/be_valid_js.rb +12 -0
  19. data/lib/rails_stuff/rspec_helpers/matchers/redirect_with_turbolinks.rb +53 -0
  20. data/lib/rails_stuff/rspec_helpers/signinable.rb +21 -0
  21. data/lib/rails_stuff/rspec_helpers.rb +123 -0
  22. data/lib/rails_stuff/sort_scope.rb +19 -0
  23. data/lib/rails_stuff/statusable/builder.rb +114 -0
  24. data/lib/rails_stuff/statusable/helper.rb +64 -0
  25. data/lib/rails_stuff/statusable/mapped_builder.rb +48 -0
  26. data/lib/rails_stuff/statusable/mapped_helper.rb +46 -0
  27. data/lib/rails_stuff/statusable.rb +53 -199
  28. data/lib/rails_stuff/test_helpers/concurrency.rb +1 -32
  29. data/lib/rails_stuff/test_helpers/integration_session.rb +18 -0
  30. data/lib/rails_stuff/test_helpers/response.rb +10 -0
  31. data/lib/rails_stuff/test_helpers.rb +50 -0
  32. data/lib/rails_stuff/types_tracker.rb +1 -1
  33. data/lib/rails_stuff/version.rb +13 -3
  34. data/lib/rails_stuff.rb +3 -0
  35. metadata +20 -8
  36. data/lib/rails_stuff/resources_controller/responder.rb +0 -21
  37. data/lib/rails_stuff/test_helpers/configurator.rb +0 -60
  38. data/lib/rails_stuff/test_helpers/rails.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 16d70694f5a696a150e54aad75558c05441d0c1c
4
- data.tar.gz: b12c95387e4bd5593842d8ad4ba3db9d5dc9ad9f
3
+ metadata.gz: 56cd33390b1d0c5cce251aba39698ef115de3c6c
4
+ data.tar.gz: 8e7032d8717fae0d1fa44c5f6ea308a150a2e73f
5
5
  SHA512:
6
- metadata.gz: e179c0f340c95ff4186022d6ab09053d023ae01cee10a0a276e697e02d387d3624626cf0c93b0bd43ee3e305330d747259e4d4a558af5c912cd9a8d336f207bc
7
- data.tar.gz: e7e396a2265bb05e1312eaff05d5230788a77a2fc92780b4f8c099f9a40979f502975c2c6b2967fd91b41d2635527cd6ee943fbde73c8541ebb7c4a9537540b4
6
+ metadata.gz: 9abf798f564088d2bb174e955efdf0cce9b47528b8f0dac7095516a35fcd11752772cd3d691266235698fd5281622db8ce9f5f9d32a3d66a75c8efde2c5da87c
7
+ data.tar.gz: 3dbbc5a6052014726fba018811d5615d9e9527e913fb14a492d615527f4bbe6bb5312815d55549e613e38c6103728447e7b558c8f1bbf630c18d65eb897bfc13
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /pkg/
9
9
  /spec/reports/
10
10
  /tmp/
11
+ /log/
data/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 0.6.0.rc1
4
+
5
+ ### Controllers
6
+
7
+ - Don't overwrite :location option if present.
8
+ - Don't overwrite responder and `respond_with`'s mimes.
9
+ - `#current_sort_scope` to access applied sorting rules.
10
+ - `.resource_helper` has `source` option, which accepts lambdas and strings.
11
+ `class` option is deprecated now in favour of `source`.
12
+
13
+ ### Models
14
+
15
+ - Improved Statusable:
16
+
17
+ - Model are now clear from lot of helper methods.
18
+ There is single `statuses` method for statusable field which holds all helpers.
19
+ - `.select_options` supports `:only` option.
20
+ - Helpers to map/unmap values for mapped statuses from external code.
21
+
22
+ ### Tests
23
+
24
+ - A lot of new test and rspec helpers and configs (see RSpecHelpers, TestHelpers).
25
+ - `RSpecHelpers.setup` & `TestHelpers.setup` to setup helpers instead of requiring
26
+ files. This methods accepts `only` & `except` options.
27
+
28
+ ### Misc
29
+
30
+ - Use AR#update instead of #update_attributes.
31
+
3
32
  ## 0.5.1
4
33
 
5
34
  Rails 5 support.
data/Gemfile CHANGED
@@ -16,6 +16,7 @@ group :development do
16
16
  gem 'has_scope', '~> 0.7.0'
17
17
  gem 'responders', '~> 2.1.0'
18
18
  gem 'kaminari', '~> 0.16.3'
19
+ gem 'hashie', '~> 3.4.0'
19
20
 
20
21
  gem 'rspec-rails', '~> 3.5.2'
21
22
  gem 'rspec-its', '~> 1.2.0'
data/README.md CHANGED
@@ -58,8 +58,7 @@ __[Helpers usage](#helpers-usage)__
58
58
 
59
59
  - __Response__
60
60
  `#json_body` to test json responses.
61
- - __Configurator__
62
- Provides useful basic configuration for RSpec.
61
+ - Useful RSpec configurations, helpers and matchers for better experience.
63
62
  - __Concurrency__
64
63
  Helpers for testing with concurrent requests.
65
64
 
@@ -166,6 +165,9 @@ has_sort_scope by: [:name, :created_at, :balance], default: [:name]
166
165
  # - `sort=name&sort_desc=true`
167
166
  # - `sort[name]&sort[created_at]`
168
167
  # - `sort[name]&sort[created_at]=desc
168
+
169
+ # access current sort scope hash with
170
+ current_sort_scope # => {'name' => :desc} or {'name' => :asc, 'id' => :desc}
169
171
  ```
170
172
 
171
173
  Requires `gem 'has_scope'`.
@@ -249,10 +251,12 @@ User.with_status(param[:status]).with_subscription_status(params[:subs_status])
249
251
  Order.with_status(:confirmed)
250
252
 
251
253
  # Translation & select helpers (requires activemodel_translation gem)
252
- User.status_name(:active)
254
+ User.statuses.translate(:active)
253
255
  user.subscription_status_name # translates current status
254
- User.status_select_options
255
- User.subscription_status_select_options except: [:expired]
256
+ User.statuses.select_options
257
+ User.subscription_statuses.select_options except: [:expired]
258
+ Order.statuses.map([:submitted, :delivered]) # => [1, 3]
259
+ Order.statuses.unmap([1, 3]) # => [:submitted, :delivered]
256
260
 
257
261
  # Accessors
258
262
  user.status = 'confirmed' or user.confirmed!
@@ -409,8 +413,13 @@ switch locales while rendering single view.
409
413
 
410
414
  ### Test helpers usage
411
415
 
412
- Add `require 'rails_stuff/test_helpers/rails'` to `test_helper.rb`.
416
+ Add `RailsStuff::RSpec.setup` to `rails_helper.rb` to load all the stuff or
417
+ pick from `rails_stuff/test_helpers/` and `rails_stuff/rspec`.
418
+
419
+ Please check the source for complete list of helpers, while this section is not
420
+ well-documented.
413
421
 
422
+ #### `json_body`
414
423
  ```ruby
415
424
  assert_equal({'id' => 1, 'name' => 'John'}, response.json_body)
416
425
  assert_equal('John', response.json_body['name'])
@@ -430,17 +439,29 @@ Use `json_body['key']` instead.
430
439
 
431
440
  There is `Configurator` with useful RSpec configs:
432
441
 
442
+ #### RSpec configurations
443
+
433
444
  ```ruby
434
- RSpec.configure do |config|
435
- RailsStuff::TestHelpers::Configurator.tap do |configurator|
436
- # Setup DatabaseCleaner with basic settings:
437
- configurator.database_cleaner(config)
438
- # Flush redis after suite and exampes with `flush_redis: true`:
439
- configurator.redis(config)
440
- # Run debugger after failed tests:
441
- configurator.debug(config)
442
- end
443
- end
445
+ # Setup DatabaseCleaner with basic settings:
446
+ RailsStuff::RSpec.database_cleaner
447
+
448
+ # Flush redis after suite and exampes with `flush_redis: true`:
449
+ RailsStuff::RSpec.redis
450
+
451
+ # Run debugger after failed tests:
452
+ RailsStuff::RSpec.debug
453
+
454
+ # Clear log/test.log after suite:
455
+ RailsStuff::RSpec.clear_logs
456
+
457
+ # Raise errors from threads:
458
+ RailsStuff::RSpec.thread
459
+
460
+ # Raise errors for all missing I18n translation:
461
+ RailsStuff::RSpec.i18n
462
+
463
+ # Freeze time with for group/example with `:frozen_time` metadata (requires timecop gem):
464
+ RailsStuff::RSpec.frozen_time
444
465
  ```
445
466
 
446
467
  ### PluginManager
@@ -15,6 +15,7 @@ group :development do
15
15
  gem "has_scope", "~> 0.7.0"
16
16
  gem "responders", "~> 2.1.0"
17
17
  gem "kaminari", "~> 0.16.3"
18
+ gem "hashie", "~> 3.4.0"
18
19
  gem "rspec-rails", "~> 3.5.2"
19
20
  gem "rspec-its", "~> 1.2.0"
20
21
  gem "rubocop", "~> 0.37.2"
@@ -15,6 +15,7 @@ group :development do
15
15
  gem "has_scope", "~> 0.7.0"
16
16
  gem "responders", "~> 2.1.0"
17
17
  gem "kaminari", "~> 0.16.3"
18
+ gem "hashie", "~> 3.4.0"
18
19
  gem "rspec-rails", "~> 3.5.2"
19
20
  gem "rspec-its", "~> 1.2.0"
20
21
  gem "rubocop", "~> 0.37.2"
@@ -8,7 +8,7 @@ module RailsStuff
8
8
  random_uniq_attr: :model,
9
9
  statusable: :model,
10
10
  resources_controller: [
11
- :controller,
11
+ -> { defined?(::Responders) && :controller },
12
12
  -> { ResourcesController.use_kaminari! if defined?(::Kaminari) },
13
13
  ],
14
14
  sort_scope: -> { defined?(::HasScope) && :controller },
@@ -8,21 +8,21 @@ module RailsStuff
8
8
 
9
9
  def create(options = {}, &block)
10
10
  if create_resource
11
- options[:location] = after_save_url
11
+ options[:location] ||= after_save_url
12
12
  end
13
13
  respond_with(resource, options, &block)
14
14
  end
15
15
 
16
16
  def update(options = {}, &block)
17
17
  if update_resource
18
- options[:location] = after_save_url
18
+ options[:location] ||= after_save_url
19
19
  end
20
20
  respond_with(resource, options, &block)
21
21
  end
22
22
 
23
23
  def destroy(options = {}, &block)
24
24
  resource.destroy
25
- options[:location] = after_destroy_url
25
+ options[:location] ||= after_destroy_url
26
26
  flash_errors!
27
27
  respond_with(resource, options, &block)
28
28
  end
@@ -82,7 +82,7 @@ module RailsStuff
82
82
 
83
83
  # Updates resource with `resource_params`.
84
84
  def update_resource(attrs = resource_params)
85
- resource.update_attributes(attrs)
85
+ resource.update(attrs)
86
86
  end
87
87
 
88
88
  # Flashes errors in a safe way. Joins `full_messages` and truncates
@@ -2,6 +2,15 @@ module RailsStuff
2
2
  module ResourcesController
3
3
  # Defines resource helper and finder method.
4
4
  module ResourceHelper
5
+ class << self
6
+ def deprecation
7
+ @deprecation ||= begin
8
+ require 'active_support/deprecation'
9
+ ActiveSupport::Deprecation.new('0.7', 'RailsStuff')
10
+ end
11
+ end
12
+ end
13
+
5
14
  # Defines protected helper method. Ex. for `:user`
6
15
  #
7
16
  # helper_method :user
@@ -12,26 +21,35 @@ module RailsStuff
12
21
  #
13
22
  # #### Options
14
23
  #
15
- # - `class` - class name, default to `resource_name.classify`
24
+ # - `source` - class name or Proc returning relation, default to `resource_name.classify`.
16
25
  # - `param` - param name, default to `resource_name.foreign_key`
17
- def resource_helper(resource_name, **options)
18
- helper_method resource_name, :"#{resource_name}?"
19
- resource_name = resource_name.to_s
20
- class_name = options[:class] || resource_name.classify
21
- param_key = options[:param] || resource_name.foreign_key
26
+ #
27
+ # rubocop:disable CyclomaticComplexity, PerceivedComplexity, AbcSize
28
+ def resource_helper(name, param: nil, source: nil, **options)
29
+ ResourceHelper.deprecation.warn('use :source instead of :class') if options.key?(:class)
22
30
 
23
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
24
- protected
31
+ param ||= name.to_s.foreign_key.to_sym
32
+ define_method("#{name}?") { params.key?(param) }
25
33
 
26
- def #{resource_name}
27
- @#{resource_name} ||= #{class_name}.find(params[:#{param_key}])
34
+ ivar = :"@#{name}"
35
+ source ||= options[:class] || name.to_s.classify
36
+ if source.is_a?(Proc)
37
+ define_method(name) do
38
+ instance_variable_get(ivar) ||
39
+ instance_variable_set(ivar, instance_exec(&source).find(params[param]))
28
40
  end
29
-
30
- def #{resource_name}?
31
- params.key?(:#{param_key})
41
+ else
42
+ source = Object.const_get(source) unless source.is_a?(Class)
43
+ define_method(name) do
44
+ instance_variable_get(ivar) ||
45
+ instance_variable_set(ivar, source.find(params[param]))
32
46
  end
33
- RUBY
47
+ end
48
+
49
+ helper_method name, :"#{name}?"
50
+ protected name, :"#{name}?"
34
51
  end
52
+ # rubocop:enable CyclomaticComplexity, PerceivedComplexity, AbcSize
35
53
  end
36
54
  end
37
55
  end
@@ -41,8 +41,6 @@ module RailsStuff
41
41
  def resources_controller(**options)
42
42
  ResourcesController.inject(self, **options)
43
43
 
44
- respond_to :html
45
- self.responder = Responder
46
44
  self.after_save_action = options[:after_save_action] || after_save_action
47
45
 
48
46
  resource_belongs_to(*options[:belongs_to]) if options[:belongs_to]
@@ -0,0 +1,13 @@
1
+ module RailsStuff
2
+ module Responders
3
+ module Turbolinks
4
+ # Bypasses `:turbolinks` from options.
5
+ def redirect_to(url, opts = {})
6
+ if !opts.key?(:turbolinks) && options.key?(:turbolinks)
7
+ opts[:turbolinks] = options[:turbolinks]
8
+ end
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ require 'rails_stuff/responders/turbolinks'
2
+
3
+ module RailsStuff
4
+ # Here are some useful responders extensions.
5
+ #
6
+ # Previous versions had responder with SJR helpers, which has been removed.
7
+ # To achieve same result define responder with:
8
+ #
9
+ # class CustomResponder < ActionController::Responder
10
+ # include Responders::HttpCacheResponder
11
+ # include RailsStuff::Responders::Turbolinks
12
+ #
13
+ # # SJR: render action on failures, redirect on success
14
+ # alias_method :to_js, :to_html
15
+ # end
16
+ #
17
+ module Responders
18
+ end
19
+ end
@@ -0,0 +1,45 @@
1
+ require 'active_support/concern'
2
+ require 'rails_stuff/test_helpers/concurrency'
3
+
4
+ module RailsStuff
5
+ module RSpecHelpers
6
+ module Concurrency
7
+ extend ActiveSupport::Concern
8
+ include RailsStuff::TestHelpers::Concurrency
9
+
10
+ module ClassMethods
11
+ # Defines subject which runs parent's value in multiple threads concurrently.
12
+ # Define `thread_args` or `threads_count` with `let` to configure it.
13
+ #
14
+ # Sets metadata `concurrent: true` so database cleaner uses right strategy.
15
+ def concurrent_subject!
16
+ metadata[:concurrent] = true
17
+ subject do
18
+ super_proc = super()
19
+ args = defined?(thread_args) && thread_args
20
+ args ||= defined?(threads_count) && threads_count
21
+ -> { concurrently(args, &super_proc) }
22
+ end
23
+ end
24
+
25
+ # Runs given block in current context and nested context with concurrent subject.
26
+ #
27
+ # subject { -> { increment_value_once } }
28
+ # # This will create 2 examples. One for current contex, and one
29
+ # # for current context where subject will run multiple times concurrently.
30
+ # check_concurrent do
31
+ # it { should change { value }.by(1) }
32
+ # end
33
+ def check_concurrent(&block)
34
+ instance_eval(&block)
35
+ context 'running multiple times concurrently' do
36
+ concurrent_subject!
37
+ instance_eval(&block)
38
+ end
39
+ end
40
+ end
41
+
42
+ ::RSpec.configuration.include(self) if defined?(::RSpec)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ module RailsStuff
2
+ module RSpecHelpers
3
+ module Groups
4
+ module Feature
5
+ def wait_for_ajax
6
+ Timeout.timeout(Capybara.default_max_wait_time) do
7
+ loop until finished_all_ajax_requests?
8
+ end
9
+ end
10
+
11
+ # Tuned for jQuery, override it if you don't use jQuery.
12
+ def finished_all_ajax_requests?
13
+ page.evaluate_script('jQuery.active').zero?
14
+ end
15
+
16
+ def pause
17
+ $stderr.write 'Press enter to continue'
18
+ $stdin.gets
19
+ end
20
+
21
+ ::RSpec.configuration.include self, type: :feature
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,79 @@
1
+ require 'active_support/concern'
2
+
3
+ module RailsStuff
4
+ module RSpecHelpers
5
+ module Groups
6
+ module Request
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ # Define default params for ResourcesController.
11
+ #
12
+ # subject { -> { patch(resource_path, params: params) } }
13
+ # let(:resource) { create(:user) }
14
+ # let(:resource_params) { {name: 'new name'} }
15
+ # # params will be {user: {name: 'new name'}}
16
+ if described_class.respond_to?(:resource_param_name)
17
+ let(:params) { {described_class.resource_param_name => resource_params} }
18
+ end
19
+ end
20
+
21
+ module ClassMethods
22
+ # Adds `referer`, `referer_path` and `headers` with `let`.
23
+ # Requires `root_url`
24
+ def set_referer
25
+ let(:referer) { root_url.sub(%r{/$}, referer_path) }
26
+ let(:referer_path) { '/test_referer' }
27
+ let(:headers) do
28
+ headers = {Referer: referer}
29
+ defined?(super) ? super().merge(headers) : headers
30
+ end
31
+ end
32
+
33
+ # Perform simple request to initialize session.
34
+ # Useful for `change` matchers.
35
+ def init_session
36
+ before do
37
+ path = defined?(init_session_path) ? init_session_path : '/'
38
+ get(path)
39
+ end
40
+ end
41
+
42
+ def with_csrf_protection!
43
+ around do |ex|
44
+ begin
45
+ old = ActionController::Base.allow_forgery_protection
46
+ ActionController::Base.allow_forgery_protection = true
47
+ ex.run
48
+ ensure
49
+ ActionController::Base.allow_forgery_protection = old
50
+ end
51
+ end
52
+ let(:csrf_response) do
53
+ path = defined?(csrf_response_path) ? csrf_response_path : '/'
54
+ get(path) && response.body
55
+ end
56
+ let(:csrf_param) { csrf_response.match(/meta name="csrf-param" content="([^"]*)"/)[1] }
57
+ let(:csrf_token) { csrf_response.match(/<meta name="csrf-token" content="([^"]*)"/)[1] }
58
+ end
59
+ end
60
+
61
+ # Generate url to current controller.
62
+ def controller_path(**options)
63
+ url_for(controller: described_class.controller_path, only_path: true, **options)
64
+ end
65
+
66
+ # Generate url to current controller with resource and default action to `:show`.
67
+ # It uses `resource` method by default:
68
+ #
69
+ # expect(resource_path).to eq resource_path(resource)
70
+ # resource_path(other_user, action: :edit)
71
+ def resource_path(resource = self.resource, **options)
72
+ controller_path(action: :show, id: resource, **options)
73
+ end
74
+
75
+ ::RSpec.configuration.include self, type: :request
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,12 @@
1
+ RSpec::Matchers.define :be_valid_js do
2
+ match_unless_raises do |actual|
3
+ ExecJS.exec("var test = function(){\n#{actual}\n}")
4
+ end
5
+
6
+ failure_message do |actual|
7
+ js_error = rescued_exception.message
8
+ line = js_error.lines[0].split(':').last.to_i - 1
9
+ js_error = /SyntaxError.*$/.match(js_error)[0] if js_error.include?('SyntaxError')
10
+ "expected string to be valid js, got '#{js_error}' on line #{line} for\n\n#{actual}"
11
+ end
12
+ end
@@ -0,0 +1,53 @@
1
+ module RailsStuff
2
+ module RSpecHelpers
3
+ module Matchers
4
+ module RedirectWithTurbolinks
5
+ include ::RSpec::Matchers
6
+
7
+ class XhrFailure < StandardError; end
8
+
9
+ def matches?(response)
10
+ return unless @scope.request
11
+ if @scope.request.xhr?
12
+ match_unless_raises(XhrFailure) { matches_xhr?(response) }
13
+ else
14
+ super
15
+ end
16
+ end
17
+
18
+ def failure_message
19
+ @scope.request ? super : 'Request was not performed'
20
+ end
21
+
22
+ def matches_xhr?(response)
23
+ unless be_ok.matches?(response)
24
+ raise XhrFailure, "Expect #{response.inspect} to be OK for Turbolinks redirect"
25
+ end
26
+ location, _options = turbolinks_location(response)
27
+ raise XhrFailure, "No Turbolinks redirect in\n\n#{response.body}" unless location
28
+ active_support_assertion(location)
29
+ end
30
+
31
+ def turbolinks_location(response)
32
+ body = response.body
33
+ return unless body
34
+ match_data = /Turbolinks\.visit\(([^,]+)(,\s*([^)]+))?\)/.match(body)
35
+ return unless match_data
36
+ [match_data[1], match_data[3]].map { |x| JSON.parse("[#{x}]")[0] }
37
+ end
38
+
39
+ def active_support_assertion(location)
40
+ redirect_is = @scope.send(:normalize_argument_to_redirection, location)
41
+ redirect_expected = @scope.send(:normalize_argument_to_redirection, @expected)
42
+ message = "Expected response to be a Turbolinks redirect to <#{redirect_expected}>" \
43
+ " but was a redirect to <#{redirect_is}>"
44
+ @scope.assert_operator redirect_expected, :===, redirect_is, message
45
+ rescue ActiveSupport::TestCase::Assertion => e
46
+ raise XhrFailure, e
47
+ end
48
+
49
+ ::RSpec::Rails::Matchers::RedirectTo::RedirectTo.prepend(self) if defined?(::RSpec::Rails)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,21 @@
1
+ module RailsStuff
2
+ module RSpecHelpers
3
+ module Signinable
4
+ # Context-level helper to add before filter to sign in user.
5
+ # Adds `current_user` with let if not defined yet or with gven block.
6
+ #
7
+ # Instance-level `sign_in(user_or_nil)` method must be defined, so
8
+ # this module can be used in any of feature, request or controller groups.
9
+ #
10
+ # sign_in { owner }
11
+ # sign_in # will call current_user or define it with nil
12
+ def sign_in(&block)
13
+ if block || !instance_methods.include?(:current_user)
14
+ block ||= ->(*) {}
15
+ let(:current_user, &block)
16
+ end
17
+ before { sign_in(instance_eval { current_user }) }
18
+ end
19
+ end
20
+ end
21
+ end