diff --git a/.gitignore b/.gitignore index 95cf2de..61982c5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ pkg/* *.gem .bundle .rvmrc +.ruby-version +.versions.conf Gemfile.lock log/*.log .DS_Store diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..44f6b5b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: ruby +rvm: + - 2.3.0 +env: + - DB=sqlite +before_install: + - gem update bundler +script: bundle exec rspec spec diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0c15023 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,30 @@ +# Next Release + +## 1.4.0 (10/21/2016) + +* Add ability to `store_sign_in` info with devise provider +* Respect `relative_url_root` +* Fix `selected_user_of_helper` bug + +## 1.3.0 (07/23/2016) + +* Add capybara support +* Add class and style options to `switch_user_select` +* Fix `grouped_options_for_select` for rails 3.2 + +## 1.2.0 (12/01/2015) + +* Replace select option to `group_option` + +## 1.1.0 (07/01/2015) + +* Rails 3.x compatibility +* Don't attempt to query db if scope str isn't in `scope_id` str +* Allow custom method as `available_users_names` + +## 1.0.0 (06/22/2015) + +* Performance improved, only load necessary data. +* Devise provider- don't store `sign_in` details +* Security :guardsman:, raise RoutingError in `developer_modes_only` +* Restore original user after sorcery logout diff --git a/README.md b/README.md index b0c9370..79a7c72 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # switch_user +[![Build Status](https://secure.travis-ci.org/flyerhzm/switch_user.png)](http://travis-ci.org/flyerhzm/switch_user) + Inspired from [hobo][0], switch_user provides a convenient way to switch current user without needing to log out and log in manually. ## Use Case @@ -12,7 +14,7 @@ switch_user is very useful in such use cases ## Example -Visit here: , switch the current user in the select box. +Visit here: , switch the current user in the select box. And source code here: @@ -22,6 +24,9 @@ Add in Gemfile. ```ruby gem "switch_user" ``` + +If you get the following error: **undefined method `before_action' for SwitchUserController:Class**, you are probably using an older version of Rails (<4). You can use this gem: https://github.com/pschambacher/rails3-before_action + ## Usage Add following code into your layout page. @@ -34,6 +39,12 @@ or haml = switch_user_select +If you want to add a class or styles + + <%= switch_user_select class: 'special-select', styles: 'width: 220px' %> + + = switch_user_select class: 'special-select', styles: 'width: 220px' + If there are too many users (on production), the switch_user_select is not a good choice, you should call the switch user request by yourself. <%= link_to user.login, "/switch_user?scope_identifier=user_#{user.id}" %> @@ -45,7 +56,8 @@ If there are too many users (on production), the switch_user_select is not a goo If you have a wildcard route in your project, add a route before the wildcard route. ```ruby # config/routes.rb -get 'switch_user' => 'switch_user#set_current_user' +get 'switch_user', to: 'switch_user#set_current_user' +get 'switch_user/remember_user', to: 'switch_user#remember_user' # wildcard route that will get get ':id' => 'pages#show' ``` @@ -54,13 +66,13 @@ get ':id' => 'pages#show' By default, you can switch between Guest and all users in users table, you don't need to do anything. The following is some of the more commonly used configuration options. ```ruby SwitchUser.setup do |config| - # provider may be :devise, :authlogic, :clearance, :restful_authentication or :sorcery + # provider may be :devise, :authlogic, :clearance, :restful_authentication, :sorcery, or {name: :devise, store_sign_in: true} config.provider = :devise # available_users is a hash, # key is the model name of user (:user, :admin, or any name you use), # value is a block that return the users that can be switched. - config.available_users = { :user => lambda { User.all } } + config.available_users = { user: -> { User.all } } # use User.scoped instead for rails 3.2 # available_users_identifiers is a hash, # keys in this hash should match a key in the available_users hash @@ -68,55 +80,55 @@ SwitchUser.setup do |config| # defaults to id # this hash is to allow you to specify a different column to # expose for instance a username on a User model instead of id - config.available_users_identifiers = { :user => :id } + config.available_users_identifiers = { user: :id } # available_users_names is a hash, # keys in this hash should match a key in the available_users hash # value is the column name which will be displayed in select box - config.available_users_names = { :user => :email } + config.available_users_names = { user: :email } # controller_guard is a block, # if it returns true, the request will continue, # else the request will be refused and returns "Permission Denied" # if you switch from "admin" to user, the current_user param is "admin" - config.controller_guard = lambda { |current_user, request| Rails.env.development? } + config.controller_guard = ->(current_user, request) { Rails.env.development? } # view_guard is a block, # if it returns true, the switch user select box will be shown, # else the select box will not be shown # if you switch from admin to "user", the current_user param is "user" - config.view_guard = lambda { |current_user, request| Rails.env.development? } + config.view_guard = ->(current_user, request) { Rails.env.development? } # redirect_path is a block, it returns which page will be redirected # after switching a user. - config.redirect_path = lambda { |request, params| '/' } + config.redirect_path = ->(request, params) { '/' } end ``` If you need to override the default configuration, run rails g switch_user:install and a copy of the configuration file will be copied to config/initializers/switch_user.rb in your project. If you want to switch both available users and available admins ```ruby -config.available_users = { :user => lambda { User.available }, :admin => lambda { Admin.available } } +config.available_users = { :user => -> { User.available }, :admin => -> { Admin.available } } ``` If you want to use name column as the user identifier ```ruby -config.available_users_identifiers => { :user => :name } +config.available_users_identifiers => { user: :name } ``` If you want to display the login field in switch user select box ```ruby -config.available_users_names = { :user => :login } +config.available_users_names = { user: :login } ``` If you only allow switching from admin to user in production environment ```ruby -config.controller_guard = lambda { |current_user, request| Rails.env == "production" and current_user.admin? } +config.controller_guard = ->(current_user, request) { Rails.env.production? && current_user.admin? } ``` If you only want to display switch user select box for admins in production environment ```ruby -config.view_guard = lambda { |current_user, request| Rails.env == "production" and current_user and current_user.admin? } +config.view_guard = ->(current_user, request) { Rails.env.production? && current_user && current_user.admin? } ``` If you want to redirect user to "/dashboard" page ```ruby -config.redirect_path = lambda { |request, params| "/dashboard" } +config.redirect_path = ->(request, params) { "/dashboard" } ``` If you want to hide a 'Guest' item in the helper dropdown list ```ruby @@ -128,17 +140,41 @@ Sometimes you'll want to be able to switch to an unprivileged user and then back You will need to make the following modifications to your configuration: ```ruby config.switch_back = true -config.controller_guard = lambda { |current_user, request, original_user| - current_user && current_user.admin? || original_user && original_user.super_admin? -} +config.controller_guard = ->(current_user, request, original_user) { current_user && current_user.admin? || original_user && original_user.super_admin? } # Do something similar for the view_guard as well. ``` This example would allow an admin user to user switch_user, but would only let you switch back to another user if the original user was a super admin. +## Using SwitchUser with RSpec and Capybara + +Add the following code to spec/support/switch_user.rb or spec/spec_helper.rb: + +```ruby +require 'switch_user/rspec' +``` + +You can now write your specs like so : + +```ruby +feature "Your feature", type: :feature do + background do + @user = User.make(email: 'user@example.com', password: 'password') + end + + scenario "Your scenario" do + switch_user @user + # or + # switch_user :user, @user.id + + visit '/' + end +end +``` + ### How it works Click the checkbox next to switch_user_select menu to remember that user for this session. Once this -has been checked, that user is passed in as the 3rd option to the view and controller guards. +has been checked, that user is passed in as the 3rd option to the view and controller guards. This allows you to check against current_user as well as that original_user to see if the switch_user action should be allowed. @@ -146,8 +182,14 @@ switch_user action should be allowed. This feature should be used with extreme caution because of the security implications. This is especially true in a production environment. +## Contributing + +#### Run tests + +`bundle exec rspec spec` + ## Credit -Copyright © 2010 - 2012 Richard Huang (flyerhzm@gmail.com), released under the MIT license +Copyright © 2010 - 2017 Richard Huang (flyerhzm@gmail.com), released under the MIT license [0]: https://github.com/tablatom/hobo diff --git a/app/controllers/switch_user_controller.rb b/app/controllers/switch_user_controller.rb index 7c7fbf8..0b5366f 100644 --- a/app/controllers/switch_user_controller.rb +++ b/app/controllers/switch_user_controller.rb @@ -1,5 +1,5 @@ class SwitchUserController < ApplicationController - before_filter :developer_modes_only + before_action :developer_modes_only, :switch_back def set_current_user handle_request(params) @@ -7,10 +7,21 @@ def set_current_user redirect_to(SwitchUser.redirect_path.call(request, params)) end + def remember_user + redirect_to(SwitchUser.redirect_path.call(request, params)) + end + private + def switch_back + if SwitchUser.switch_back + provider.remember_current_user(true) if params[:remember] == "true" + provider.remember_current_user(false) if params[:remember] == "false" + end + end + def developer_modes_only - render :text => "Permission Denied", :status => 403 unless available? + raise ActionController::RoutingError.new('Do not try to hack us.') unless available? end def available? @@ -18,10 +29,6 @@ def available? end def handle_request(params) - if SwitchUser.switch_back - provider.remember_current_user(params[:remember] == "true") - end - if params[:scope_identifier].blank? provider.logout_all else @@ -31,9 +38,9 @@ def handle_request(params) return end if SwitchUser.login_exclusive - provider.login_exclusive(record.user, :scope => record.scope) + provider.login_exclusive(record.user, scope: record.scope) else - provider.login_inclusive(record.user, :scope => record.scope) + provider.login_inclusive(record.user, scope: record.scope) end end end diff --git a/app/helpers/switch_user_helper.rb b/app/helpers/switch_user_helper.rb index 258fe9e..c57d7b5 100644 --- a/app/helpers/switch_user_helper.rb +++ b/app/helpers/switch_user_helper.rb @@ -1,18 +1,33 @@ module SwitchUserHelper SelectOption = Struct.new(:label, :scope_id) - def switch_user_select + def switch_user_select(options = {}) return unless available? - if provider.current_user - selected_user = "user_#{current_user.id}" - else - selected_user = nil + selected_user = nil + + grouped_options_container = {}.tap do |h| + SwitchUser.all_users.each do |record| + scope = record.is_a?(SwitchUser::GuestRecord) ? :Guest : record.scope.to_s.capitalize + h[scope] ||= [] + h[scope] << [record.label, record.scope_id] + + if selected_user.nil? + unless record.is_a?(SwitchUser::GuestRecord) + if provider.current_user?(record.user, record.scope) + selected_user = record.scope_id + end + end + end + end end - render :partial => "switch_user/widget", - :locals => { - :options => SwitchUser.all_users, - :current_scope => selected_user + option_tags = grouped_options_for_select(grouped_options_container.to_a, selected_user) + + render partial: "switch_user/widget", + locals: { + option_tags: option_tags, + classes: options[:class], + styles: options[:style], } end diff --git a/app/views/switch_user/_widget.html.erb b/app/views/switch_user/_widget.html.erb index a0c5590..c397c1f 100644 --- a/app/views/switch_user/_widget.html.erb +++ b/app/views/switch_user/_widget.html.erb @@ -1,4 +1,4 @@ <% if SwitchUser.switch_back %> - <%= check_box_tag "remember_user", "remember_user", provider.original_user.present?, :onchange => "location.href = '/switch_user/remember_user?remember=' + encodeURIComponent(this.checked)" %> + <%= check_box_tag "remember_user", "remember_user", provider.original_user.present?, onchange: "location.href = '#{ActionController::Base.relative_url_root || '/'}switch_user/remember_user?remember=' + encodeURIComponent(this.checked)" %> <% end %> -<%= select_tag "switch_user_identifier", options_from_collection_for_select(options, :scope_id, :label, current_scope), :onchange => "location.href = '/switch_user?scope_identifier=' + encodeURIComponent(this.options[this.selectedIndex].value)" %> +<%= select_tag "switch_user_identifier", option_tags, onchange: "location.href = '#{ActionController::Base.relative_url_root || '/'}switch_user?scope_identifier=' + encodeURIComponent(this.options[this.selectedIndex].value)", class: classes, style: styles %> diff --git a/config/routes.rb b/config/routes.rb index 271989c..6d341b7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,4 @@ -if SwitchUser.generate_routes - Rails.application.routes.draw do - get :switch_user, :to => 'switch_user#set_current_user' - end +Rails.application.routes.draw do + get :switch_user, to: 'switch_user#set_current_user' + get 'switch_user/remember_user', to: 'switch_user#remember_user' end diff --git a/lib/generators/switch_user/install/templates/switch_user.rb b/lib/generators/switch_user/install/templates/switch_user.rb index e5ff6ec..f954b94 100644 --- a/lib/generators/switch_user/install/templates/switch_user.rb +++ b/lib/generators/switch_user/install/templates/switch_user.rb @@ -1,14 +1,11 @@ SwitchUser.setup do |config| - # have switch user add routes to its controllers automatically - # config.generate_routes = true - # provider may be :devise, :authlogic, :clearance, :restful_authentication, :sorcery, or :session config.provider = :devise # available_users is a hash, # key is the model name of user (:user, :admin, or any name you use), # value is a block that return the users that can be switched. - config.available_users = { :user => lambda { User.all } } + config.available_users = { user: -> { User.all } } # available_users_identifiers is a hash, # keys in this hash should match a key in the available_users hash @@ -16,28 +13,28 @@ # defaults to id # this hash is to allow you to specify a different column to # expose for instance a username on a User model instead of id - config.available_users_identifiers = { :user => :id } + config.available_users_identifiers = { user: :id } # available_users_names is a hash, # keys in this hash should match a key in the available_users hash # value is the column name which will be displayed in select box - config.available_users_names = { :user => :email } + config.available_users_names = { user: :email } # controller_guard is a block, # if it returns true, the request will continue, # else the request will be refused and returns "Permission Denied" # if you switch from "admin" to user, the current_user param is "admin" - config.controller_guard = lambda { |current_user, request| Rails.env.development? } + config.controller_guard = ->(current_user, request) { Rails.env.development? } # view_guard is a block, # if it returns true, the switch user select box will be shown, # else the select box will not be shown # if you switch from admin to "user", the current_user param is "user" - config.view_guard = lambda { |current_user, request| Rails.env.development? } + config.view_guard = ->(current_user, request) { Rails.env.development? } # redirect_path is a block, it returns which page will be redirected # after switching a user. - config.redirect_path = lambda { |request, params| '/' } + config.redirect_path = ->(request, params) { '/' } # helper_with_guest is a boolean value, if it set to false # the guest item in the helper won't be shown diff --git a/lib/switch_user.rb b/lib/switch_user.rb index 56be5a8..0d864a9 100644 --- a/lib/switch_user.rb +++ b/lib/switch_user.rb @@ -12,7 +12,6 @@ module SwitchUser class InvalidScope < Exception; end - mattr_accessor :generate_routes mattr_accessor :provider mattr_accessor :available_users mattr_accessor :available_users_identifiers @@ -39,7 +38,7 @@ def self.guard_class=(klass) end def self.all_users - data_sources.users + data_sources.all end def self.data_sources @@ -48,20 +47,19 @@ def self.data_sources name = available_users_names.fetch(scope) DataSource.new(loader, scope, identifier, name) end - sources.unshift(GuestDataSource.new("Guest")) if helper_with_guest + sources.unshift(GuestDataSource.new) if helper_with_guest DataSources.new(sources) end def self.reset_config - self.generate_routes = true self.provider = :devise - self.available_users = { :user => lambda { User.all } } - self.available_users_identifiers = { :user => :id } - self.available_users_names = { :user => :email } + self.available_users = { user: -> { User.all } } + self.available_users_identifiers = { user: :id } + self.available_users_names = { user: :email } self.guard_class = "SwitchUser::LambdaGuard" - self.controller_guard = lambda { |current_user, request| Rails.env.development? } - self.view_guard = lambda { |current_user, request| Rails.env.development? } - self.redirect_path = lambda { |request, params| request.env["HTTP_REFERER"] ? :back : root_path } + self.controller_guard = ->(current_user, request) { Rails.env.development? } + self.view_guard = ->(current_user, request) { Rails.env.development? } + self.redirect_path = ->(request, params) { request.env["HTTP_REFERER"] ? :back : root_path } self.session_key = :user_id self.helper_with_guest = true self.switch_back = false diff --git a/lib/switch_user/data_source.rb b/lib/switch_user/data_source.rb index 05246b3..dabf141 100644 --- a/lib/switch_user/data_source.rb +++ b/lib/switch_user/data_source.rb @@ -1,50 +1,58 @@ module SwitchUser - DataSource = Struct.new(:loader, :scope, :identifier, :name) do - def users - loader.call.map {|u| Record.new(u, self) } - end - end + class DataSources + attr_reader :sources - GuestRecord = Struct.new(:scope) do - def equivalent?(other_scope_id) - scope_id == other_scope_id + def initialize(sources) + @sources = sources end - def label - "Guest" + def all + sources.flat_map { |source| source.all } end - def scope_id + def find_scope_id(scope_id) + sources.map {|source| source.find_scope_id(scope_id) }.compact.first end end - class GuestDataSource - def initialize(name) + class DataSource + attr_reader :loader, :scope, :identifier, :name + + def initialize(loader, scope, identifier, name) + @loader = loader + @scope = scope + @identifier = identifier @name = name end - def users - [ GuestRecord.new(self) ] + def all + loader.call.map { |user| Record.new(user, self) } + end + + def find_scope_id(scope_id) + scope_regexp = /\A#{scope}_/ + return unless scope_id =~ scope_regexp + + user = loader.call.where(identifier => scope_id.sub(scope_regexp, '')).first + Record.new(user, self) end end - DataSources = Struct.new(:sources) do - def users - sources.flat_map {|source| source.users } + class GuestDataSource + def all + [ GuestRecord.new ] end def find_scope_id(scope_id) - users.flat_map.detect {|u| u.scope_id == scope_id } end end - Record = Struct.new(:user, :source) do - def equivalent?(other_scope_id) - scope_id == other_scope_id - end + class Record + attr_reader :user, :source - def scope_id - "#{source.scope}_#{user.send(source.identifier)}" + def initialize(user, source) + @user = user + @source = source end def label @@ -54,5 +62,18 @@ def label def scope source.scope end + + def scope_id + "#{source.scope}_#{user.send(source.identifier)}" + end + end + + class GuestRecord + def label + "Guest" + end + + def scope_id + end end end diff --git a/lib/switch_user/provider.rb b/lib/switch_user/provider.rb index 2d873a6..d0c4d18 100644 --- a/lib/switch_user/provider.rb +++ b/lib/switch_user/provider.rb @@ -10,8 +10,15 @@ module Provider autoload :Session, "switch_user/provider/session" def self.init(controller) - klass_part = SwitchUser.provider.to_s.classify - klass = "SwitchUser::Provider::#{klass_part}".constantize + if SwitchUser.provider.is_a?(Hash) + klass_part = SwitchUser.provider[:name] + else + klass_part = SwitchUser.provider + end + + klass_part = klass_part.to_s.classify + + klass = "SwitchUser::Provider::#{klass_part}".constantize klass.new(controller) end diff --git a/lib/switch_user/provider/base.rb b/lib/switch_user/provider/base.rb index d7c3233..83a44e0 100644 --- a/lib/switch_user/provider/base.rb +++ b/lib/switch_user/provider/base.rb @@ -33,7 +33,7 @@ def original_user user_identifier = @controller.session[:original_user_scope_identifier] if user_identifier - UserLoader.prepare(:scope_identifier => user_identifier).user + UserLoader.prepare(scope_identifier: user_identifier).user end end @@ -55,6 +55,11 @@ def remember_current_user(remember) def clear_original_user @controller.session.delete(:original_user_scope_identifier) end + + def current_user?(user, scope = :user) + current_user(scope) == user + end + end end end diff --git a/lib/switch_user/provider/devise.rb b/lib/switch_user/provider/devise.rb index 930e0a8..ff70f57 100644 --- a/lib/switch_user/provider/devise.rb +++ b/lib/switch_user/provider/devise.rb @@ -6,15 +6,19 @@ def initialize(controller) @warden = @controller.warden end - def login(user, scope = :user) - @warden.set_user(user, :scope => scope) + def login(user, scope = nil) + if SwitchUser.provider.is_a?(Hash) && SwitchUser.provider[:store_sign_in] + @warden.set_user(user, scope: scope) + else + @warden.session_serializer.store(user, scope) + end end - def logout(scope = :user) + def logout(scope = nil) @warden.logout(scope) end - def current_user(scope = :user) + def current_user(scope = nil) @warden.user(scope) end end diff --git a/lib/switch_user/rspec.rb b/lib/switch_user/rspec.rb new file mode 100644 index 0000000..a97f24e --- /dev/null +++ b/lib/switch_user/rspec.rb @@ -0,0 +1,13 @@ +require 'switch_user/rspec/feature_helpers' + +require 'rspec/core' + +RSpec.configure do |config| + + config.include SwitchUser::RSpecFeatureHelpers, type: :feature + + config.before(:each, type: :feature) do + allow_any_instance_of(SwitchUserController).to receive(:available?).and_return(true) + end + +end diff --git a/lib/switch_user/rspec/feature_helpers.rb b/lib/switch_user/rspec/feature_helpers.rb new file mode 100644 index 0000000..b789306 --- /dev/null +++ b/lib/switch_user/rspec/feature_helpers.rb @@ -0,0 +1,44 @@ +module SwitchUser + module RSpecFeatureHelpers + + class InvalidArgument < StandardError; end + + def switch_user(user_record_or_scope, user_id=nil) + _user_scope = + case user_record_or_scope + when ActiveRecord::Base + user_record_or_scope.model_name.singular + else + user_record_or_scope + end + + _user_scope = _user_scope.to_s + + unless (SwitchUser.available_scopes.include?(_user_scope) or SwitchUser.available_scopes.include?(_user_scope.to_sym)) + raise SwitchUser::InvalidScope.new("don't allow this user sign in, please check config.available_users") + end + + _user_id = + case user_record_or_scope + when ActiveRecord::Base + identifier = SwitchUser.available_users_identifiers[_user_scope] || SwitchUser.available_users_identifiers[_user_scope.to_sym] + if identifier.nil? + raise SwitchUser::InvalidScope.new("don't allow switch this user, please check config.available_users_identifiers") + end + user_record_or_scope.send identifier + else + user_id + end + + if _user_id.to_s.empty? + raise InvalidArgument.new("don't allow switch this user, user_id is empty") + end + + scope_identifier = "#{_user_scope}_#{_user_id}" + + visit "/switch_user?scope_identifier=#{scope_identifier}" + end + + end + +end diff --git a/lib/switch_user/user_set.rb b/lib/switch_user/user_set.rb index a007f36..ed7454e 100644 --- a/lib/switch_user/user_set.rb +++ b/lib/switch_user/user_set.rb @@ -24,7 +24,7 @@ def initialize(scope, identifier, label, base_scope) end def find_user(id) - Record.build(users.where(:id => id).first, self) + Record.build(users.where(id: id).first, self) end alias :[] :find_user diff --git a/lib/switch_user/version.rb b/lib/switch_user/version.rb index f467eb9..8260abc 100644 --- a/lib/switch_user/version.rb +++ b/lib/switch_user/version.rb @@ -1,3 +1,3 @@ module SwitchUser - VERSION = "0.9.5.1" + VERSION = "1.4.0.1" end diff --git a/spec/controllers/switch_user_controller_spec.rb b/spec/controllers/switch_user_controller_spec.rb index d5efae3..8525e35 100644 --- a/spec/controllers/switch_user_controller_spec.rb +++ b/spec/controllers/switch_user_controller_spec.rb @@ -2,46 +2,44 @@ require 'switch_user' require 'switch_user_controller' -describe SwitchUserController, :type => :controller do +RSpec.describe SwitchUserController, type: :controller do before do SwitchUser.provider = :dummy end - let(:admin) { double(:admin, :admin? => true) } + let(:admin) { double(:admin, admin?: true) } let(:provider) { double(:provider, - :original_user => admin, - :current_user => nil) + original_user: admin, + current_user: nil) } describe "#set_current_user" do it "redirects the user to the specified location" do - SwitchUser.redirect_path = lambda {|_,_| "/path"} + SwitchUser.redirect_path = ->(_,_) { "/path" } allow(controller).to receive(:available?).and_return(true) - get :set_current_user, :scope_identifier => "user_1" + get :set_current_user, scope_identifier: "user_1" - response.should redirect_to("/path") + expect(response).to redirect_to("/path") end it "denies access according to the guard block" do - SwitchUser.controller_guard = lambda {|_,_,_| false } - get :set_current_user - - response.should be_forbidden + SwitchUser.controller_guard = ->(_,_,_) { false } + expect { + get :set_current_user + }.to raise_error(ActionController::RoutingError) end describe "requests with a privileged original_user" do before do - SwitchUser.controller_guard = lambda {|current_user, _, original_user| - current_user.try(:admin?) || original_user.try(:admin?) - } + SwitchUser.controller_guard = ->(current_user, _, original_user) { current_user.try(:admin?) || original_user.try(:admin?) } end it "allows access using the original_user param" do allow(controller).to receive(:provider).and_return(provider) - provider.should_receive(:logout_all) + expect(provider).to receive(:logout_all) get :set_current_user - response.should be_redirect + expect(response).to be_redirect end end end @@ -52,20 +50,20 @@ SwitchUser.switch_back = true end it "can remember the current user" do - provider.should_receive(:remember_current_user).with(true) + expect(provider).to receive(:remember_current_user).with(true) - get :remember_user, :remember => "true" + get :remember_user, remember: "true" end it "can forget the current user" do - provider.should_receive(:remember_current_user).with(false) + expect(provider).to receive(:remember_current_user).with(false) - get :remember_user, :remember => "false" + get :remember_user, remember: "false" end it "does nothing if switch_back is not enabled" do SwitchUser.switch_back = false - provider.should_not_receive(:remember_current_user) + expect(provider).not_to receive(:remember_current_user) - get :remember_user, :remember => "true" + get :remember_user, remember: "true" end end end diff --git a/spec/helpers/switch_user_helper_spec.rb b/spec/helpers/switch_user_helper_spec.rb new file mode 100644 index 0000000..5c9cd25 --- /dev/null +++ b/spec/helpers/switch_user_helper_spec.rb @@ -0,0 +1,173 @@ +require 'spec_helper' +require 'switch_user' +require 'switch_user_helper' + +RSpec.describe SwitchUserHelper, type: :helper do + before do + SwitchUser.provider = :dummy + end + + let(:user) { double(:user, id: 1) } + let(:admin) { double(:admin, id: 1) } + let(:provider) { + _provider = SwitchUser::Provider::Dummy.new(controller) + _provider + } + + describe "#switch_user_select" do + let(:guest_record) { SwitchUser::GuestRecord.new } + let(:user_record) { double(:user_record, user: user, scope: :user, label: 'user1', scope_id: 'user_1') } + let(:admin_record) { double(:admin_record, user: admin, scope: :admin, label: 'admin1', scope_id: 'admin_1') } + + let(:guest_option_tags) { %Q^^ } + let(:user_option_tags) { %Q^^ } + let(:user_selected_option_tags) { %Q^^ } + let(:admin_option_tags) { %Q^^ } + let(:admin_selected_option_tags) { %Q^^ } + + + before do + allow(SwitchUser).to receive(:switch_back).and_return(false) + + allow(helper).to receive(:available?).and_return(true) + + provider.instance_variable_set(:@user, user) + allow(helper).to receive(:provider).and_return(provider) + + allow(provider).to receive(:current_user).and_return(user) + + allow(SwitchUser).to receive(:all_users).and_return([guest_record, user_record]) + end + + it "when unavailable" do + allow(helper).to receive(:available?).and_return(false) + + expect(helper.switch_user_select).to eq(nil) + end + + it "when current_user is nil and all_users is []" do + allow(provider).to receive(:current_user).and_return(nil) + allow(SwitchUser).to receive(:all_users).and_return([]) + + expect(helper.switch_user_select).not_to match(%r{}) + end + + it "when current_user is nil and all_users is [guest_record]" do + allow(provider).to receive(:current_user).and_return(nil) + allow(SwitchUser).to receive(:all_users).and_return([guest_record]) + + expect(helper.switch_user_select).to match(%r{#{guest_option_tags}}) + end + + it "when current_user is nil and all_users is [guest_record, user_record]" do + allow(provider).to receive(:current_user).and_return(nil) + allow(SwitchUser).to receive(:all_users).and_return([guest_record, user_record]) + + expect(helper.switch_user_select).to match(%r{#{guest_option_tags}}) + expect(helper.switch_user_select).to match(%r{#{user_option_tags}}) + end + + it "when current_user is user and all_users is []" do + allow(provider).to receive(:current_user).and_return(user) + allow(SwitchUser).to receive(:all_users).and_return([]) + + expect(helper.switch_user_select).not_to match(%r{}) + end + + it "when current_user is user and all_users is [guest_record, user_record]" do + allow(provider).to receive(:current_user).and_return(user) + allow(SwitchUser).to receive(:all_users).and_return([guest_record, user_record]) + + expect(helper.switch_user_select).to match(%r{#{guest_option_tags}}) + expect(helper.switch_user_select).to match(%r{#{user_selected_option_tags}}) + end + + it "when current_user is default allow and all_users is default allow" do + expect(helper.switch_user_select).to match(%r{#{guest_option_tags}}) + expect(helper.switch_user_select).to match(%r{#{user_selected_option_tags}}) + end + + it "when current_user is user and all_users is [guest_record, user_record, admin_record]" do + allow(provider).to receive(:current_user).and_return(user) + allow(SwitchUser).to receive(:all_users).and_return([guest_record, user_record, admin_record]) + + expect(helper.switch_user_select).to match(%r{#{guest_option_tags}}) + expect(helper.switch_user_select).to match(%r{#{user_selected_option_tags}}) + expect(helper.switch_user_select).to match(%r{#{admin_option_tags}}) + end + + it "when current_user is admin and all_users is [guest_record, user_record, admin_record]" do + provider.instance_variable_set(:@user, admin) + allow(helper).to receive(:provider).and_return(provider) + + allow(provider).to receive(:current_user).and_return(admin) + + allow(SwitchUser).to receive(:all_users).and_return([guest_record, user_record, admin_record]) + + expect(helper.switch_user_select).to match(%r{#{guest_option_tags}}) + expect(helper.switch_user_select).to match(%r{#{user_option_tags}}) + expect(helper.switch_user_select).to match(%r{#{admin_selected_option_tags}}) + end + + it "when current_user is admin and all_users is [guest_record, user_record]" do + provider.instance_variable_set(:@user, admin) + allow(helper).to receive(:provider).and_return(provider) + + allow(provider).to receive(:current_user).and_return(admin) + + allow(SwitchUser).to receive(:all_users).and_return([guest_record, user_record]) + + expect(helper.switch_user_select).to match(%r{#{guest_option_tags}}) + expect(helper.switch_user_select).to match(%r{#{user_option_tags}}) + expect(helper.switch_user_select).to_not match(%r{#{admin_option_tags}}) + end + end + + describe "#user_tag_value" do + it "for user" do + user = double(:user, id: 1) + + expect(helper.send(:user_tag_value, user, :id, :user)).to eq('user_1') + end + end + + describe "#user_tag_label" do + it "when name has call method" do + user = double(:user) + name = ->(user) { 'user1' } + + expect(helper.send(:user_tag_label, user, name)).to eq('user1') + end + + it "when name not has call method" do + user = double(:name, name: 'user1') + name = :name + + expect(helper.send(:user_tag_label, user, name)).to eq('user1') + end + end + + describe "#available?" do + it "return true" do + allow_any_instance_of(SwitchUser.guard_class).to receive(:view_available?).and_return(true) + + expect(helper.send(:available?)).to eq(true) + end + + it "return false" do + allow_any_instance_of(SwitchUser.guard_class).to receive(:view_available?).and_return(false) + + expect(helper.send(:available?)).to eq(false) + end + end + + describe "#provider" do + it "normal" do + allow(SwitchUser::Provider).to receive(:init).with(controller).and_return(provider) + + expect(helper.send(:provider)).to eq(provider) + end + end + + +end diff --git a/spec/integration/switch_user_spec.rb b/spec/integration/switch_user_spec.rb index c1ddd8c..9f472c6 100644 --- a/spec/integration/switch_user_spec.rb +++ b/spec/integration/switch_user_spec.rb @@ -1,57 +1,82 @@ require 'spec_helper' -describe "Using SwitchUser", :type => :request do - let(:user) { User.create!(:email => "foo@bar.com", :admin => true) } - let(:other_user) { User.create!(:email => "other@bar.com", :admin => false) } +RSpec.describe "Using SwitchUser", type: :request do + let(:user) { User.create!(email: "foo@bar.com", admin: true) } + let(:other_user) { User.create!(email: "other@bar.com", admin: false) } + before do SwitchUser.reset_config SwitchUser.provider = :session - SwitchUser.controller_guard = lambda { |current_user, request| Rails.env.test? } - SwitchUser.redirect_path = lambda {|_,_| "/dummys/open"} + SwitchUser.controller_guard = ->(current_user, request) { Rails.env.test? } + SwitchUser.redirect_path = ->(_,_) { "/dummy/open" } end + it "signs a user in using switch_user" do # can't access protected url get "/dummy/protected" - response.should be_redirect + expect(response).to be_redirect get "/switch_user?scope_identifier=user_#{other_user.id}" - response.should be_redirect + expect(response).to be_redirect # now that we are logged in via switch_user we can access get "/dummy/protected" - response.should be_success + expect(response).to be_success end + context "using switch_back" do before do SwitchUser.switch_back = true - SwitchUser.controller_guard = lambda { |current_user, request, original_user| - current_user && current_user.admin? || original_user && original_user.admin? - } + SwitchUser.controller_guard = ->(current_user, request, original_user) { current_user && current_user.admin? || original_user && original_user.admin? } end - it "can switch back to a different user" do + + it "can switch back to a different user through remember_user endpoint" do # login - post "/login", :id => user.id + post "/login", id: user.id follow_redirect! # have SwitchUser remember us - get "/switch_user/remember_user", :remember => true - session["original_user_scope_identifier"].should be_present + get "/switch_user/remember_user", remember: true + expect(session["original_user_scope_identifier"]).to be_present # check that we can switch to another user get "/switch_user?scope_identifier=user_#{other_user.id}" - session["user_id"].should == other_user.id + expect(session["user_id"]).to eq other_user.id + + # logout + get "/logout" + expect(session["user_id"]).to be_nil + + # check that we can still switch to another user + get "/switch_user?scope_identifier=user_#{user.id}" + expect(session["user_id"]).to eq user.id + + # check that we can be un-remembered + get "/switch_user/remember_user", remember: false + expect(session["original_user"]).to be_nil + end + + it "can switch back to a different user without hitting remember_user endpoint" do + # login + post "/login", :id => user.id + follow_redirect! + + # check that we can switch to another user + get "/switch_user?scope_identifier=user_#{other_user.id}", :remember => true + expect(session["user_id"]).to eq other_user.id + expect(session["original_user_scope_identifier"]).to_not be_nil # logout get "/logout" - session["user_id"].should be_nil + expect(session["user_id"]).to be_nil # check that we can still switch to another user get "/switch_user?scope_identifier=user_#{user.id}" - session["user_id"].should == user.id + expect(session["user_id"]).to eq user.id # check that we can be un-remembered get "/switch_user/remember_user", :remember => false - session["original_user"].should be_nil + expect(session["original_user"]).to be_nil end end end diff --git a/spec/provider/authlogic_spec.rb b/spec/provider/authlogic_spec.rb index 2dbe3c3..cb19877 100644 --- a/spec/provider/authlogic_spec.rb +++ b/spec/provider/authlogic_spec.rb @@ -29,7 +29,7 @@ def current_user_session end end -describe SwitchUser::Provider::Authlogic do +RSpec.describe SwitchUser::Provider::Authlogic do let(:controller) { AuthlogicController.new } let(:provider) { SwitchUser::Provider::Authlogic.new(controller) } diff --git a/spec/provider/clearance_spec.rb b/spec/provider/clearance_spec.rb index 43257e5..5de9ff7 100644 --- a/spec/provider/clearance_spec.rb +++ b/spec/provider/clearance_spec.rb @@ -15,7 +15,7 @@ def current_user end end -describe SwitchUser::Provider::Clearance do +RSpec.describe SwitchUser::Provider::Clearance do let(:controller) { ClearanceController.new } let(:provider) { SwitchUser::Provider::Clearance.new(controller) } diff --git a/spec/provider/devise_spec.rb b/spec/provider/devise_spec.rb index 48a1920..5f8a9a4 100644 --- a/spec/provider/devise_spec.rb +++ b/spec/provider/devise_spec.rb @@ -1,6 +1,17 @@ require 'spec_helper' require 'switch_user/provider/devise' +class FakeWardenSessionSerializer + attr_accessor :user_hash + + + def store(user, scope) + return unless user + user_hash[scope] = user + end + +end + class FakeWarden attr_reader :user_hash @@ -13,6 +24,12 @@ def set_user(user, args) @user_hash[scope] = user end + def session_serializer + serializer = FakeWardenSessionSerializer.new + serializer.user_hash = @user_hash + serializer + end + def user(scope) @user_hash[scope] end @@ -32,7 +49,7 @@ def current_user end end -describe SwitchUser::Provider::Devise do +RSpec.describe SwitchUser::Provider::Devise do let(:controller) { DeviseController.new } let(:provider) { SwitchUser::Provider::Devise.new(controller) } let(:user) { double(:user) } @@ -43,44 +60,54 @@ def current_user user = double(:user) provider.login(user, :admin) - provider.current_user(:admin).should == user + expect(provider.current_user(:admin)).to eq user end describe "#login_exclusive" do before do - allow(SwitchUser).to receive(:available_users).and_return({:user => nil, :admin => nil}) + allow(SwitchUser).to receive(:available_users).and_return({user: nil, admin: nil}) provider.login(user, :admin) - provider.login_exclusive(user, :scope => "user") + provider.login_exclusive(user, scope: "user") end it "logs the user in" do - provider.current_user.should == user + expect(provider.current_user(:user)).to eq user end it "logs out other scopes" do - provider.current_user(:admin).should be_nil + expect(provider.current_user(:admin)).to be_nil end end describe "#logout_all" do it "logs out users under all scopes" do - allow(SwitchUser).to receive(:available_users).and_return({:user => nil, :admin => nil}) + allow(SwitchUser).to receive(:available_users).and_return({user: nil, admin: nil}) provider.login(user, :admin) provider.login(user, :user) provider.logout_all - provider.current_user(:admin).should be_nil - provider.current_user(:user).should be_nil + expect(provider.current_user(:admin)).to be_nil + expect(provider.current_user(:user)).to be_nil end end describe "#all_current_users" do it "pulls users from an alternate scope" do - allow(SwitchUser).to receive(:available_users).and_return({:user => nil, :admin => nil}) + allow(SwitchUser).to receive(:available_users).and_return({user: nil, admin: nil}) provider.login(user, :admin) - provider.current_users_without_scope.should == [user] + expect(provider.current_users_without_scope).to eq [user] + end + end + + describe "#current_user?" do + it "logs the user in" do + user = double(:user) + provider.login(user, :user) + + expect(provider.current_user?(user, :user)).to eq true + expect(provider.current_user?(user, :admin)).to eq false end end end diff --git a/spec/provider/dummy_spec.rb b/spec/provider/dummy_spec.rb index 8366532..07b1d93 100644 --- a/spec/provider/dummy_spec.rb +++ b/spec/provider/dummy_spec.rb @@ -4,7 +4,7 @@ class SessionController < TestController end -describe SwitchUser::Provider::Session do +RSpec.describe SwitchUser::Provider::Session do let(:controller) { SessionController.new } let(:provider) { SwitchUser::Provider::Dummy.new(controller) } diff --git a/spec/provider/restful_authentication_spec.rb b/spec/provider/restful_authentication_spec.rb index c433eef..91119df 100644 --- a/spec/provider/restful_authentication_spec.rb +++ b/spec/provider/restful_authentication_spec.rb @@ -9,7 +9,7 @@ def logout_killing_session! end end -describe SwitchUser::Provider::RestfulAuthentication do +RSpec.describe SwitchUser::Provider::RestfulAuthentication do let(:controller) { RestfulAuthenticationController.new } let(:provider) { SwitchUser::Provider::RestfulAuthentication.new(controller) } diff --git a/spec/provider/session_spec.rb b/spec/provider/session_spec.rb index b545ce5..9af32e8 100644 --- a/spec/provider/session_spec.rb +++ b/spec/provider/session_spec.rb @@ -7,7 +7,7 @@ def current_user end end -describe SwitchUser::Provider::Session do +RSpec.describe SwitchUser::Provider::Session do before do SwitchUser.session_key = :uid end diff --git a/spec/provider/sorcery_spec.rb b/spec/provider/sorcery_spec.rb index c43a565..3e3512c 100644 --- a/spec/provider/sorcery_spec.rb +++ b/spec/provider/sorcery_spec.rb @@ -16,7 +16,7 @@ def current_user end end -describe SwitchUser::Provider::Sorcery do +RSpec.describe SwitchUser::Provider::Sorcery do let(:controller) { SorceryController.new } let(:provider) { SwitchUser::Provider::Sorcery.new(controller) } diff --git a/spec/provider_spec.rb b/spec/provider_spec.rb index 2367ff3..97100fc 100644 --- a/spec/provider_spec.rb +++ b/spec/provider_spec.rb @@ -1,10 +1,10 @@ require 'spec_helper' module SwitchUser - describe Provider do + RSpec.describe Provider do it "initializes the provider" do SwitchUser.provider = :dummy - Provider.init(double(:controller)).should be_a(Provider::Dummy) + expect(Provider.init(double(:controller))).to be_a(Provider::Dummy) end end end diff --git a/spec/rspec/feature_helpers_spec.rb b/spec/rspec/feature_helpers_spec.rb new file mode 100644 index 0000000..72c4edf --- /dev/null +++ b/spec/rspec/feature_helpers_spec.rb @@ -0,0 +1,127 @@ +require 'spec_helper' + +require 'capybara/rspec' +require 'capybara/rails' +Capybara.app = MyApp::Application + +require 'switch_user/rspec' + +RSpec.feature "SwitchUser::RSpecFeatureHelpers", type: :feature do + background do + @user = User.create!(email: "foo@bar.com", admin: true) + @client = Client.create!(email: "foo@bar.com") + end + + before(:example) do + allow(SwitchUser).to receive(:controller_guard).and_return(->(current_user, request) { true }) + + allow(SwitchUser).to receive(:available_users).and_return({user: -> { User.all }}) + + allow(SwitchUser).to receive(:available_users_identifiers).and_return({user: :id}) + + allow(SwitchUser).to receive(:available_users_names).and_return({user: :email}) + end + + scenario "when controller_guard return false" do + allow(SwitchUser).to receive(:controller_guard).and_return(->(current_user, request) { false }) + + expect do + switch_user @user + end.not_to raise_error + end + + scenario "when controller_guard return false and controller call original available?" do + allow(SwitchUser).to receive(:controller_guard).and_return(->(current_user, request) { false }) + + allow_any_instance_of(SwitchUserController).to receive(:available?).and_call_original + + expect do + switch_user @user + end.to raise_error ActionController::RoutingError, /Do not try to hack us/ + end + + scenario "arg is @user, available_users is default, and available_users_identifiers is default" do + expect do + switch_user @user + end.not_to raise_error + end + + scenario "arg is @user, available_users is default, and available_users_identifiers is {user: id}" do + allow(SwitchUser).to receive(:available_users_identifiers).and_return({user: :id}) + + expect do + switch_user @user + end.not_to raise_error + end + + scenario "arg is @user, available_users is default, and available_users_identifiers is {:client => :id}" do + allow(SwitchUser).to receive(:available_users_identifiers).and_return({client: :id}) + allow(SwitchUser).to receive(:available_users_names).and_return({client: :email}) + + expect do + switch_user @user + end.to raise_error SwitchUser::InvalidScope, /config.available_users_identifiers/ + end + + scenario "arg is @client, available_users is default, and available_users_identifiers is default" do + expect do + switch_user @client + end.to raise_error SwitchUser::InvalidScope, /config.available_users/ + end + + scenario "arg is @client, available_users is {:user => lambda { User.all }, :client => lambda {Client.all}}, and available_users_identifiers is default" do + allow(SwitchUser).to receive(:available_users).and_return({user: -> { User.all }, client: -> { Client.all }}) + + expect do + switch_user @client + end.to raise_error SwitchUser::InvalidScope, /config.available_users_identifiers/ + end + + scenario "arg is @client, available_users is {:user => lambda { User.all }, :client => lambda {Client.all}}, and available_users_identifiers is {:user => id, :client => id}" do + allow(SwitchUser).to receive(:available_users).and_return({user: -> { User.all }, client: -> { Client.all }}) + + allow(SwitchUser).to receive(:available_users_identifiers).and_return({user: :id, client: :id}) + allow(SwitchUser).to receive(:available_users_names).and_return({user: :email, client: :email}) + + expect do + switch_user @client + end.not_to raise_error + end + + scenario "args is :user and @user.id, available_users is default, and available_users_identifiers is default" do + expect do + switch_user :user, @user.id + end.not_to raise_error + end + + scenario "arg is :client and @client.id, available_users is default, and available_users_identifiers is default" do + expect do + switch_user :client, @client.id + end.to raise_error SwitchUser::InvalidScope, /config.available_users/ + end + + scenario "args is :user, available_users is default, and available_users_identifiers is default" do + expect do + switch_user :user + end.to raise_error SwitchUser::RSpecFeatureHelpers::InvalidArgument, /user_id is empty/ + end + + scenario "args is :user and nil, available_users is default, and available_users_identifiers is default" do + expect do + switch_user :user, nil + end.to raise_error SwitchUser::RSpecFeatureHelpers::InvalidArgument, /user_id is empty/ + end + + scenario "args is :user and '', available_users is default, and available_users_identifiers is default" do + expect do + switch_user :user, '' + end.to raise_error SwitchUser::RSpecFeatureHelpers::InvalidArgument, /user_id is empty/ + end + + scenario "args is :user and 0, available_users is default, and available_users_identifiers is default" do + expect do + switch_user :user, 0 + end.not_to raise_error + end + +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ce15ee2..908f817 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,9 +7,10 @@ require 'awesome_print' RSpec.configure do |config| - config.filter_run :focus => true + config.filter_run focus: true config.run_all_when_everything_filtered = true config.use_transactional_fixtures = true + config.expose_dsl_globally = false end class TestController diff --git a/spec/support/application.rb b/spec/support/application.rb index 523a1d2..b59c382 100644 --- a/spec/support/application.rb +++ b/spec/support/application.rb @@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base def require_user - current_user || redirect_to("/tests/open") + current_user || redirect_to("/dummy/open") end def current_user @@ -16,27 +16,29 @@ def login user = User.find(params[:id]) session[SwitchUser.session_key] = user.id - redirect_to("/tests/protected") + redirect_to("/dummy/protected") end def logout session[SwitchUser.session_key] = nil + + redirect_to("/dummy/open") end end class DummyController < ApplicationController - before_filter :require_user, :only => :protected + before_action :require_user, only: :protected def authenticated - render :text => current_user.inspect + render text: current_user.inspect end def open - render :text => view_context.switch_user_select + render text: view_context.switch_user_select end def protected - render :text => view_context.switch_user_select + render text: view_context.switch_user_select end end @@ -46,17 +48,20 @@ class Application < Rails::Application config.secret_key_base = "abc123" config.eager_load = true config.secret_token = '153572e559247c7aedd1bca5a246874d' + + # should set it + config.action_dispatch.show_exceptions = false end end Rails.application.initialize! Rails.application.routes.draw do - get 'dummy/protected', :to => "dummy#protected" - get 'dummy/open', :to => "dummy#open" - post 'login', :to => "dummy#login" - get 'logout', :to => "dummy#logout" - get 'authenticated', :to => "dummy#authenticated" - get :switch_user, :to => 'switch_user#set_current_user' - get 'switch_user/remember_user', :to => 'switch_user#remember_user' + get 'dummy/protected', to: "dummy#protected" + get 'dummy/open', to: "dummy#open" + post 'login', to: "dummy#login" + get 'logout', to: "dummy#logout" + get 'authenticated', to: "dummy#authenticated" + get :switch_user, to: 'switch_user#set_current_user' + get 'switch_user/remember_user', to: 'switch_user#remember_user' end connection = ActiveRecord::Base.connection @@ -67,3 +72,10 @@ class Application < Rails::Application class User < ActiveRecord::Base end + +connection.create_table :clients do |t| + t.column :email, :string +end + +class Client < ActiveRecord::Base +end diff --git a/spec/support/provider.rb b/spec/support/provider.rb index 6161c39..ff10a7c 100644 --- a/spec/support/provider.rb +++ b/spec/support/provider.rb @@ -1,11 +1,11 @@ -shared_examples_for "a provider" do +RSpec.shared_examples_for "a provider" do let(:user) { User.create! } let(:other_user) { User.create! } it "can log a user in" do provider.login(user) - provider.current_user.should == user + expect(provider.current_user).to eq user end it "can log a user out" do @@ -13,21 +13,21 @@ provider.logout - provider.current_user.should == nil + expect(provider.current_user).to eq nil end it "responds to login_exclusive" do - provider.should respond_to(:login_exclusive) + expect(provider).to respond_to(:login_exclusive) end it "responds to login_exclusive" do - provider.should respond_to(:login_inclusive) + expect(provider).to respond_to(:login_inclusive) end it "knows if there are any users logged in" do - provider.login(user) + provider.login(user, :user) - provider.current_users_without_scope.should == [user] + expect(provider.current_users_without_scope).to eq [user] end it "can lock the original user, allowing us to change current_user" do @@ -35,17 +35,17 @@ provider.remember_current_user(true) provider.login_exclusive(other_user, scope: "user") - provider.original_user.should == user - provider.current_user.should == other_user + expect(provider.original_user).to eq user + expect(provider.current_user(:user)).to eq other_user end it "can forget the original_user" do provider.login(user) provider.remember_current_user(true) - provider.original_user.should == user + expect(provider.original_user).to eq user provider.remember_current_user(false) - provider.original_user.should == nil + expect(provider.original_user).to eq nil end end diff --git a/spec/switch_user/data_source_spec.rb b/spec/switch_user/data_source_spec.rb index 6bd6738..a2efea4 100644 --- a/spec/switch_user/data_source_spec.rb +++ b/spec/switch_user/data_source_spec.rb @@ -1,49 +1,87 @@ require 'switch_user/data_source' module SwitchUser - describe DataSource do - it "can load users" do - loader = lambda { [ double, double] } - source = DataSource.new(loader, :user, :id, :email) + RSpec.describe DataSources do + describe '#all' do + it 'aggregates multiple data_sources' do + user = double(:user) + s1 = double(:s1, all: [user]) + source = DataSources.new([s1, s1]) - source.users.should have(2).records + expect(source.all).to eq [user, user] + end + end + + describe '#find_scope_id' do + it 'can find a corresponding record across data sources' do + user = double(:user) + s1 = double(:s1, find_scope_id: nil) + s2 = double(:s2, find_scope_id: user) + source = DataSources.new([s1, s2]) + + expect(source.find_scope_id("user_10")).to eq user + end end end - describe DataSources do - it "aggregates multiple data_sources" do - user = double(:user) - s1 = double(:s1, :users => [user]) - source = DataSources.new([s1,s1]) + RSpec.describe DataSource do + skip # it's tested in integration test, need to find a good way to test it here. + end - source.users.should == [user, user] + RSpec.describe GuestDataSource do + let(:source) { GuestDataSource.new } + + describe '#all' do + it 'gets a GuestRecord' do + expect(source.all.size).to eq 1 + expect(source.all.first).to be_instance_of GuestRecord + end end - describe "#find_source_id" do - it "can find a corresponding record across data sources" do - user = double(:user, :scope_id => "user_10") - s1 = double(:s1, :users => []) - s2 = double(:s1, :users => [user]) - source = DataSources.new([s1,s2]) + describe '#find_scope_id' do + it 'gets nil' do + expect(source.find_scope_id('')).to be_nil + end + end + end - source.find_scope_id("user_10").should == user + RSpec.describe Record do + let(:source) { DataSource.new({}, :user, :id, :email) } + let(:user) { double(:user, id: '1', email: 'flyerhzm@gmail.com') } + let(:record) { Record.new(user, source) } + + describe '#label' do + it 'gets user email' do + expect(record.label).to eq 'flyerhzm@gmail.com' + end + end + + describe '#scope' do + it 'gets user' do + expect(record.scope).to eq :user + end + end + + describe '#scope_id' do + it 'gets scope and id' do + expect(record.scope_id).to eq 'user_1' end end end - describe Record do - it "can be compared to a identifier string" do - id1 = "user_100" - id2 = "user_101" - id3 = "staff_100" - user = double(:user, :id => 100, :email => "test@example.com") - source = DataSource.new(nil, :user, :id, :email) + RSpec.describe GuestRecord do + let(:record) { GuestRecord.new } - record = Record.new(user, source) + describe '#label' do + it 'gets Guest' do + expect(record.label).to eq 'Guest' + end + end - record.should be_equivalent(id1) - record.should_not be_equivalent(id2) - record.should_not be_equivalent(id3) + describe '#scope_id' do + it 'gets nil' do + expect(record.scope_id).to be_nil + end end end end diff --git a/spec/switch_user/lambda_guard_spec.rb b/spec/switch_user/lambda_guard_spec.rb index b13f8b4..1effbc3 100644 --- a/spec/switch_user/lambda_guard_spec.rb +++ b/spec/switch_user/lambda_guard_spec.rb @@ -1,18 +1,18 @@ require 'spec_helper' module SwitchUser - describe LambdaGuard do + RSpec.describe LambdaGuard do describe "#controller_available?" do it "calls the controller_guard proc" do controller = double.as_null_object provider = double.as_null_object guard = SwitchUser::LambdaGuard.new(controller, provider) - SwitchUser.controller_guard = lambda {|a| a } - guard.should be_controller_available + SwitchUser.controller_guard = ->(a) { a } + expect(guard).to be_controller_available - SwitchUser.controller_guard = lambda {|a| !a } - guard.should_not be_controller_available + SwitchUser.controller_guard = ->(a) { !a } + expect(guard).not_to be_controller_available end end end diff --git a/spec/switch_user/user_loader_spec.rb b/spec/switch_user/user_loader_spec.rb index 9f0d36c..5502b4d 100644 --- a/spec/switch_user/user_loader_spec.rb +++ b/spec/switch_user/user_loader_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'switch_user/user_loader' -describe SwitchUser::UserLoader do +RSpec.describe SwitchUser::UserLoader do let(:user) { double(:user) } let(:user_result) { [user] } @@ -11,18 +11,18 @@ describe ".user" do before do - SwitchUser.available_users_identifiers = {:user => :id} - allow(User).to receive(:where).with(:id => "1").and_return(user_result) + SwitchUser.available_users_identifiers = {user: :id} + allow(User).to receive(:where).with(id: "1").and_return(user_result) end it "can be loaded from a scope and identifier" do loaded_user = SwitchUser::UserLoader.prepare("user","1").user - loaded_user.should == user + expect(loaded_user).to eq user end it "can be loaded by a passing an unprocessed scope identifier" do - loaded_user = SwitchUser::UserLoader.prepare(:scope_identifier => "user_1").user + loaded_user = SwitchUser::UserLoader.prepare(scope_identifier: "user_1").user - loaded_user.should == user + expect(loaded_user).to eq user end it "raises an error for an invalid scope" do expect { @@ -32,25 +32,25 @@ end it "returns a user" do - allow(User).to receive(:where).with(:id => 1).and_return(user_result) + allow(User).to receive(:where).with(id: 1).and_return(user_result) loader = SwitchUser::UserLoader.new("user", 1) - loader.user.should == user + expect(loader.user).to eq user end it "returns nil if no user is found" do loader = SwitchUser::UserLoader.new("user", 3) - User.find_by_id(3).should be_nil - loader.user.should == nil + expect(User.find_by_id(3)).to be_nil + expect(loader.user).to eq nil end it "loads a user with an alternate identifier column" do - allow(User).to receive(:where).with(:email => 2).and_return(user_result) - SwitchUser.available_users_identifiers = {:user => :email} + allow(User).to receive(:where).with(email: 2).and_return(user_result) + SwitchUser.available_users_identifiers = {user: :email} loader = SwitchUser::UserLoader.new("user", 2) - loader.user.should == user + expect(loader.user).to eq user end end diff --git a/spec/switch_user/user_set_spec.rb b/spec/switch_user/user_set_spec.rb index c9cc177..2cbef41 100644 --- a/spec/switch_user/user_set_spec.rb +++ b/spec/switch_user/user_set_spec.rb @@ -2,33 +2,33 @@ require 'switch_user/user_set' module SwitchUser - describe UserSet do - let!(:user) { User.create(:email => "test@example.com") } - let(:set) { UserSet.new(:user, :id, :email, lambda { User.all }) } + RSpec.describe UserSet do + let!(:user) { User.create(email: "test@example.com") } + let(:set) { UserSet.new(:user, :id, :email, -> { User.all }) } after { User.delete_all } it "returns an object that knows it's scope, id and label" do found_user = set[user.id] - found_user.id.should == user.id - found_user.scope.should == :user - found_user.label.should == "test@example.com" + expect(found_user.id).to eq user.id + expect(found_user.scope).to eq :user + expect(found_user.label).to eq "test@example.com" end it "returns all available users for a scope" do - set.users.should == [user] + expect(set.users).to eq [user] end it "chains the where on to the provided scope" do - set = UserSet.new(:user, :id, :email, lambda { User.all }) - set.find_user(user.id).label.should == user.email + set = UserSet.new(:user, :id, :email, -> { User.all }) + expect(set.find_user(user.id).label).to eq user.email end end - describe UserSet::Record do + RSpec.describe UserSet::Record do it "correctly configures the record using the set" do - user = double(:user, :id => 100, :email => "test@example.com") - set = double(:set, :identifier => :id, :label => :email, :scope => :user) + user = double(:user, id: 100, email: "test@example.com") + set = double(:set, identifier: :id, label: :email, scope: :user) record = UserSet::Record.build(user, set) - record.id.should == 100 - record.label.should == "test@example.com" - record.scope.should == :user + expect(record.id).to eq 100 + expect(record.label).to eq "test@example.com" + expect(record.scope).to eq :user end end end diff --git a/spec/switch_user_spec.rb b/spec/switch_user_spec.rb index be42491..c7b68e7 100644 --- a/spec/switch_user_spec.rb +++ b/spec/switch_user_spec.rb @@ -1,10 +1,10 @@ require 'spec_helper' require 'switch_user' -describe SwitchUser do +RSpec.describe SwitchUser do describe "#available_scopes" do it "returns a list of available scopes" do - SwitchUser.available_scopes.should == [:user] + expect(SwitchUser.available_scopes).to eq [:user] end end @@ -12,7 +12,7 @@ it "sets the provider" do # ensure we aren't breaking existing functionality SwitchUser.provider = :sorcery - SwitchUser.provider.should == :sorcery + expect(SwitchUser.provider).to eq :sorcery end end end diff --git a/switch_user.gemspec b/switch_user.gemspec index e453285..23cbe01 100644 --- a/switch_user.gemspec +++ b/switch_user.gemspec @@ -18,12 +18,14 @@ Gem::Specification.new do |s| s.add_development_dependency "bundler", ">= 1.0.0" s.add_development_dependency "actionpack" s.add_development_dependency "railties" - s.add_development_dependency "rspec-rails", "~> 2.14.0" + s.add_development_dependency "rspec" + s.add_development_dependency "rspec-rails" s.add_development_dependency "tzinfo" s.add_development_dependency "sqlite3" s.add_development_dependency "activerecord" s.add_development_dependency "awesome_print" s.add_development_dependency "pry" + s.add_development_dependency "capybara" s.files = `git ls-files`.split("\n") s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact