设计用户注册和登录。
使用rails控制台设置管理员(将admin boolean设置为true)。
Rspec和FactoryGirl。
不幸的是,我在编写测试之前编写了我的应用程序(最好的课程是通过艰难的方式学习的)。我现在正在学习rspec并为应用程序编写测试套件。
我为管理员和非管理员设置了控制器权限和查看权限,这些权限在实践中有效(我通过全面的浏览器手动测试了解到这一点)。
在这种情况下,我在标题中有一个“管理员”链接,当用户登录并且也是管理员时会显示该链接。
我的StaticPagesController也有一个有效的before_action设置,所以没有人可以访问管理页面,除非他们已登录并且也是管理员。
我为此编写了一些测试,并且认为我对它进行了排序,直到我注意到,当对包含这些测试的特定/功能规范文件进行更改时,guard仅运行那些测试并传递它们。但是,当我运行整个测试套件时,那些相同的测试失败了。我对这完全感到困惑。
我认为它可能与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 => 'testuser@email.com')
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
在运行完整测试套件时,“如果用户不是管理员”上下文中的测试全部失败。他们都失败了同样的错误:
Failure/Error: expect(current_path).to eq(root_path)
expected: "/"
got: "/admin"
(compared using ==)
对我而言,这意味着管理页面可以访问,而不应该访问。在我的浏览器中,无法看到管理页面链接,也无法通过手动输入网址来访问该页面,除非用户已登录并且是管理员。
在运行完整测试套件时,“如果用户是管理员”上下文中的测试都是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.erb partial的相关部分:
<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 :(得分:0)
您的测试失败的原因是您在重定向完成之前检查current_path。基本上你正在调用visit(xxx),它将current_path设置为xxx,然后立即读回xxx,同时服务器将重定向返回给/然后浏览器将current_path更改为/。只要您使用Capybara 2.5+,就应该使用has_current_path匹配器,它将重试一段时间,从而为重定向时间提供处理
expect(page).to have_current_path(root_path)