Merge pull request #67 from Retrospring/use-real-roles
Use Rolify for admin and moderator roles
This commit is contained in:
commit
da25be15b1
|
@ -35,3 +35,5 @@ desktop.ini
|
||||||
|
|
||||||
# ignore exports
|
# ignore exports
|
||||||
/public/export
|
/public/export
|
||||||
|
|
||||||
|
/spec/examples.txt
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
AllCops:
|
AllCops:
|
||||||
RunRailsCops: true
|
Rails:
|
||||||
|
Enabled: true
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'vendor/**/*'
|
- 'vendor/**/*'
|
||||||
- 'db/schema.rb'
|
- 'db/schema.rb'
|
||||||
|
@ -7,7 +8,7 @@ AllCops:
|
||||||
Metrics/ClassLength:
|
Metrics/ClassLength:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Metrics/LineLength:
|
Layout/LineLength:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Metrics/MethodLength:
|
Metrics/MethodLength:
|
||||||
|
@ -16,9 +17,6 @@ Metrics/MethodLength:
|
||||||
Metrics/ModuleLength:
|
Metrics/ModuleLength:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Style/BracesAroundHashParameters:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
Style/ClassAndModuleChildren:
|
Style/ClassAndModuleChildren:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -42,6 +42,8 @@ gem 'tiny-color-rails'
|
||||||
gem 'jquery-minicolors-rails'
|
gem 'jquery-minicolors-rails'
|
||||||
gem 'colorize'
|
gem 'colorize'
|
||||||
|
|
||||||
|
gem "rolify", "~> 5.2"
|
||||||
|
|
||||||
source "https://rails-assets.org" do
|
source "https://rails-assets.org" do
|
||||||
gem 'rails-assets-growl'
|
gem 'rails-assets-growl'
|
||||||
gem 'rails-assets-jquery', '~> 2.2.0'
|
gem 'rails-assets-jquery', '~> 2.2.0'
|
||||||
|
|
|
@ -382,6 +382,7 @@ GEM
|
||||||
responders (3.0.0)
|
responders (3.0.0)
|
||||||
actionpack (>= 5.0)
|
actionpack (>= 5.0)
|
||||||
railties (>= 5.0)
|
railties (>= 5.0)
|
||||||
|
rolify (5.2.0)
|
||||||
rspec-core (3.9.1)
|
rspec-core (3.9.1)
|
||||||
rspec-support (~> 3.9.1)
|
rspec-support (~> 3.9.1)
|
||||||
rspec-expectations (3.9.1)
|
rspec-expectations (3.9.1)
|
||||||
|
@ -554,6 +555,7 @@ DEPENDENCIES
|
||||||
rake
|
rake
|
||||||
redcarpet
|
redcarpet
|
||||||
redis
|
redis
|
||||||
|
rolify (~> 5.2)
|
||||||
rspec-rails (~> 3.9)
|
rspec-rails (~> 3.9)
|
||||||
ruby-progressbar
|
ruby-progressbar
|
||||||
sanitize
|
sanitize
|
||||||
|
|
52
Rakefile
52
Rakefile
|
@ -105,44 +105,48 @@ namespace :justask do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Gives admin status to an user."
|
desc "Gives admin status to a user."
|
||||||
task :admin, [:screen_name] => :environment do |t, args|
|
task :admin, [:screen_name] => :environment do |t, args|
|
||||||
fail "screen name required" if args[:screen_name].nil?
|
abort "screen name required" if args[:screen_name].nil?
|
||||||
|
|
||||||
user = User.find_by_screen_name(args[:screen_name])
|
user = User.find_by_screen_name(args[:screen_name])
|
||||||
fail "user #{args[:screen_name]} not found" if user.nil?
|
abort "user #{args[:screen_name]} not found" if user.nil?
|
||||||
user.admin = true
|
|
||||||
user.save!
|
user.add_role :administrator
|
||||||
puts "#{user.screen_name} is now an admin."
|
puts "#{user.screen_name} is now an administrator."
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Removes admin status from an user."
|
desc "Removes admin status from a user."
|
||||||
task :deadmin, [:screen_name] => :environment do |t, args|
|
task :deadmin, [:screen_name] => :environment do |t, args|
|
||||||
fail "screen name required" if args[:screen_name].nil?
|
abort "screen name required" if args[:screen_name].nil?
|
||||||
|
|
||||||
user = User.find_by_screen_name(args[:screen_name])
|
user = User.find_by_screen_name(args[:screen_name])
|
||||||
fail "user #{args[:screen_name]} not found" if user.nil?
|
abort "user #{args[:screen_name]} not found" if user.nil?
|
||||||
user.admin = false
|
|
||||||
user.save!
|
user.remove_role :administrator
|
||||||
puts "#{user.screen_name} is no longer an admin."
|
puts "#{user.screen_name} is no longer an administrator."
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Gives moderator status to an user."
|
desc "Gives moderator status to a user."
|
||||||
task :mod, [:screen_name] => :environment do |t, args|
|
task :mod, [:screen_name] => :environment do |t, args|
|
||||||
fail "screen name required" if args[:screen_name].nil?
|
abort "screen name required" if args[:screen_name].nil?
|
||||||
|
|
||||||
user = User.find_by_screen_name(args[:screen_name])
|
user = User.find_by_screen_name(args[:screen_name])
|
||||||
fail "user #{args[:screen_name]} not found" if user.nil?
|
abort "user #{args[:screen_name]} not found" if user.nil?
|
||||||
user.moderator = true
|
|
||||||
user.save!
|
user.add_role :moderator
|
||||||
puts "#{user.screen_name} is now an moderator."
|
puts "#{user.screen_name} is now a moderator."
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Removes moderator status from an user."
|
desc "Removes moderator status from a user."
|
||||||
task :demod, [:screen_name] => :environment do |t, args|
|
task :demod, [:screen_name] => :environment do |t, args|
|
||||||
fail "screen name required" if args[:screen_name].nil?
|
abort "screen name required" if args[:screen_name].nil?
|
||||||
|
|
||||||
user = User.find_by_screen_name(args[:screen_name])
|
user = User.find_by_screen_name(args[:screen_name])
|
||||||
fail "user #{args[:screen_name]} not found" if user.nil?
|
abort "user #{args[:screen_name]} not found" if user.nil?
|
||||||
user.moderator = false
|
|
||||||
user.save!
|
user.remove_role :moderator
|
||||||
puts "#{user.screen_name} is no longer an moderator."
|
puts "#{user.screen_name} is no longer a moderator."
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Hits an user with the banhammer."
|
desc "Hits an user with the banhammer."
|
||||||
|
|
|
@ -125,9 +125,9 @@ class Ajax::ModerationController < ApplicationController
|
||||||
unban = params[:ban] == "0"
|
unban = params[:ban] == "0"
|
||||||
perma = params[:permaban] == "1"
|
perma = params[:permaban] == "1"
|
||||||
|
|
||||||
buntil = DateTime.strptime params[:until], "%m/%d/%Y %I:%M %p" unless unban or perma
|
buntil = DateTime.strptime params[:until], "%m/%d/%Y %I:%M %p" unless unban || perma
|
||||||
|
|
||||||
if not unban and target.admin?
|
if !unban && target.has_role?(:administrator)
|
||||||
@status = :nopriv
|
@status = :nopriv
|
||||||
@message = I18n.t('messages.moderation.ban.nopriv')
|
@message = I18n.t('messages.moderation.ban.nopriv')
|
||||||
@success = false
|
@success = false
|
||||||
|
@ -166,7 +166,7 @@ class Ajax::ModerationController < ApplicationController
|
||||||
@message = I18n.t('messages.moderation.privilege.nope')
|
@message = I18n.t('messages.moderation.privilege.nope')
|
||||||
return unless %w(blogger supporter moderator admin contributor translator).include? params[:type].downcase
|
return unless %w(blogger supporter moderator admin contributor translator).include? params[:type].downcase
|
||||||
|
|
||||||
if %w(supporter moderator admin).include?(params[:type].downcase) and !current_user.admin?
|
if %w(supporter moderator admin).include?(params[:type].downcase) && !current_user.has_role?(:administrator)
|
||||||
@status = :nopriv
|
@status = :nopriv
|
||||||
@message = I18n.t('messages.moderation.privilege.nopriv')
|
@message = I18n.t('messages.moderation.privilege.nopriv')
|
||||||
@success = false
|
@success = false
|
||||||
|
@ -174,7 +174,9 @@ class Ajax::ModerationController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
@checked = status
|
@checked = status
|
||||||
case params[:type].downcase
|
type = params[:type].downcase
|
||||||
|
target_role = {"admin" => "administrator"}.fetch(type, type).to_sym
|
||||||
|
case type
|
||||||
when 'blogger'
|
when 'blogger'
|
||||||
target_user.blogger = status
|
target_user.blogger = status
|
||||||
when 'contributor'
|
when 'contributor'
|
||||||
|
@ -183,10 +185,12 @@ class Ajax::ModerationController < ApplicationController
|
||||||
target_user.translator = status
|
target_user.translator = status
|
||||||
when 'supporter'
|
when 'supporter'
|
||||||
target_user.supporter = status
|
target_user.supporter = status
|
||||||
when 'moderator'
|
when 'moderator', 'admin'
|
||||||
target_user.moderator = status
|
if status
|
||||||
when 'admin'
|
target_user.add_role target_role
|
||||||
target_user.admin = status
|
else
|
||||||
|
target_user.remove_role target_role
|
||||||
|
end
|
||||||
end
|
end
|
||||||
target_user.save!
|
target_user.save!
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Role < ApplicationRecord
|
||||||
|
has_and_belongs_to_many :users, join_table: :users_roles
|
||||||
|
|
||||||
|
belongs_to :resource,
|
||||||
|
polymorphic: true,
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
validates :resource_type,
|
||||||
|
inclusion: { in: Rolify.resource_types },
|
||||||
|
allow_nil: true
|
||||||
|
|
||||||
|
scopify
|
||||||
|
end
|
|
@ -5,6 +5,8 @@ class User < ApplicationRecord
|
||||||
:recoverable, :rememberable, :trackable,
|
:recoverable, :rememberable, :trackable,
|
||||||
:validatable, :confirmable, :authentication_keys => [:login]
|
:validatable, :confirmable, :authentication_keys => [:login]
|
||||||
|
|
||||||
|
rolify
|
||||||
|
|
||||||
# attr_accessor :login
|
# attr_accessor :login
|
||||||
|
|
||||||
has_many :questions, dependent: :destroy
|
has_many :questions, dependent: :destroy
|
||||||
|
@ -183,7 +185,7 @@ class User < ApplicationRecord
|
||||||
|
|
||||||
# @return [Boolean] is the user a moderator?
|
# @return [Boolean] is the user a moderator?
|
||||||
def mod?
|
def mod?
|
||||||
self.moderator? || self.admin?
|
has_role?(:moderator) || has_role?(:administrator)
|
||||||
end
|
end
|
||||||
|
|
||||||
# region stuff used for reporting/moderation
|
# region stuff used for reporting/moderation
|
||||||
|
@ -258,4 +260,10 @@ class User < ApplicationRecord
|
||||||
end
|
end
|
||||||
!self.export_processing
|
!self.export_processing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# %w[admin moderator].each do |m|
|
||||||
|
# define_method(m) { raise "not allowed: #{m}" }
|
||||||
|
# define_method(m+??) { raise "not allowed: #{m}?"}
|
||||||
|
# define_method(m+?=) { |*a| raise "not allowed: #{m}="}
|
||||||
|
# end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
%i.fa.fa-fw.fa-cog
|
%i.fa.fa-fw.fa-cog
|
||||||
= t('views.navigation.settings')
|
= t('views.navigation.settings')
|
||||||
%li.divider
|
%li.divider
|
||||||
- if current_user.admin?
|
- if current_user.has_role?(:administrator)
|
||||||
%li
|
%li
|
||||||
%a{href: rails_admin_path}
|
%a{href: rails_admin_path}
|
||||||
%i.fa.fa-fw.fa-cogs
|
%i.fa.fa-fw.fa-cogs
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
%a{href: '#', data: { target: "#modal-privileges", toggle: :modal }}
|
%a{href: '#', data: { target: "#modal-privileges", toggle: :modal }}
|
||||||
%i.fa.fa-wrench
|
%i.fa.fa-wrench
|
||||||
= raw t('views.actions.privilege', user: user.screen_name)
|
= raw t('views.actions.privilege', user: user.screen_name)
|
||||||
- unless user.admin?
|
- unless user.has_role?(:administrator)
|
||||||
%li
|
%li
|
||||||
%a{href: '#', data: { target: "#modal-ban", toggle: :modal }}
|
%a{href: '#', data: { target: "#modal-ban", toggle: :modal }}
|
||||||
%i.fa.fa-ban
|
%i.fa.fa-ban
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
= render 'user/modal_privileges_item', privilege: 'blogger', description: t('views.modal.privilege.blogger'), user: @user
|
= render 'user/modal_privileges_item', privilege: 'blogger', description: t('views.modal.privilege.blogger'), user: @user
|
||||||
= render 'user/modal_privileges_item', privilege: 'contributor', description: t('views.modal.privilege.contributor'), user: @user
|
= render 'user/modal_privileges_item', privilege: 'contributor', description: t('views.modal.privilege.contributor'), user: @user
|
||||||
= render 'user/modal_privileges_item', privilege: 'translator', description: t('views.modal.privilege.translator'), user: @user
|
= render 'user/modal_privileges_item', privilege: 'translator', description: t('views.modal.privilege.translator'), user: @user
|
||||||
- if current_user.admin?
|
- if current_user.has_role?(:administrator)
|
||||||
= render 'user/modal_privileges_item', privilege: 'supporter', description: t('views.modal.privilege.supporter'), user: @user
|
= render 'user/modal_privileges_item', privilege: 'supporter', description: t('views.modal.privilege.supporter'), user: @user
|
||||||
= render 'user/modal_privileges_item', privilege: 'moderator', description: t('views.modal.privilege.moderator'),user: @user
|
= render 'user/modal_privileges_item', privilege: 'moderator', description: t('views.modal.privilege.moderator'),user: @user
|
||||||
= render 'user/modal_privileges_item', privilege: 'admin', description: t('views.modal.privilege.admin'), user: @user
|
= render 'user/modal_privileges_item', privilege: 'admin', description: t('views.modal.privilege.admin'), user: @user
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
- description ||= ''
|
- description ||= ''
|
||||||
|
- role_mapping = {"admin" => "administrator"}
|
||||||
|
- requires_role = %w[admin moderator].include?(privilege)
|
||||||
|
- checked = requires_role ? user.has_role?(role_mapping.fetch(privilege, privilege).to_sym) : user.public_send("#{privilege}?")
|
||||||
%li.list-group-item{id: "privilege-#{privilege}"}
|
%li.list-group-item{id: "privilege-#{privilege}"}
|
||||||
.media
|
.media
|
||||||
.pull-left.j2-table
|
.pull-left.j2-table
|
||||||
%input.input--center{type: :checkbox, name: 'check-your-privileges', data: { type: privilege, user: user.screen_name }, checked: user.send("#{privilege}?"), autocomplete: 'off'}
|
%input.input--center{type: :checkbox, name: 'check-your-privileges', data: { type: privilege, user: user.screen_name }, checked: checked, autocomplete: 'off'}
|
||||||
.media-body
|
.media-body
|
||||||
.list-group-item-heading= privilege.capitalize
|
.list-group-item-heading= privilege.capitalize
|
||||||
- unless description.blank?
|
- unless description.blank?
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
.panel.panel-default#profile
|
.panel.panel-default#profile
|
||||||
%img.profile--avatar{src: @user.profile_picture.url(:large)}
|
%img.profile--avatar{src: @user.profile_picture.url(:large)}
|
||||||
- if user_signed_in? && current_user.admin?
|
- if user_signed_in? && current_user.has_role?(:administrator)
|
||||||
- if @user.admin?
|
- if @user.has_role?(:administrator)
|
||||||
.profile--panel-badge.panel-badge-danger
|
.profile--panel-badge.panel-badge-danger
|
||||||
%i.fa.fa-flask
|
%i.fa.fa-flask
|
||||||
= t 'views.user.title.admin'
|
= t 'views.user.title.admin'
|
||||||
- if @user.moderator?
|
- if @user.has_role?(:moderator)
|
||||||
.profile--panel-badge.panel-badge-success
|
.profile--panel-badge.panel-badge-success
|
||||||
%i.fa.fa-users
|
%i.fa.fa-users
|
||||||
= t 'views.user.title.moderator'
|
= t 'views.user.title.moderator'
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
|
|
||||||
%p.data-heading Admin
|
%p.data-heading Admin
|
||||||
%p
|
%p
|
||||||
- if current_user.admin?
|
- if current_user.has_role?(:administrator)
|
||||||
%span.label.label-success
|
%span.label.label-success
|
||||||
%i.fa.fa-fw.fa-check
|
%i.fa.fa-fw.fa-check
|
||||||
- else
|
- else
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# workaround to get pagination right
|
# workaround to get pagination right
|
||||||
if defined? WillPaginate
|
if defined? WillPaginate
|
||||||
Kaminari.configure do |config|
|
Kaminari.configure do |config|
|
||||||
|
@ -6,12 +8,11 @@ if defined? WillPaginate
|
||||||
end
|
end
|
||||||
|
|
||||||
RailsAdmin.config do |config|
|
RailsAdmin.config do |config|
|
||||||
|
|
||||||
config.main_app_name = ['justask', 'Kontrollzentrum']
|
config.main_app_name = ['justask', 'Kontrollzentrum']
|
||||||
|
|
||||||
## == Authentication ==
|
## == Authentication ==
|
||||||
config.authenticate_with do
|
config.authenticate_with do
|
||||||
redirect_to main_app.root_path unless current_user.try :admin?
|
redirect_to main_app.root_path unless current_user&.has_role?(:administrator)
|
||||||
end
|
end
|
||||||
config.current_user_method(&:current_user)
|
config.current_user_method(&:current_user)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
Rolify.configure do |config|
|
||||||
|
# By default ORM adapter is ActiveRecord. uncomment to use mongoid
|
||||||
|
# config.use_mongoid
|
||||||
|
|
||||||
|
# Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false
|
||||||
|
# config.use_dynamic_shortcuts
|
||||||
|
|
||||||
|
# Configuration to remove roles from database once the last resource is removed. Default is: true
|
||||||
|
config.remove_role_if_empty = false
|
||||||
|
end
|
|
@ -2,19 +2,19 @@ require 'sidekiq/web'
|
||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
start = Time.now
|
start = Time.now
|
||||||
|
|
||||||
# Admin panel
|
|
||||||
mount RailsAdmin::Engine => '/justask_admin', as: 'rails_admin'
|
|
||||||
|
|
||||||
# Sidekiq
|
# Sidekiq
|
||||||
constraints ->(req) { req.env["warden"].authenticate?(scope: :user) &&
|
constraints ->(req) { req.env["warden"].authenticate?(scope: :user) &&
|
||||||
req.env['warden'].user.admin? } do
|
req.env["warden"].user.has_role?(:administrator) } do
|
||||||
|
# Admin panel
|
||||||
|
mount RailsAdmin::Engine => "/justask_admin", as: "rails_admin"
|
||||||
|
|
||||||
mount Sidekiq::Web, at: "/sidekiq"
|
mount Sidekiq::Web, at: "/sidekiq"
|
||||||
mount PgHero::Engine, at: "/pghero", as: 'pghero'
|
mount PgHero::Engine, at: "/pghero", as: "pghero"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Moderation panel
|
# Moderation panel
|
||||||
constraints ->(req) { req.env['warden'].authenticate?(scope: :user) &&
|
constraints ->(req) { req.env["warden"].authenticate?(scope: :user) &&
|
||||||
(req.env['warden'].user.mod?) } do
|
req.env["warden"].user.mod? } do
|
||||||
match '/moderation/priority(/:user_id)', to: 'moderation#priority', via: :get, as: :moderation_priority
|
match '/moderation/priority(/:user_id)', to: 'moderation#priority', via: :get, as: :moderation_priority
|
||||||
match '/moderation/ip/:user_id', to: 'moderation#ip', via: :get, as: :moderation_ip
|
match '/moderation/ip/:user_id', to: 'moderation#ip', via: :get, as: :moderation_ip
|
||||||
match '/moderation(/:type)', to: 'moderation#index', via: :get, as: :moderation, defaults: {type: 'all'}
|
match '/moderation(/:type)', to: 'moderation#index', via: :get, as: :moderation, defaults: {type: 'all'}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RolifyCreateRoles < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_table(:roles) do |t|
|
||||||
|
t.string :name
|
||||||
|
t.references :resource, polymorphic: true
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table(:users_roles, id: false) do |t|
|
||||||
|
t.references :user
|
||||||
|
t.references :role
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index(:roles, %i[name resource_type resource_id])
|
||||||
|
add_index(:users_roles, %i[user_id role_id])
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,34 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CreateInitialRoles < ActiveRecord::Migration[5.2]
|
||||||
|
def up
|
||||||
|
%w[Administrator Moderator].each do |role|
|
||||||
|
Role.where(name: role.parameterize).first_or_create
|
||||||
|
end
|
||||||
|
|
||||||
|
{
|
||||||
|
admin: :administrator,
|
||||||
|
moderator: :moderator
|
||||||
|
}.each do |legacy_role, new_role|
|
||||||
|
User.where(legacy_role => true).each do |u|
|
||||||
|
puts "-- migrating #{u.screen_name} (#{u.id}) from field:#{legacy_role} to role:#{new_role}"
|
||||||
|
u.add_role new_role
|
||||||
|
u.public_send("#{legacy_role}=", false)
|
||||||
|
u.save!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
{
|
||||||
|
administrator: :admin,
|
||||||
|
moderator: :moderator
|
||||||
|
}.each do |new_role, legacy_role|
|
||||||
|
User.with_role(new_role).each do |u|
|
||||||
|
puts "-- migrating #{u.screen_name} (#{u.id}) from role:#{new_role} to field:#{legacy_role}"
|
||||||
|
u.public_send("#{legacy_role}=", true)
|
||||||
|
u.save!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
20
db/schema.rb
20
db/schema.rb
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2016_01_05_165913) do
|
ActiveRecord::Schema.define(version: 2020_04_19_185535) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -137,6 +137,16 @@ ActiveRecord::Schema.define(version: 2016_01_05_165913) do
|
||||||
t.string "reason"
|
t.string "reason"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "roles", force: :cascade do |t|
|
||||||
|
t.string "name"
|
||||||
|
t.string "resource_type"
|
||||||
|
t.bigint "resource_id"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id"
|
||||||
|
t.index ["resource_type", "resource_id"], name: "index_roles_on_resource_type_and_resource_id"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "services", id: :serial, force: :cascade do |t|
|
create_table "services", id: :serial, force: :cascade do |t|
|
||||||
t.string "type", null: false
|
t.string "type", null: false
|
||||||
t.integer "user_id", null: false
|
t.integer "user_id", null: false
|
||||||
|
@ -270,4 +280,12 @@ ActiveRecord::Schema.define(version: 2016_01_05_165913) do
|
||||||
t.index ["screen_name"], name: "index_users_on_screen_name", unique: true
|
t.index ["screen_name"], name: "index_users_on_screen_name", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "users_roles", id: false, force: :cascade do |t|
|
||||||
|
t.bigint "user_id"
|
||||||
|
t.bigint "role_id"
|
||||||
|
t.index ["role_id"], name: "index_users_roles_on_role_id"
|
||||||
|
t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id"
|
||||||
|
t.index ["user_id"], name: "index_users_roles_on_user_id"
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,3 +5,7 @@
|
||||||
#
|
#
|
||||||
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
|
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
|
||||||
# Mayor.create(name: 'Emanuel', city: cities.first)
|
# Mayor.create(name: 'Emanuel', city: cities.first)
|
||||||
|
|
||||||
|
%w[Administrator Moderator].each do |role|
|
||||||
|
Role.where(name: role.parameterize).first_or_create
|
||||||
|
end
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'json'
|
require 'json'
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
require 'httparty'
|
require 'httparty'
|
||||||
require 'securerandom'
|
require 'securerandom'
|
||||||
|
|
||||||
class Exporter
|
class Exporter
|
||||||
|
EXPORT_ROLES = [:administrator, :moderator].freeze
|
||||||
|
|
||||||
def initialize(user)
|
def initialize(user)
|
||||||
@user = user
|
@user = user
|
||||||
@obj = {}
|
@obj = {}
|
||||||
|
@ -30,10 +34,10 @@ class Exporter
|
||||||
private
|
private
|
||||||
|
|
||||||
def collect_user_info
|
def collect_user_info
|
||||||
%i(admin answered_count asked_count ban_reason banned_until bio blogger comment_smiled_count commented_count
|
%i(answered_count asked_count ban_reason banned_until bio blogger comment_smiled_count commented_count
|
||||||
confirmation_sent_at confirmed_at contributor created_at crop_h crop_h_h crop_h_w crop_h_x crop_h_y
|
confirmation_sent_at confirmed_at contributor created_at crop_h crop_h_h crop_h_w crop_h_x crop_h_y
|
||||||
crop_w crop_x crop_y current_sign_in_at current_sign_in_ip display_name email follower_count friend_count
|
crop_w crop_x crop_y current_sign_in_at current_sign_in_ip display_name email follower_count friend_count
|
||||||
id last_sign_in_at last_sign_in_ip locale location moderator motivation_header permanently_banned
|
id last_sign_in_at last_sign_in_ip locale location motivation_header permanently_banned
|
||||||
privacy_allow_anonymous_questions privacy_allow_public_timeline privacy_allow_stranger_answers
|
privacy_allow_anonymous_questions privacy_allow_public_timeline privacy_allow_stranger_answers
|
||||||
privacy_show_in_search profile_header_content_type profile_header_file_name profile_header_file_size
|
privacy_show_in_search profile_header_content_type profile_header_file_name profile_header_file_size
|
||||||
profile_header_updated_at profile_picture_content_type profile_picture_file_name profile_picture_file_size
|
profile_header_updated_at profile_picture_content_type profile_picture_file_name profile_picture_file_size
|
||||||
|
@ -41,6 +45,10 @@ class Exporter
|
||||||
updated_at website).each do |f|
|
updated_at website).each do |f|
|
||||||
@obj[f] = @user.send f
|
@obj[f] = @user.send f
|
||||||
end
|
end
|
||||||
|
|
||||||
|
EXPORT_ROLES.each do |role|
|
||||||
|
@obj[role] = @user.has_role?(role)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def collect_questions
|
def collect_questions
|
||||||
|
@ -221,11 +229,16 @@ class Exporter
|
||||||
|
|
||||||
def user_stub(user)
|
def user_stub(user)
|
||||||
uobj = {}
|
uobj = {}
|
||||||
%i(admin answered_count asked_count bio blogger comment_smiled_count commented_count contributor created_at
|
%i(answered_count asked_count bio blogger comment_smiled_count commented_count contributor created_at
|
||||||
display_name follower_count friend_count id location moderator motivation_header permanently_banned screen_name
|
display_name follower_count friend_count id location motivation_header permanently_banned screen_name
|
||||||
smiled_count supporter translator website).each do |f|
|
smiled_count supporter translator website).each do |f|
|
||||||
uobj[f] = user.send f
|
uobj[f] = user.send f
|
||||||
end
|
end
|
||||||
|
|
||||||
|
EXPORT_ROLES.each do |role|
|
||||||
|
uobj[role] = user.has_role?(role)
|
||||||
|
end
|
||||||
|
|
||||||
uobj
|
uobj
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe UserController, :type => :controller do
|
|
||||||
before do
|
|
||||||
@user = create(:user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'responds successfully with a HTTP 200 status code' do
|
|
||||||
get :show, username: @user.screen_name, page: 1
|
|
||||||
expect(response).to be_success
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,9 +0,0 @@
|
||||||
FactoryBot.define do
|
|
||||||
factory :user do |u|
|
|
||||||
u.sequence(:screen_name) { |n| "#{Faker::Internet.user_name 0..12, %w(_)}#{n}" }
|
|
||||||
u.sequence(:email) { |n| "#{n}#{Faker::Internet.email}" }
|
|
||||||
u.password { "P4s5w0rD" }
|
|
||||||
u.sequence(:confirmed_at) { Time.zone.now }
|
|
||||||
u.display_name { Faker::Name.name }
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,6 +0,0 @@
|
||||||
FactoryBot.define do
|
|
||||||
factory :answer do |u|
|
|
||||||
u.sequence(:content) { |n| "This is an answer. I'm number #{n}!" }
|
|
||||||
u.user { FactoryBot.create(:user) }
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,8 +0,0 @@
|
||||||
FactoryBot.define do
|
|
||||||
factory :notification do
|
|
||||||
target_type { "MyString" }
|
|
||||||
target_id { 1 }
|
|
||||||
recipient_id { 1 }
|
|
||||||
new { false }
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,6 +0,0 @@
|
||||||
FactoryBot.define do
|
|
||||||
factory :question do |u|
|
|
||||||
u.sequence(:content) { |n| "#{QuestionGenerator.generate}#{n}" }
|
|
||||||
u.author_is_anonymous { true }
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
FactoryBot.define do
|
||||||
|
factory :user do
|
||||||
|
sequence(:screen_name) { |i| "#{Faker::Internet.username(specifier: 0..12, separators: %w(_))}#{i}" }
|
||||||
|
sequence(:email) { |i| "#{i}#{Faker::Internet.email}" }
|
||||||
|
password { "P4s5w0rD" }
|
||||||
|
confirmed_at { Time.now.utc }
|
||||||
|
display_name { Faker::Name.name }
|
||||||
|
|
||||||
|
transient do
|
||||||
|
roles { [] }
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:create) do |user, evaluator|
|
||||||
|
evaluator.roles.each do |role|
|
||||||
|
user.add_role role
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,45 +0,0 @@
|
||||||
include Warden::Test::Helpers
|
|
||||||
Warden.test_mode!
|
|
||||||
|
|
||||||
# Feature: Ban users
|
|
||||||
# As a user
|
|
||||||
# I want to get banned
|
|
||||||
# So I can't sign in anymore
|
|
||||||
feature "Ban users", :devise do
|
|
||||||
|
|
||||||
after :each do
|
|
||||||
Warden.test_reset!
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User gets banned
|
|
||||||
# Given I am signed in
|
|
||||||
# When I visit another page
|
|
||||||
# And I am banned
|
|
||||||
# Then I see the sign in page
|
|
||||||
scenario "user gets banned", js: true do
|
|
||||||
me = FactoryBot.create :user
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
visit root_path
|
|
||||||
expect(page).to have_text("Timeline")
|
|
||||||
page.driver.render Rails.root.join("tmp/ban_#{Time.now.to_i}_1.png"), full: true
|
|
||||||
|
|
||||||
me.permanently_banned = true
|
|
||||||
me.save
|
|
||||||
|
|
||||||
visit "/inbox"
|
|
||||||
|
|
||||||
expect(current_path).to eq(new_user_session_path)
|
|
||||||
page.driver.render Rails.root.join("tmp/ban_#{Time.now.to_i}_2.png"), full: true
|
|
||||||
end
|
|
||||||
|
|
||||||
scenario 'user visits banned user profiles', js: true do
|
|
||||||
evil_user = FactoryBot.create :user
|
|
||||||
evil_user.permanently_banned = true
|
|
||||||
evil_user.save
|
|
||||||
|
|
||||||
visit show_user_profile_path(evil_user.screen_name)
|
|
||||||
expect(page).to have_text('BANNED')
|
|
||||||
page.driver.render Rails.root.join("tmp/ban_#{Time.now.to_i}_3.png"), full: true
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,28 +0,0 @@
|
||||||
include Warden::Test::Helpers
|
|
||||||
Warden.test_mode!
|
|
||||||
|
|
||||||
feature "User profile page", :devise do
|
|
||||||
|
|
||||||
after :each do
|
|
||||||
Warden.test_reset!
|
|
||||||
end
|
|
||||||
|
|
||||||
scenario "user gets followed", js: true do
|
|
||||||
me = FactoryBot.create(:user)
|
|
||||||
other = FactoryBot.create(:user)
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
visit show_user_profile_path(other.screen_name)
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_1.png"), full: true
|
|
||||||
|
|
||||||
click_button "Follow"
|
|
||||||
wait_for_ajax
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_2.png"), full: true
|
|
||||||
|
|
||||||
expect(page).to have_text("FOLLOWING")
|
|
||||||
|
|
||||||
click_link 'Follower'
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_3.png"), full: true
|
|
||||||
expect(page).to have_text(me.screen_name)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,144 +0,0 @@
|
||||||
include Warden::Test::Helpers
|
|
||||||
Warden.test_mode!
|
|
||||||
|
|
||||||
# Feature: Answer questions
|
|
||||||
# As a user
|
|
||||||
# I want to go to the inbox
|
|
||||||
# So I can answer and get new questions
|
|
||||||
feature "Inbox", :devise do
|
|
||||||
|
|
||||||
after :each do
|
|
||||||
Warden.test_reset!
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User answers a question
|
|
||||||
# Given I am signed in
|
|
||||||
# When I visit the inbox
|
|
||||||
# And I have a question in my inbox
|
|
||||||
# Then I can answer my question
|
|
||||||
# And see the answer on my user profile
|
|
||||||
scenario "user answers a question", js: true do
|
|
||||||
me = FactoryBot.create :user
|
|
||||||
question = FactoryBot.create :question
|
|
||||||
Inbox.create question: question, user: me, new: true
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
visit root_path
|
|
||||||
|
|
||||||
click_link "Inbox"
|
|
||||||
expect(page).to have_text(question.content)
|
|
||||||
fill_in "ib-answer", with: Faker::Lorem.sentence
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_2.png"), full: true
|
|
||||||
|
|
||||||
click_button "Answer"
|
|
||||||
wait_for_ajax
|
|
||||||
expect(page).not_to have_text(question.content)
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_3.png"), full: true
|
|
||||||
|
|
||||||
visit show_user_profile_path(me.screen_name)
|
|
||||||
expect(page).to have_text(question.content)
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_4.png"), full: true
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User generates new question
|
|
||||||
# Given I am signed in
|
|
||||||
# When I visit the inbox
|
|
||||||
# And I click "Get new question"
|
|
||||||
# Then I get a new question
|
|
||||||
scenario 'user generates new question', js: true do
|
|
||||||
me = FactoryBot.create :user
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
visit inbox_path
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_1.png"), full: true
|
|
||||||
|
|
||||||
click_button "Get new question"
|
|
||||||
wait_for_ajax
|
|
||||||
expect(page).to have_text('Answer')
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_2.png"), full: true
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User with privacy options generates new question
|
|
||||||
# Given I am signed in
|
|
||||||
# When I visit the inbox
|
|
||||||
# And I click "Get new question"
|
|
||||||
# And I don't want to receive questions by anonymous users
|
|
||||||
# Then I get a new question
|
|
||||||
scenario 'user with privacy options generates new question', js: true do
|
|
||||||
me = FactoryBot.create :user
|
|
||||||
me.privacy_allow_anonymous_questions = false
|
|
||||||
me.save
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
visit inbox_path
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_1.png"), full: true
|
|
||||||
|
|
||||||
click_button "Get new question"
|
|
||||||
wait_for_ajax
|
|
||||||
expect(page).to have_text('Answer')
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_2.png"), full: true
|
|
||||||
end
|
|
||||||
|
|
||||||
=begin
|
|
||||||
# Scenario: User deletes a question
|
|
||||||
# Given I am signed in
|
|
||||||
# When I visit the inbox
|
|
||||||
# And I have a question in my inbox
|
|
||||||
# And I delete the question
|
|
||||||
# Then don't see it anymore in my inbox
|
|
||||||
scenario "user deletes a question", js: true do
|
|
||||||
me = FactoryBot.create :user
|
|
||||||
question = FactoryBot.create :question
|
|
||||||
Inbox.create question: question, user: me
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
visit inbox_path
|
|
||||||
expect(page).to have_text(question.content)
|
|
||||||
|
|
||||||
click_button "Delete"
|
|
||||||
expect(page).to have_text('Really delete?')
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_1.png"), full: true
|
|
||||||
|
|
||||||
# this apparently doesn't get triggered :(
|
|
||||||
page.find('.sweet-alert').click_button 'Delete'
|
|
||||||
wait_for_ajax
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
visit inbox_path
|
|
||||||
expect(page).not_to have_text(question.content)
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_2.png"), full: true
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User deletes all questions
|
|
||||||
# Given I am signed in
|
|
||||||
# When I visit the inbox
|
|
||||||
# And I have a few questions in my inbox
|
|
||||||
# And I click on "Delete all questions"
|
|
||||||
# Then don't see them anymore in my inbox
|
|
||||||
scenario "user deletes all questions", js: true do
|
|
||||||
me = FactoryBot.create :user
|
|
||||||
5.times do
|
|
||||||
question = FactoryBot.create :question
|
|
||||||
Inbox.create question: question, user: me
|
|
||||||
end
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
visit inbox_path
|
|
||||||
expect(page).to have_text('Answer'.upcase)
|
|
||||||
|
|
||||||
click_button "Delete all questions"
|
|
||||||
expect(page).to have_text('Really delete 5 questions?')
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_1.png"), full: true
|
|
||||||
|
|
||||||
page.find('.sweet-alert').click_button 'Delete'
|
|
||||||
wait_for_ajax
|
|
||||||
|
|
||||||
puts me.inbox.all
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
visit inbox_path
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_2.png"), full: true
|
|
||||||
expect(page).not_to have_text('Answer'.upcase)
|
|
||||||
end
|
|
||||||
=end
|
|
||||||
end
|
|
|
@ -1,45 +0,0 @@
|
||||||
# Feature: Sign in
|
|
||||||
# As a user
|
|
||||||
# I want to sign in
|
|
||||||
# So I can visit protected areas of the site
|
|
||||||
feature 'Sign in', :devise do
|
|
||||||
|
|
||||||
scenario 'user cannot sign in if not registered', js: true do
|
|
||||||
user = FactoryBot.build(:user)
|
|
||||||
signin(user.screen_name, user.password)
|
|
||||||
expect(page).to have_content I18n.t 'devise.failure.not_found_in_database', authentication_keys: 'login'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User can sign in with valid credentials
|
|
||||||
# Given I exist as a user
|
|
||||||
# And I am not signed in
|
|
||||||
# When I sign in with valid credentials
|
|
||||||
# Then I see a success message
|
|
||||||
scenario 'user can sign in with valid credentials', js: true do
|
|
||||||
user = FactoryBot.create(:user)
|
|
||||||
signin(user.email, user.password)
|
|
||||||
expect(page).to have_content I18n.t 'devise.sessions.signed_in'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User cannot sign in with wrong email
|
|
||||||
# Given I exist as a user
|
|
||||||
# And I am not signed in
|
|
||||||
# When I sign in with a wrong email
|
|
||||||
# Then I see an invalid email message
|
|
||||||
scenario 'user cannot sign in with wrong email', js: true do
|
|
||||||
user = FactoryBot.create(:user)
|
|
||||||
signin('invalid@email.com', user.password)
|
|
||||||
expect(page).to have_content I18n.t 'devise.failure.not_found_in_database', authentication_keys: 'login'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User cannot sign in with wrong password
|
|
||||||
# Given I exist as a user
|
|
||||||
# And I am not signed in
|
|
||||||
# When I sign in with a wrong password
|
|
||||||
# Then I see an invalid password message
|
|
||||||
scenario 'user cannot sign in with wrong password', js: true do
|
|
||||||
user = FactoryBot.create(:user)
|
|
||||||
signin(user.email, 'what the fuck is my p4s5w0rD again?')
|
|
||||||
expect(page).to have_content I18n.t 'devise.failure.invalid', authentication_keys: 'login'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,19 +0,0 @@
|
||||||
# Feature: Sign out
|
|
||||||
# As a user
|
|
||||||
# I want to sign out
|
|
||||||
# So I can protect my account from unauthorized access
|
|
||||||
feature 'Sign out', :devise do
|
|
||||||
|
|
||||||
# Scenario: User signs out successfully
|
|
||||||
# Given I am signed in
|
|
||||||
# When I sign out
|
|
||||||
# Then I see a signed out message
|
|
||||||
scenario 'user signs out successfully', js: true do
|
|
||||||
user = FactoryBot.create(:user)
|
|
||||||
signin(user.email, user.password)
|
|
||||||
expect(page).to have_content I18n.t 'devise.sessions.signed_in'
|
|
||||||
click_link user.screen_name
|
|
||||||
click_link 'Logout'
|
|
||||||
expect(page).to have_content I18n.t 'devise.sessions.signed_out'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,66 +0,0 @@
|
||||||
include Warden::Test::Helpers
|
|
||||||
Warden.test_mode!
|
|
||||||
|
|
||||||
# Feature: User profile page
|
|
||||||
# As a user
|
|
||||||
# I want to visit my user profile page
|
|
||||||
# So I can see my personal account data
|
|
||||||
feature "User profile page", :devise do
|
|
||||||
|
|
||||||
after :each do
|
|
||||||
Warden.test_reset!
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User sees own profile
|
|
||||||
# Given I am signed in
|
|
||||||
# When I visit the user profile page
|
|
||||||
# Then I see my own screen name and follower count
|
|
||||||
scenario 'user sees own profile', js: true do
|
|
||||||
user = FactoryBot.create(:user)
|
|
||||||
|
|
||||||
login_as(user, :scope => :user)
|
|
||||||
|
|
||||||
visit show_user_profile_path(user.screen_name)
|
|
||||||
|
|
||||||
expect(page).to have_content user.screen_name
|
|
||||||
expect(page).to have_content user.follower_count
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User sees another user's profile
|
|
||||||
# Given I am signed in
|
|
||||||
# When I visit another user's profile
|
|
||||||
# Then I see that user's screen name and follower count
|
|
||||||
scenario "user sees another user's profile", js: true do
|
|
||||||
me = FactoryBot.create(:user)
|
|
||||||
other = FactoryBot.create(:user)
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
|
|
||||||
visit show_user_profile_path(other.screen_name)
|
|
||||||
|
|
||||||
expect(page).to have_content other.screen_name
|
|
||||||
expect(page).to have_content other.follower_count
|
|
||||||
end
|
|
||||||
|
|
||||||
# Scenario: User gets asked a question
|
|
||||||
# Given I am signed in
|
|
||||||
# When I visit another user's profile
|
|
||||||
# And I fill something in the question box
|
|
||||||
# And I click on "Ask"
|
|
||||||
# Then I see "Question asked successfully."
|
|
||||||
scenario "user gets asked a question", js: true do
|
|
||||||
me = FactoryBot.create(:user)
|
|
||||||
other = FactoryBot.create(:user)
|
|
||||||
|
|
||||||
login_as me, scope: :user
|
|
||||||
visit show_user_profile_path(other.screen_name)
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_1.png"), full: true
|
|
||||||
|
|
||||||
fill_in "qb-question", with: Faker::Lorem.sentence
|
|
||||||
click_button "Ask"
|
|
||||||
wait_for_ajax
|
|
||||||
page.driver.render Rails.root.join("tmp/#{Time.now.to_i}_2.png"), full: true
|
|
||||||
|
|
||||||
expect(page).to have_text("Question asked successfully.")
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,15 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
# Specs in this file have access to a helper object that includes
|
|
||||||
# the SubscribeHelper. For example:
|
|
||||||
#
|
|
||||||
# describe SubscribeHelper do
|
|
||||||
# describe "string concat" do
|
|
||||||
# it "concats two strings with spaces" do
|
|
||||||
# expect(helper.concat_strings("this","that")).to eq("this that")
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
RSpec.describe SubscribeHelper, :type => :helper do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
end
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe 'role-constrained routes', type: :request do
|
||||||
|
shared_examples_for 'fails to access route' do
|
||||||
|
it 'fails to access route' do
|
||||||
|
# 404 = no user found -- we have a fallback route if something could not be matched
|
||||||
|
expect(subject).to eq 404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples_for 'routes for' do |roles, subject_block, skip_reason: nil|
|
||||||
|
before { skip(skip_reason) } if skip_reason
|
||||||
|
|
||||||
|
subject(&subject_block)
|
||||||
|
|
||||||
|
context 'not signed in' do
|
||||||
|
include_examples 'fails to access route'
|
||||||
|
end
|
||||||
|
|
||||||
|
roles.each do |role|
|
||||||
|
context "signed in user without #{role} role" do
|
||||||
|
let(:user) { FactoryBot.create(:user, password: 'test1234') }
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
post '/sign_in', params: { user: { login: user.email, password: user.password } }
|
||||||
|
end
|
||||||
|
|
||||||
|
include_examples 'fails to access route'
|
||||||
|
end
|
||||||
|
|
||||||
|
context "signed in user with #{role} role" do
|
||||||
|
let(:user) { FactoryBot.create(:user, password: 'test1234', roles: [role]) }
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
post '/sign_in', params: { user: { login: user.email, password: user.password } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'can access route' do
|
||||||
|
expect(subject).to be_in 200..299
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like('routes for', [:administrator], -> { get('/justask_admin') })
|
||||||
|
it_behaves_like('routes for', [:administrator], -> { get('/sidekiq') })
|
||||||
|
it_behaves_like('routes for', [:administrator], -> { get('/pghero') }, skip_reason: 'PG::InFailedSqlTransaction due to 5.1 upgrade, works fine outside specs though')
|
||||||
|
it_behaves_like('routes for', %i[administrator moderator], -> { get('/moderation') })
|
||||||
|
end
|
|
@ -1,19 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe Answer, :type => :model do
|
|
||||||
before :each do
|
|
||||||
@answer = Answer.new(
|
|
||||||
content: 'This is an answer.',
|
|
||||||
user: FactoryBot.create(:user),
|
|
||||||
question: FactoryBot.create(:question)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
subject { @answer }
|
|
||||||
|
|
||||||
it { should respond_to(:content) }
|
|
||||||
|
|
||||||
it '#content returns a string' do
|
|
||||||
expect(@answer.content).to match 'This is an answer.'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,5 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe Notification, :type => :model do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
end
|
|
|
@ -1,8 +1,16 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
||||||
ENV["RAILS_ENV"] ||= 'test'
|
ENV["RAILS_ENV"] ||= "test"
|
||||||
require 'spec_helper'
|
|
||||||
require File.expand_path("../../config/environment", __FILE__)
|
require File.expand_path("../../config/environment", __FILE__)
|
||||||
require 'rspec/rails'
|
# Prevent database truncation if the environment is production
|
||||||
|
abort("The Rails environment is running in production mode!") if Rails.env.production?
|
||||||
|
require "spec_helper"
|
||||||
|
require "rspec/rails"
|
||||||
|
# Add additional requires below this line. Rails is not loaded until this point!
|
||||||
|
require "devise"
|
||||||
|
require "capybara/rails"
|
||||||
|
require "capybara/rspec"
|
||||||
|
|
||||||
# Requires supporting ruby files with custom matchers and macros, etc, in
|
# Requires supporting ruby files with custom matchers and macros, etc, in
|
||||||
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
|
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
|
||||||
|
@ -11,20 +19,40 @@ require 'rspec/rails'
|
||||||
# run twice. It is recommended that you do not name files matching this glob to
|
# run twice. It is recommended that you do not name files matching this glob to
|
||||||
# end with _spec.rb. You can configure this pattern with the --pattern
|
# end with _spec.rb. You can configure this pattern with the --pattern
|
||||||
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
|
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
|
||||||
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
|
#
|
||||||
|
# The following line is provided for convenience purposes. It has the downside
|
||||||
|
# of increasing the boot-up time by auto-requiring all files in the support
|
||||||
|
# directory. Alternatively, in the individual `*_spec.rb` files, manually
|
||||||
|
# require only the support files necessary.
|
||||||
|
#
|
||||||
|
# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
|
||||||
|
|
||||||
# Checks for pending migrations before tests are run.
|
# Checks for pending migration and applies them before tests are run.
|
||||||
# If you are not using ActiveRecord, you can remove this line.
|
# If you are not using ActiveRecord, you can remove this line.
|
||||||
ActiveRecord::Migration.maintain_test_schema!
|
ActiveRecord::Migration.maintain_test_schema!
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
|
config.before :suite do
|
||||||
|
# Run webpack compilation before suite, so assets exists in public/packs
|
||||||
|
# It would be better to run the webpack compilation only if at least one :js spec
|
||||||
|
# should be executed, but `when_first_matching_example_defined`
|
||||||
|
# does not work with `config.infer_spec_type_from_file_location!`
|
||||||
|
# see https://github.com/rspec/rspec-core/issues/2366
|
||||||
|
|
||||||
|
unless ENV.key?("DISABLE_WEBPACK_IN_TESTS")
|
||||||
|
start = Time.now # rubocop:disable all
|
||||||
|
`bin/webpack`
|
||||||
|
puts "processing time of webpack: \033[32;1m#{(Time.now - start).round(3).to_s.ljust(5, '0')}s\033[0m" # rubocop:disable all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
||||||
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
||||||
|
|
||||||
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
||||||
# examples within a transaction, remove the following line or assign false
|
# examples within a transaction, remove the following line or assign false
|
||||||
# instead of true.
|
# instead of true.
|
||||||
config.use_transactional_fixtures = false
|
config.use_transactional_fixtures = true
|
||||||
|
|
||||||
# RSpec Rails can automatically mix in different behaviours to your tests
|
# RSpec Rails can automatically mix in different behaviours to your tests
|
||||||
# based on their file location, for example enabling you to call `get` and
|
# based on their file location, for example enabling you to call `get` and
|
||||||
|
@ -40,4 +68,13 @@ RSpec.configure do |config|
|
||||||
# The different available types are documented in the features, such as in
|
# The different available types are documented in the features, such as in
|
||||||
# https://relishapp.com/rspec/rspec-rails/docs
|
# https://relishapp.com/rspec/rspec-rails/docs
|
||||||
config.infer_spec_type_from_file_location!
|
config.infer_spec_type_from_file_location!
|
||||||
|
|
||||||
|
# Filter lines from Rails gems in backtraces.
|
||||||
|
config.filter_rails_from_backtrace!
|
||||||
|
# arbitrary gems may also be filtered via:
|
||||||
|
# config.filter_gems_from_backtrace("gem name")
|
||||||
|
|
||||||
|
config.include Devise::Test::ControllerHelpers, type: :controller
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Dir[Rails.root.join "spec", "shared_examples", "*.rb"].sort.each { |f| require f }
|
||||||
|
|
|
@ -1,99 +1,102 @@
|
||||||
require 'simplecov'
|
# frozen_string_literal: true
|
||||||
require 'simplecov-json'
|
|
||||||
require 'simplecov-rcov'
|
|
||||||
|
|
||||||
SimpleCov.formatters = [
|
require "support/simplecov"
|
||||||
SimpleCov::Formatter::HTMLFormatter,
|
require "support/factory_bot"
|
||||||
SimpleCov::Formatter::JSONFormatter,
|
|
||||||
SimpleCov::Formatter::RcovFormatter
|
|
||||||
]
|
|
||||||
SimpleCov.start
|
|
||||||
|
|
||||||
require 'capybara/poltergeist'
|
|
||||||
Capybara.register_driver :poltergeist do |app|
|
|
||||||
Capybara::Poltergeist::Driver.new app,
|
|
||||||
js_errors: false,
|
|
||||||
timeout: 180
|
|
||||||
end
|
|
||||||
Capybara.javascript_driver = :poltergeist
|
|
||||||
|
|
||||||
require 'factory_bot_rails'
|
|
||||||
|
|
||||||
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
|
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
|
||||||
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
||||||
# The generated `.rspec` file contains `--require spec_helper` which will cause this
|
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
||||||
# file to always be loaded, without a need to explicitly require it in any files.
|
# this file to always be loaded, without a need to explicitly require it in any
|
||||||
|
# files.
|
||||||
#
|
#
|
||||||
# Given that it is always loaded, you are encouraged to keep this file as
|
# Given that it is always loaded, you are encouraged to keep this file as
|
||||||
# light-weight as possible. Requiring heavyweight dependencies from this file
|
# light-weight as possible. Requiring heavyweight dependencies from this file
|
||||||
# will add to the boot time of your test suite on EVERY test run, even for an
|
# will add to the boot time of your test suite on EVERY test run, even for an
|
||||||
# individual file that may not need all of that loaded. Instead, make a
|
# individual file that may not need all of that loaded. Instead, consider making
|
||||||
# separate helper file that requires this one and then use it only in the specs
|
# a separate helper file that requires the additional dependencies and performs
|
||||||
# that actually need it.
|
# the additional setup, and require it from the spec files that actually need
|
||||||
|
# it.
|
||||||
#
|
#
|
||||||
# The `.rspec` file also contains a few flags that are not defaults but that
|
# The `.rspec` file also contains a few flags that are not defaults but that
|
||||||
# users commonly want.
|
# users commonly want.
|
||||||
#
|
#
|
||||||
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
# The settings below are suggested to provide a good initial experience
|
|
||||||
# with RSpec, but feel free to customize to your heart's content.
|
|
||||||
=begin
|
|
||||||
# These two settings work together to allow you to limit a spec run
|
|
||||||
# to individual examples or groups you care about by tagging them with
|
|
||||||
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
|
||||||
# get run.
|
|
||||||
config.filter_run :focus
|
|
||||||
config.run_all_when_everything_filtered = true
|
|
||||||
|
|
||||||
# Many RSpec users commonly either run the entire suite or an individual
|
|
||||||
# file, and it's useful to allow more verbose output when running an
|
|
||||||
# individual spec file.
|
|
||||||
if config.files_to_run.one?
|
|
||||||
# Use the documentation formatter for detailed output,
|
|
||||||
# unless a formatter has already been configured
|
|
||||||
# (e.g. via a command-line flag).
|
|
||||||
config.default_formatter = 'doc'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Print the 10 slowest examples and example groups at the
|
|
||||||
# end of the spec run, to help surface which specs are running
|
|
||||||
# particularly slow.
|
|
||||||
config.profile_examples = 10
|
|
||||||
|
|
||||||
# Run specs in random order to surface order dependencies. If you find an
|
|
||||||
# order dependency and want to debug it, you can fix the order by providing
|
|
||||||
# the seed, which is printed after each run.
|
|
||||||
# --seed 1234
|
|
||||||
config.order = :random
|
|
||||||
|
|
||||||
# Seed global randomization in this process using the `--seed` CLI option.
|
|
||||||
# Setting this allows you to use `--seed` to deterministically reproduce
|
|
||||||
# test failures related to randomization by passing the same `--seed` value
|
|
||||||
# as the one that triggered the failure.
|
|
||||||
Kernel.srand config.seed
|
|
||||||
|
|
||||||
# rspec-expectations config goes here. You can use an alternate
|
# rspec-expectations config goes here. You can use an alternate
|
||||||
# assertion/expectation library such as wrong or the stdlib/minitest
|
# assertion/expectation library such as wrong or the stdlib/minitest
|
||||||
# assertions if you prefer.
|
# assertions if you prefer.
|
||||||
config.expect_with :rspec do |expectations|
|
config.expect_with :rspec do |expectations|
|
||||||
# Enable only the newer, non-monkey-patching expect syntax.
|
# This option will default to `true` in RSpec 4. It makes the `description`
|
||||||
# For more details, see:
|
# and `failure_message` of custom matchers include text for helper methods
|
||||||
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
# defined using `chain`, e.g.:
|
||||||
expectations.syntax = :expect
|
# be_bigger_than(2).and_smaller_than(4).description
|
||||||
|
# # => "be bigger than 2 and smaller than 4"
|
||||||
|
# ...rather than:
|
||||||
|
# # => "be bigger than 2"
|
||||||
|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
||||||
end
|
end
|
||||||
|
|
||||||
# rspec-mocks config goes here. You can use an alternate test double
|
# rspec-mocks config goes here. You can use an alternate test double
|
||||||
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
||||||
config.mock_with :rspec do |mocks|
|
config.mock_with :rspec do |mocks|
|
||||||
# Enable only the newer, non-monkey-patching expect syntax.
|
|
||||||
# For more details, see:
|
|
||||||
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
|
||||||
mocks.syntax = :expect
|
|
||||||
|
|
||||||
# Prevents you from mocking or stubbing a method that does not exist on
|
# Prevents you from mocking or stubbing a method that does not exist on
|
||||||
# a real object. This is generally recommended.
|
# a real object. This is generally recommended, and will default to
|
||||||
|
# `true` in RSpec 4.
|
||||||
mocks.verify_partial_doubles = true
|
mocks.verify_partial_doubles = true
|
||||||
end
|
end
|
||||||
=end
|
|
||||||
|
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
|
||||||
|
# have no way to turn it off -- the option exists only for backwards
|
||||||
|
# compatibility in RSpec 3). It causes shared context metadata to be
|
||||||
|
# inherited by the metadata hash of host groups and examples, rather than
|
||||||
|
# triggering implicit auto-inclusion in groups with matching metadata.
|
||||||
|
config.shared_context_metadata_behavior = :apply_to_host_groups
|
||||||
|
|
||||||
|
# The settings below are suggested to provide a good initial experience
|
||||||
|
# with RSpec, but feel free to customize to your heart's content.
|
||||||
|
# # This allows you to limit a spec run to individual examples or groups
|
||||||
|
# # you care about by tagging them with `:focus` metadata. When nothing
|
||||||
|
# # is tagged with `:focus`, all examples get run. RSpec also provides
|
||||||
|
# # aliases for `it`, `describe`, and `context` that include `:focus`
|
||||||
|
# # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
|
||||||
|
# config.filter_run_when_matching :focus
|
||||||
|
#
|
||||||
|
# # Allows RSpec to persist some state between runs in order to support
|
||||||
|
# # the `--only-failures` and `--next-failure` CLI options. We recommend
|
||||||
|
# # you configure your source control system to ignore this file.
|
||||||
|
config.example_status_persistence_file_path = "spec/examples.txt"
|
||||||
|
#
|
||||||
|
# # Limits the available syntax to the non-monkey patched syntax that is
|
||||||
|
# # recommended. For more details, see:
|
||||||
|
# # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
||||||
|
# # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
||||||
|
# # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
||||||
|
# config.disable_monkey_patching!
|
||||||
|
#
|
||||||
|
# # Many RSpec users commonly either run the entire suite or an individual
|
||||||
|
# # file, and it's useful to allow more verbose output when running an
|
||||||
|
# # individual spec file.
|
||||||
|
# if config.files_to_run.one?
|
||||||
|
# # Use the documentation formatter for detailed output,
|
||||||
|
# # unless a formatter has already been configured
|
||||||
|
# # (e.g. via a command-line flag).
|
||||||
|
# config.default_formatter = 'doc'
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# # Print the 10 slowest examples and example groups at the
|
||||||
|
# # end of the spec run, to help surface which specs are running
|
||||||
|
# # particularly slow.
|
||||||
|
# config.profile_examples = 10
|
||||||
|
#
|
||||||
|
# # Run specs in random order to surface order dependencies. If you find an
|
||||||
|
# # order dependency and want to debug it, you can fix the order by providing
|
||||||
|
# # the seed, which is printed after each run.
|
||||||
|
# # --seed 1234
|
||||||
|
# config.order = :random
|
||||||
|
#
|
||||||
|
# # Seed global randomization in this process using the `--seed` CLI option.
|
||||||
|
# # Setting this allows you to use `--seed` to deterministically reproduce
|
||||||
|
# # test failures related to randomization by passing the same `--seed` value
|
||||||
|
# # as the one that triggered the failure.
|
||||||
|
# Kernel.srand config.seed
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
RSpec.configure do |config|
|
|
||||||
config.include Devise::TestHelpers, type: :controller
|
|
||||||
end
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "factory_bot_rails"
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.include FactoryBot::Syntax::Methods
|
config.include FactoryBot::Syntax::Methods
|
||||||
end
|
end
|
|
@ -1,5 +0,0 @@
|
||||||
require 'support/helpers/session_helpers'
|
|
||||||
|
|
||||||
RSpec.configure do |config|
|
|
||||||
config.include Features::SessionHelpers, type: :feature
|
|
||||||
end
|
|
|
@ -1,19 +0,0 @@
|
||||||
module Features
|
|
||||||
module SessionHelpers
|
|
||||||
def sign_up_with(screen_name, email, password, confirmation)
|
|
||||||
visit new_user_registration_path
|
|
||||||
fill_in 'User name', with: screen_name
|
|
||||||
fill_in 'Email address', with: email
|
|
||||||
fill_in 'Password', with: password
|
|
||||||
fill_in 'Password confirmation', :with => confirmation
|
|
||||||
click_button 'Sign up'
|
|
||||||
end
|
|
||||||
|
|
||||||
def signin(email, password)
|
|
||||||
visit new_user_session_path
|
|
||||||
fill_in 'User name', with: email
|
|
||||||
fill_in 'Password', with: password
|
|
||||||
click_button 'Sign in'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "simplecov"
|
||||||
|
# require "simplecov-rcov"
|
||||||
|
# SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
|
||||||
|
SimpleCov.start "rails"
|
|
@ -1,15 +0,0 @@
|
||||||
module WaitForAjax
|
|
||||||
def wait_for_ajax
|
|
||||||
Timeout.timeout(Capybara.default_wait_time) do
|
|
||||||
loop until finished_all_ajax_requests?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def finished_all_ajax_requests?
|
|
||||||
page.evaluate_script('jQuery.active').zero?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
RSpec.configure do |config|
|
|
||||||
config.include WaitForAjax, type: :feature
|
|
||||||
end
|
|
Loading…
Reference in New Issue