rails_stuff 0.5.1 → 0.6.0.rc1

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