2015-05-16 3 views
0

Разработчик для регистрации и входа пользователя.Проблема с Capybara и администратором Разрешения пользователя (и разработка)

Администраторы устанавливаются с помощью консоли рельсов (установка логического значения admin в true).

Rspec и FactoryGirl.

К сожалению, перед тем, как писать тесты, я написал свое приложение (лучшие уроки усложняются). Теперь я изучаю rspec и пишу тестовый набор для приложения.

У меня есть разрешения на доступ к контроллерам и разрешения на просмотр, для администраторов и не-админов, которые работают на практике (я знаю это путем тщательного ручного тестирования браузера).

В этом случае у меня есть ссылка «Admin» в заголовке, которая отображается при входе пользователя в систему и также является администратором.

My StaticPagesController также имеет эффективную настройку before_action, поэтому никто не может получить доступ к странице администратора, если они не вошли в систему и не являются администраторами.

Я написал несколько тестов для этого и подумал, что я его отсортировал, пока не заметил, что при внесении изменений в спецификационный файл спецификаций/функций, содержащий эти тесты, защита запускает только те тесты и передает их. Однако, когда я запускаю весь набор тестов, те же тесты терпят неудачу. Я полностью смутился этим.

Я думаю, что это может иметь какое-то отношение к Devise, но я просто не знаю.

спецификации/особенности/user_and_role_spec.rb

require 'rails_helper' 

def manually_create_user 
    visit new_user_registration_path 
    fill_in('user_first_name', :with => 'Test') 
    fill_in('user_last_name', :with => 'User') 
    fill_in('user_email', :with => '[email protected]') 
    fill_in('user_password', :with => 'testuser') 
    click_button('Sign up') 
end 

def create_user_and_login_as(type) 
    user = FactoryGirl.create(type) 
    visit(new_user_session_path) 
    fill_in('user_email', :with => user.email) 
    fill_in('user_password', :with => user.password) 
    click_button('Log in') 
end 


describe 'with users and roles' do 

    context "if user is not an admin" do 

     it "does not allow any user to visit the admin page if not logged-in" do 
      visit(admin_path) 
      expect(current_path).to eq(root_path) 
     end 

     it "does not allow a new user to visit the admin page" do 
      manually_create_user 
      visit(admin_path) 
      expect(current_path).to eq(root_path) 
     end 

     it "does not allow a student to visit the admin page" do 
      create_user_and_login_as(:student) 
      visit admin_path 
      expect(current_path).to eq(root_path) 
     end 

     it "does not allow a teacher to visit the admin page" do 
      create_user_and_login_as(:teacher) 
      visit admin_path 
      expect(current_path).to eq(root_path) 
     end 

    end 


    context "if user is an admin" do 

     it "allows an admin user to visit the admin page" do 
      create_user_and_login_as(:admin_user) 
      click_link 'Admin' 
      expect(current_path).to eq(admin_path) 
     end 

     it "allows a teacher_admin to visit the admin page" do 
      create_user_and_login_as(:teacher_admin_user) 
      click_link 'Admin' 
      expect(current_path).to eq(admin_path) 
     end 

    end 

end 

Испытания в контексте «если пользователь не является администратором» все FAIL при выполнении полного набора тестов. Они не в состоянии с той же ошибкой:

Failure/Error: expect(current_path).to eq(root_path) 

     expected: "/" 
      got: "/admin" 

     (compared using ==) 

Который, мне, значит страница администратора была доступна, когда оно не должно быть. В моем браузере ссылка на страницу администратора не может быть видна, и к странице не может быть доступа, вручную набрав URL-адрес, если пользователь не зарегистрирован и не является администратором.

Тестирование в контексте «если пользователь является администратором» все PASS при запуске полного набора тестов.

спецификации/фабрики/users.rb:

require 'faker' 

FactoryGirl.define do 
    factory :user do |f| 
     f.first_name { Faker::Name.first_name } 
     f.last_name  { Faker::Name.last_name } 
     f.email   { Faker::Internet.email } 
     f.password  { Faker::Internet.password(8) } 
     f.admin   false 

     trait :student do 
      type "Student" 
     end 

     trait :teacher do 
      type "Teacher" 
     end 

     trait :admin do 
      admin true 
     end 

     factory :admin_user,   traits: [:admin] 
     factory :student,    traits: [:student] 
     factory :teacher,    traits: [:teacher] 
     factory :teacher_admin_user, traits: [:teacher, :admin] 

    end 
end 

static_pages_controller.rb:

class StaticPagesController < ApplicationController 
    before_action :admin?, only: [:admin] 

    def home 
    @testimonials = Testimonial.all 
    end 

    def admin 
    @groups = Group.all 

    @users = User.all 

    @students = Student.all 

    @teachers = Teacher.all 
    end 

    private 

    def admin? 
    unless signed_in? and current_user.admin == true 
     redirect_to root_path, notice: "You must be a signed-in admin to view this page" 
    end 
    end 

end 

static_pages_helper.rb:

module StaticPagesHelper 

    def allowed_to_see_admin_link? 
     signed_in? && current_user.admin 
    end 

end 

модели/user.rb:

class User < ActiveRecord::Base 
    # Include default devise modules. Others available are: 
    # :confirmable, :lockable, :timeoutable and :omniauthable 
    devise :database_authenticatable, :registerable, 
     :recoverable, :rememberable, :trackable, :validatable 

    validates :first_name, presence: true 
    validates :last_name, presence: true 
    validates :admin, inclusion: { in: [true, false] } 

    scope :newest_first, -> { order("created_at DESC") } 
    scope :order_by_first_name, -> { order("first_name") } 

    def full_name 
    "#{first_name} #{last_name}" 
    end 

    def unassigned? 
    type != "Student" and type != "Teacher" 
    end 

    def can_view_materials? 
    admin || type == "Teacher" || type == "Student" && groups.any? # So only current students can view the Materials page. 
    end 

    def testimonial_owner?(testimonial) 
    id == testimonial.student_id 
    end 

end 

Релевантная часть _header.html.Еврорадио: частичный:

<ul class="nav navbar-nav navbar-right"> 
     <% if allowed_to_see_admin_link? %> 
      <li><%= link_to "Admin", admin_path %></li> 
     <% end %> 
     </ul> 

Gemfile:

gem 'rails', '4.2.0' 
gem 'bootstrap-sass', '~> 3.3.3' 
gem 'sass-rails', '~> 5.0' 
gem 'uglifier', '>= 1.3.0' 
gem 'coffee-rails', '~> 4.1.0' 
gem 'jquery-rails' 
gem 'turbolinks' 
gem 'jbuilder', '~> 2.0' 
gem 'sdoc', '~> 0.4.0', group: :doc 
gem 'devise' 

group :development, :test do 
    gem 'sqlite3' 
    gem 'byebug' 
    gem 'web-console', '~> 2.0' 
    gem 'spring' 
    gem 'better_errors' 
    gem 'binding_of_caller' 
    gem 'rspec-rails' 
    gem 'guard-rspec', require: false 
    gem 'factory_girl_rails' 
end 

group :test do 
    gem 'faker' 
    gem 'capybara' 
    gem 'launchy' 
    gem 'database_cleaner' 
end 

group :production do 
    gem 'pg' 
    gem 'rails_12factor' 
end 

пользователей в схеме:

create_table "users", force: :cascade do |t| 
    t.string "email",     default: "", null: false 
    t.string "encrypted_password",  default: "", null: false 
    t.string "reset_password_token" 
    t.datetime "reset_password_sent_at" 
    t.datetime "remember_created_at" 
    t.integer "sign_in_count",   default: 0,  null: false 
    t.datetime "current_sign_in_at" 
    t.datetime "last_sign_in_at" 
    t.string "current_sign_in_ip" 
    t.string "last_sign_in_ip" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.boolean "admin",     default: false 
    t.string "type" 
    t.string "first_name" 
    t.string "last_name" 
    end 

routes.rb:

resources :materials 

    root 'static_pages#home' 

    devise_for :users, :controllers => { registrations: 'registrations' } 

    get 'admin' => 'static_pages#admin' 

    resources :groups 
    resources :users 
    resources :students 
    resources :teachers 
    resources :testimonials 
    post 'assign_to_group' => 'students#assign_to_group' # Could have been 'patch', but default in the controller method is 'post', so I left the method as default and changed this route to 'post'. Doesn't NEED to be patch. 
    post 'remove_from_group' => 'students#remove_from_group' 
    post 'unassign_teacher' => 'groups#unassign_teacher' 
    post 'assign_as_student' => 'teachers#assign_as_student' 
    post 'assign_as_teacher' => 'students#assign_as_teacher' 
    post 'add_student' => 'groups#add_student' 
    post 'remove_student_from_group' => 'groups#remove_student_from_group' 
+0

В вашей спецификации - попробуйте проверить что-то, что пользователь на самом деле будет/не видеть на странице администратора, например 'ожидать (страница) .not_to has_content (" Welcome Mr Admin ")' или что-то на самом деле на странице входа в систему - если вы видите, что тогда да, вам нужно будет выяснить, почему люди автоматически вошли в админ. В противном случае, возможно, они находятся на странице входа в админ? –

+0

Кроме того, точки стиля: используйте '&&' и '||' вместо 'and' и' or' (читайте, почему здесь: http://devblog.avdi.org/2010/08/02/using-and-and -or-in-ruby /) Во-вторых: 'current_user.admin == true' это довольно опасно ... что, если вы случайно забыли один из' = '- это трудная ошибка, и вы на самом деле не будете код для отказа ... просто чтобы все пользователи могли видеть страницу администратора. Это хорошая привычка * всегда * делать это вместо этого: 'true == current_user.admin' Это будет громко, если вы случайно используете' = 'вместо этого –

ответ

0

Причина тесты терпят неудачу в том, что вы проверяете текущий_path перед перенаправлением закончил. В основном вы вызываете посещение (xxx), которое устанавливает текущий_path в xxx, а затем сразу читает xxx, а сервер возвращает перенаправление обратно в /, а затем браузер меняет current_path на /. До тех пор, пока вы используете Capybara 2.5+ вы должны использовать have_current_path Искатель, который повторит немного, тем самым давая время редиректа для обработки

expect(page).to have_current_path(root_path) 
Смежные вопросы