Add api/nonprofits#create

This commit is contained in:
Eric Schultz 2020-04-21 13:47:49 -05:00
parent f6f92788dd
commit c20d01c4e8
10 changed files with 114 additions and 602 deletions

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
class Api::ApiController < ApplicationController
rescue_from ActiveRecord::RecordInvalid, with: :record_invalid_rescue
protected
def record_invalid_rescue(error)
render json:{errors: error.record.errors.messages}, status: :unprocessable_entity
end
end

View file

@ -1,5 +1,7 @@
class Api::NonprofitsController < ApplicationController # frozen_string_literal: true
rescue_from ActiveRecord::RecordInvalid, with: :record_invalid_rescue
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
class Api::NonprofitsController < Api::ApiController
# requires :nonprofit, type: Hash do # requires :nonprofit, type: Hash do
# requires :name, type: String, desc: 'Organization Name', allow_blank: false, documentation: { param_type: 'body' } # requires :name, type: String, desc: 'Organization Name', allow_blank: false, documentation: { param_type: 'body' }
# requires :zip_code, type: String, allow_blank: false, desc: 'Organization Address ZIP Code', documentation: { param_type: 'body' } # requires :zip_code, type: String, allow_blank: false, desc: 'Organization Address ZIP Code', documentation: { param_type: 'body' }
@ -12,94 +14,15 @@ class Api::NonprofitsController < ApplicationController
# requires :email, type: String, desc: 'Username', allow_blank: false, documentation: { param_type: 'body' } # requires :email, type: String, desc: 'Username', allow_blank: false, documentation: { param_type: 'body' }
# requires :password, type: String, desc: 'Password', allow_blank: false, is_equal_to: :password_confirmation, documentation: { param_type: 'body' } # requires :password, type: String, desc: 'Password', allow_blank: false, is_equal_to: :password_confirmation, documentation: { param_type: 'body' }
def create def create
#model = CreateModel.new(clean_params) @nonprofit = Nonprofit.new(clean_params.merge({user_id: current_user_id}))
Qx.transaction do @nonprofit.save!
# raise Errors::MessageInvalid.new(model) unless model.valid? render status: :created
nonprofit = Nonprofit.new(clean_params)
nonprofit.save!
end
# Qx.transaction do
# byebug
# np = ::Nonprofit.new(OnboardAccounts.set_nonprofit_defaults(clean_params[:nonprofit]))
# begin
# np.save!
# rescue ActiveRecord::RecordInvalid => e
# if e.record.errors[:slug]
# begin
# slug = SlugNonprofitNamingAlgorithm.new(np.state_code_slug, np.city_slug).create_copy_name(np.slug)
# np.slug = slug
# np.save!
# rescue UnableToCreateNameCopyError
# raise Grape::Exceptions::ValidationErrors.new(errors: [Grape::Exceptions::Validation.new(
# params: ['nonprofit[name]'],
# message: 'has an invalid slug. Contact support for help.'
# )])
# end
# else
# raise e
# end
# end
# u = User.new(clean_params[:user])
# u.save!
# role = u.roles.build(host: np, name: 'nonprofit_admin')
# role.save!
# billing_plan = BillingPlan.find(Settings.default_bp.id)
# b_sub = np.build_billing_subscription(billing_plan: billing_plan, status: 'active')
# b_sub.save!
# rescue ActiveRecord::RecordInvalid => e
# class_to_name = { Nonprofit => 'nonprofit', User => 'user' }
# if class_to_name[e.record.class]
# errors = e.record.errors.keys.map do |k|
# errors = e.record.errors[k].uniq
# errors.map do |error|
# Grape::Exceptions::Validation.new(
# params: ["#{class_to_name[e.record.class]}[#{k}]"],
# message: error
# )
# end
# end
# raise Grape::Exceptions::ValidationErrors.new(errors: errors.flatten)
# else
# raise e
# end
# end
end end
private private
def record_invalid_rescue(error)
render json:{errors: error.record.errors.messages}, status: :unprocessable_entity
end
def change_to_errors(message)
message.model.errors.keys.map do |k|
errors = e.record.errors[k].uniq
errors.map do |error|
Grape::Exceptions::Validation.new(
params: ["#{class_to_name[e.record.class]}[#{k}]"],
message: error
)
end
end
end
def flatten_errors(hash_or_array, parent=nil)
if hash_or_array.keys
result = hash_or_array.keys.map{|i|
param = !parent ? i : "#{parent}[#{i}]"
}
else
return hash_or_array;
end
end
def clean_params def clean_params
params.permit(:name, :zip_code, :state_code, :city, :user) params.permit(:name, :zip_code, :state_code, :city, :phone, :email, :website)
end end
end end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
module Api::NonprofitsHelper
def nonprofit_slug_url(nonprofit)
nonprofit_location_url city: nonprofit.city_slug, state_code: nonprofit.state_code_slug, name: nonprofit.slug
end
def nonprofit_slug_path(nonprofit)
nonprofit_location_path city: nonprofit.city_slug, state_code: nonprofit.state_code_slug, name: nonprofit.slug
end
end

View file

@ -83,9 +83,10 @@ class Nonprofit < ApplicationRecord
validates :name, presence: true validates :name, presence: true
validates :city, presence: true validates :city, presence: true
validates :state_code, presence: true validates :state_code, presence: true
validates :email, format: { with: Email::Regex }, allow_blank: true validates_format_of :email, with: Email::Regex, allow_nil: true
validates_uniqueness_of :slug, scope: %i[city_slug state_code_slug] validates_format_of :website, with: URI.regexp(['https', 'http']), allow_nil: true
validates_presence_of :slug validates_presence_of :slug
validates_uniqueness_of :slug, scope: %i[city_slug state_code_slug]
validates_presence_of :user_id, on: :create, unless: -> {register_np_only} validates_presence_of :user_id, on: :create, unless: -> {register_np_only}
validate :user_is_valid, on: :create, unless: -> {register_np_only} validate :user_is_valid, on: :create, unless: -> {register_np_only}
@ -165,7 +166,7 @@ class Nonprofit < ApplicationRecord
slug = SlugNonprofitNamingAlgorithm.new(self.state_code_slug, self.city_slug).create_copy_name(self.slug) slug = SlugNonprofitNamingAlgorithm.new(self.state_code_slug, self.city_slug).create_copy_name(self.slug)
self.slug = slug self.slug = slug
rescue UnableToCreateNameCopyError rescue UnableToCreateNameCopyError
errors.add(:slug, "another nonprofit admin") errors.add(:slug, "could not be created.")
end end
end end
@ -176,10 +177,6 @@ class Nonprofit < ApplicationRecord
self self
end end
def user_is_valid
(user && user.is_a?(User)) || errors.add(:user_id, "is not a valid user")
end
def full_address def full_address
Format::Address.full_address(address, city, state_code) Format::Address.full_address(address, city, state_code)
end end
@ -228,11 +225,6 @@ class Nonprofit < ApplicationRecord
Settings.intntl.all_currencies.find { |i| i.abbv.casecmp(currency).zero? }&.symbol Settings.intntl.all_currencies.find { |i| i.abbv.casecmp(currency).zero? }&.symbol
end end
def user_registerable_as_admin
if user && user.roles.nonprofit_admins.any?
errors.add(:user_id, "cannot already be an admin for a nonprofit.")
end
end
private private
def build_admin_role def build_admin_role
role = user.roles.build(host: self, name: 'nonprofit_admin') role = user.roles.build(host: self, name: 'nonprofit_admin')
@ -244,4 +236,15 @@ private
b_sub = build_billing_subscription(billing_plan: billing_plan, status: 'active') b_sub = build_billing_subscription(billing_plan: billing_plan, status: 'active')
b_sub.save! b_sub.save!
end end
def user_registerable_as_admin
if user && user.roles.nonprofit_admins.any?
errors.add(:user_id, "cannot already be an admin for a nonprofit.")
end
end
def user_is_valid
(user && user.is_a?(User)) || errors.add(:user_id, "is not a valid user")
end
end end

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
json.id @nonprofit.id
json.name @nonprofit.name
json.city @nonprofit.city
json.state_code @nonprofit.state_code
json.zip_code @nonprofit.zip_code
json.state_code_slug @nonprofit.state_code_slug
json.city_slug @nonprofit.city_slug
json.slug @nonprofit.slug
json.email @nonprofit.email
json.website @nonprofit.website
json.phone @nonprofit.phone
json.urls do
json.plain_url nonprofit_url(@nonprofit)
json.slug_url nonprofit_slug_url(@nonprofit)
end

View file

@ -1,204 +0,0 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
require 'rails_helper'
describe 'HOUDINI NOnprofit_spec', type: :request do
describe 'get' do
end
describe 'post' do
around(:each) do |example|
@old_bp = Settings.default_bp
example.run
Settings.default_bp = @old_bp
end
def expect_validation_errors(actual, input)
expected_errors = input.with_indifferent_access[:errors]
expect(actual['errors']).to match_array expected_errors
end
def create_errors(*wrapper_params)
output = totally_empty_errors
wrapper_params.each { |i| output[:errors].push(h(params: [i], messages: gr_e('presence'))) }
output
end
def h(h = {})
h.with_indifferent_access
end
let(:totally_empty_errors) do
{
errors:
[
h(params: ['nonprofit[name]'], messages: gr_e('presence', 'blank')),
h(params: ['nonprofit[zip_code]'], messages: gr_e('presence', 'blank')),
h(params: ['nonprofit[state_code]'], messages: gr_e('presence', 'blank')),
h(params: ['nonprofit[city]'], messages: gr_e('presence', 'blank')),
h(params: ['user[name]'], messages: gr_e('presence', 'blank')),
h(params: ['user[email]'], messages: gr_e('presence', 'blank')),
h(params: ['user[password]'], messages: gr_e('presence', 'blank')),
h(params: ['user[password_confirmation]'], messages: gr_e('presence', 'blank'))
]
}.with_indifferent_access
end
describe 'authorization' do
around(:each) do |e|
Rails.configuration.action_controller.allow_forgery_protection = true
e.run
Rails.configuration.action_controller.allow_forgery_protection = false
end
it 'rejects csrf' do
post '/api/nonprofits', params: {}, xhr: true
expect(response.code).to eq '400'
end
end
it 'validates nothing' do
input = {}
post '/api/nonprofits', params: input, xhr: true
expect(response.code).to eq '400'
expect_validation_errors(JSON.parse(response.body), create_errors('nonprofit', 'user'))
end
it 'validates url, email, phone ' do
input = {
nonprofit: {
email: 'noemeila',
phone: 'notphone',
url: ''
}
}
post '/api/nonprofits', params: input, xhr: true
expect(response.code).to eq '400'
expected = create_errors('user')
expected[:errors].push(h(params: ['nonprofit[email]'], messages: gr_e('regexp')))
# expected[:errors].push(h(params:["nonprofit[phone]"], messages: gr_e("regexp")))
# expected[:errors].push(h(params:["nonprofit[url]"], messages: gr_e("regexp")))
expect_validation_errors(JSON.parse(response.body), expected)
end
it 'should reject unmatching passwords ' do
input = {
user: {
email: 'wmeil@email.com',
name: 'name',
password: 'password',
password_confirmation: 'doesn\'t match'
}
}
post '/api/nonprofits', params: input, xhr: true
expect(response.code).to eq '400'
expect(JSON.parse(response.body)['errors']).to include(h(params: ['user[password]', 'user[password_confirmation]'], messages: gr_e('is_equal_to')))
end
it 'attempts to make a slug copy and returns the proper errors' do
force_create(:nm_justice, slug: 'n', state_code_slug: 'wi', city_slug: 'appleton')
input = {
nonprofit: { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915 },
user: { name: 'Name', email: 'em@em.com', password: '12345678', password_confirmation: '12345678' }
}
expect_any_instance_of(SlugNonprofitNamingAlgorithm).to receive(:create_copy_name).and_raise(UnableToCreateNameCopyError.new)
post '/api/nonprofits', params: input, xhr: true
expect(response.code).to eq '400'
expect_validation_errors(JSON.parse(response.body),
errors: [
h(
params: ['nonprofit[name]'],
messages: ['has an invalid slug. Contact support for help.']
)
])
end
it 'errors on attempt to add user with email that already exists' do
force_create(:user, email: 'em@em.com')
input = {
nonprofit: { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915 },
user: { name: 'Name', email: 'em@em.com', password: '12345678', password_confirmation: '12345678' }
}
post '/api/nonprofits', params: input, xhr: true
expect(response.code).to eq '400'
expect_validation_errors(JSON.parse(response.body),
errors: [
h(
params: ['user[email]'],
messages: ['has already been taken']
)
])
end
it 'succeeds' do
force_create(:nm_justice, slug: 'n', state_code_slug: 'wi', city_slug: 'appleton')
input = {
nonprofit: { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915, url: 'www.cs.c', website: 'www.cs.c' },
user: { name: 'Name', email: 'em@em.com', password: '12345678', password_confirmation: '12345678' }
}
bp = force_create(:billing_plan)
Settings.default_bp.id = bp.id
# expect(Houdini::V1::Nonprofit).to receive(:sign_in)
post '/api/nonprofits', params: input, xhr: true
expect(response.code).to eq '201'
our_np = Nonprofit.all[1]
expected_np = {
name: 'n',
state_code: 'WI',
city: 'appleton',
zip_code: '54915',
state_code_slug: 'wi',
city_slug: 'appleton',
slug: 'n-00',
website: 'http://www.cs.c'
}.with_indifferent_access
expected_np = our_np.attributes.with_indifferent_access.merge(expected_np)
expect(our_np.attributes).to eq expected_np
expect(our_np.billing_subscription.billing_plan).to eq bp
response_body = {
id: our_np.id
}.with_indifferent_access
expect(JSON.parse(response.body)).to eq response_body
user = User.first
expected_user = {
email: 'em@em.com',
name: 'Name'
}
expected_user = user.attributes.with_indifferent_access.merge(expected_user)
expect(our_np.roles.nonprofit_admins.count).to eq 1
expect(our_np.roles.nonprofit_admins.first.user.attributes).to eq expected_user
end
end
end
def find_error_message(json, field_name)
errors = json['errors']
error = errors.select { |i| i['params'].any? { |j| j == field_name } }.first
return error unless error
error['messages']
end
def gr_e(*keys)
keys.map { |i| I18n.translate('grape.errors.messages.' + i, locale: 'en') }
end

View file

@ -1,172 +0,0 @@
# frozen_string_literal: true
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
require 'controllers/support/general_shared_user_context'
RSpec.shared_context :api_shared_user_verification do
include_context :general_shared_user_context
let(:user_as_np_admin) do
__create_admin(nonprofit)
end
let(:user_as_other_np_admin) do
__create_admin(other_nonprofit)
end
let(:user_as_np_associate) do
__create_associate(nonprofit)
end
let(:user_as_other_np_associate) do
__create_associate(other_nonprofit)
end
let(:unauth_user) do
force_create(:user)
end
let(:campaign_editor) do
__create(:campaign_editor, campaign)
end
let(:confirmed_user) do
force_create(:user, confirmed_at: Time.current)
end
let(:event_editor) do
__create(:event_editor, event)
end
let(:super_admin) do
__create(:super_admin, other_nonprofit)
end
let(:user_with_profile) do
u = force_create(:user)
force_create(:profile, user: u)
u
end
let(:all_users) do
{ user_as_np_admin: user_as_np_admin,
user_as_other_np_admin: user_as_other_np_admin,
user_as_np_associate: user_as_np_associate,
user_as_other_np_associate: user_as_other_np_associate,
unauth_user: unauth_user,
campaign_editor: campaign_editor,
event_editor: event_editor,
super_admin: super_admin,
user_with_profile: user_with_profile }
end
let(:roles__open_to_all) do
[nil, :user_as_np_admin,
:user_as_other_np_admin,
:user_as_np_associate,
:user_as_other_np_associate,
:unauth_user,
:campaign_editor,
:event_editor,
:super_admin,
:user_with_profile]
end
let(:roles__open_to_np_associate) do
%i[user_as_np_admin
user_as_np_associate
super_admin]
end
def __create(name, host)
u = force_create(:user)
force_create(:role, user: u, name: name, host: host)
u
end
def __create_admin(host)
u = force_create(:user)
force_create(:role, user: u, name: :nonprofit_admin, host: host)
u
end
def __create_associate(host)
u = force_create(:user)
force_create(:role, user: u, name: :nonprofit_associate, host: host)
u
end
def sign_in(user_to_signin)
post_via_redirect 'users/sign_in', 'user[email]' => user_to_signin.email, 'user[password]' => user_to_signin.password, format: 'json'
end
def sign_out
send(:get, 'users/sign_out')
end
def send(method, *args)
case method
when :get
xhr(:get, *args)
when :post
xhr(:post, *args)
when :delete
xhr(:delete, *args)
when :put
xhr(:put, *args)
end
end
def accept(user_to_signin:, method:, action:, args:)
new_user = user_to_signin
if !user_to_signin.nil? && user_to_signin.is_a?(OpenStruct)
new_user = user_to_signin.value
end
sign_in new_user if new_user
# allows us to run the helpers but ignore what the controller action does
#
send(method, action, args)
expect(response.status).to eq(200), "expcted success for user: #{(user_to_signin.is_a?(OpenStruct) ? user_to_signin.key.to_s + ':' : '')} #{new_user&.attributes}"
sign_out
end
def reject(user_to_signin:, method:, action:, args:)
new_user = user_to_signin
if !user_to_signin.nil? && user_to_signin.is_a?(OpenStruct)
new_user = user_to_signin.value
end
sign_in new_user if new_user
send(method, action, args)
expect(response.status).to eq(401), "expected failure for user: #{(user_to_signin.is_a?(OpenStruct) ? user_to_signin.key.to_s + ':' : '')} #{new_user&.attributes}"
sign_out
end
alias_method :redirects_to, :reject
def run_authorization_tests(details, &block)
@method = details[:method]
@successful_users = details[:successful_users]
@action = details[:action]
@block_to_get_arguments_to_run = block || ->(_) {} # no-op
accept_test_for_nil = false
all_users.each do |k, v|
os = OpenStruct.new
os.key = k
os.value = v
if k.nil?
accept(user_to_signin: nil, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(v))
accept_test_for_nil = true
end
if @successful_users.include? k
accept(user_to_signin: os, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(v))
else
reject(user_to_signin: os, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(v))
end
end
unless accept_test_for_nil
reject(user_to_signin: nil, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(nil))
end
end
end

View file

@ -9,115 +9,35 @@ describe Api::NonprofitsController, type: :request do
role role
end end
let(:nonprofit) {create(:nm_justice)} let(:nonprofit) {create(:nm_justice)}
describe 'get' do describe 'get' do
end end
describe 'post' do describe 'create' do
around(:each) do |example| around(:each) do |example|
@old_bp = Settings.default_bp @old_bp = Settings.default_bp
example.run example.run
Settings.default_bp = @old_bp Settings.default_bp = @old_bp
end end
def expect_validation_errors(actual, input)
expected_errors = input.with_indifferent_access[:errors]
expect(actual['errors']).to match_array expected_errors
end
def create_errors(*wrapper_params) it 'validates and returns correct errors' do
output = totally_empty_errors
wrapper_params.each { |i| output[:errors].push(h(params: [i], messages: gr_e('presence'))) }
output
end
def h(h = {})
h.with_indifferent_access
end
describe 'authorization' do
around(:each) do |e|
Rails.configuration.action_controller.allow_forgery_protection = true
e.run
Rails.configuration.action_controller.allow_forgery_protection = false
end
it 'rejects csrf' do
post :create, params: {}, xhr: true
expect(response.code).to eq '400'
end
end
it 'validates nothing' do
input = {} input = {}
post '/api/nonprofits', params: input, xhr: true post '/api/nonprofits', params: input, xhr: true
expect(response).to have_http_status :unprocessable_entity expect(response).to have_http_status :unprocessable_entity
expect(response.parsed_body['errors'].keys).to match_array ['name', 'city', 'state_code', 'slug', 'user'] expect(response.parsed_body['errors'].keys).to match_array ['name', 'city', 'state_code', 'slug', 'user_id']
end
it 'validates url, email, phone ' do
input = {
nonprofit: {
email: 'noemeila',
phone: 'notphone',
url: ''
}
}
post :create, params: input, xhr: true
expect(response.code).to eq '400'
expected = create_errors('user')
expected[:errors].push(h(params: ['nonprofit[email]'], messages: gr_e('regexp')))
# expected[:errors].push(h(params:["nonprofit[phone]"], messages: gr_e("regexp")))
# expected[:errors].push(h(params:["nonprofit[url]"], messages: gr_e("regexp")))
expect_validation_errors(JSON.parse(response.body), expected)
end
it 'attempts to make a slug copy and returns the proper errors' do
force_create(:nonprofit, slug: 'n', state_code_slug: 'wi', city_slug: 'appleton')
input = {
nonprofit: { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915 },
user: { name: 'Name', email: 'em@em.com', password: '12345678', password_confirmation: '12345678' }
}
expect_any_instance_of(SlugNonprofitNamingAlgorithm).to receive(:create_copy_name).and_raise(UnableToCreateNameCopyError.new)
post :create, params: input, xhr: true
expect(response.code).to eq '400'
expect_validation_errors(JSON.parse(response.body),
errors: [
h(
params: ['nonprofit[name]'],
messages: ['has an invalid slug. Contact support for help.']
)
])
end
it 'errors on attempt to add the user to a second nonprofit' do
nonprofit_admin_role
input = { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915, user_id: user.id }
post '/api/nonprofits', params: input, xhr:true
expect(response).to have_http_status :unprocessable_entity
expect(response.parsed_body['errors'].keys).to match_array 'user'
byebug
expect(response.parsed_body['errors']['user'].first).to has_include? 'nonprofit admin'
end end
it 'succeeds' do it 'succeeds' do
force_create(:nonprofit, slug: 'n', state_code_slug: 'wi', city_slug: 'appleton') input = { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915, user_id: user.id, phone: '920-555-5555' }
input = { sign_in user
nonprofit: { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915, url: 'www.cs.c', website: 'www.cs.c' },
user: { name: 'Name', email: 'em@em.com', password: '12345678', password_confirmation: '12345678' }
}
bp = force_create(:billing_plan) bp = force_create(:billing_plan)
Settings.default_bp.id = bp.id Settings.default_bp.id = bp.id
# expect(Houdini::V1::Nonprofit).to receive(:sign_in) sign_in user
post :create, params: input, xhr: true post '/api/nonprofits', params: input, xhr: true
expect(response.code).to eq '201' expect(response).to have_http_status :created
our_np = Nonprofit.all[1]
expected_np = { expected_np = {
name: 'n', name: 'n',
state_code: 'WI', state_code: 'WI',
@ -125,45 +45,17 @@ describe Api::NonprofitsController, type: :request do
zip_code: '54915', zip_code: '54915',
state_code_slug: 'wi', state_code_slug: 'wi',
city_slug: 'appleton', city_slug: 'appleton',
slug: 'n-00', slug: 'n',
website: 'http://www.cs.c' phone: '920-555-5555',
email: nil,
website: nil,
urls: {plain_url: "http://www.example.com/nonprofits/1", slug_url: "http://www.example.com/wi/appleton/n"}
}.with_indifferent_access }.with_indifferent_access
expected_np = our_np.attributes.with_indifferent_access.merge(expected_np) expect(response.parsed_body['id']).to be > 0
expect(our_np.attributes).to eq expected_np expect(response.parsed_body.except('id')).to eq expected_np
expect(our_np.billing_subscription.billing_plan).to eq bp
response_body = {
id: our_np.id
}.with_indifferent_access
expect(JSON.parse(response.body)).to eq response_body
user = User.first
expected_user = {
email: 'em@em.com',
name: 'Name'
}
expected_user = user.attributes.with_indifferent_access.merge(expected_user)
expect(our_np.roles.nonprofit_admins.count).to eq 1
expect(our_np.roles.nonprofit_admins.first.user.attributes).to eq expected_user
end end
end end
end end
def find_error_message(json, field_name)
errors = json['errors']
error = errors.select { |i| i['params'].any? { |j| j == field_name } }.first
return error unless error
error['messages']
end
def gr_e(*keys)
keys.map { |i| I18n.translate('grape.errors.messages.' + i, locale: 'en') }
end

View file

@ -53,6 +53,8 @@ RSpec.describe Nonprofit, type: :model do
let(:nonprofit_with_same_name) { Nonprofit.new({name: "New Mexico Equality", state_code: nm_justice.state_code, city: nm_justice.city, user_id: user.id})} let(:nonprofit_with_same_name) { Nonprofit.new({name: "New Mexico Equality", state_code: nm_justice.state_code, city: nm_justice.city, user_id: user.id})}
let(:nonprofit_with_same_name_but_different_state) { Nonprofit.new({name: "New Mexico Equality", state_code: 'mn', city: nm_justice.city, user_id: user.id })} let(:nonprofit_with_same_name_but_different_state) { Nonprofit.new({name: "New Mexico Equality", state_code: 'mn', city: nm_justice.city, user_id: user.id })}
let(:nonprofit_with_bad_email_and_website) { Nonprofit.new({email: 'not_email', website: 'not_website'})}
let(:user) { create(:user)} let(:user) { create(:user)}
let(:nonprofit_admin_role) do let(:nonprofit_admin_role) do
role = user.roles.build(host: nonprofit, name: 'nonprofit_admin') role = user.roles.build(host: nonprofit, name: 'nonprofit_admin')
@ -61,7 +63,15 @@ RSpec.describe Nonprofit, type: :model do
end end
let(:nm_justice) {create(:nm_justice)} let(:nm_justice) {create(:nm_justice)}
before(:each) { nonprofit.valid?; nonprofit_with_invalid_user.valid?; nonprofit_with_user_who_already_admin.valid?; nonprofit_with_same_name.valid?; nonprofit_with_same_name_but_different_state.valid?} before(:each) do
nonprofit.valid?
nonprofit_with_invalid_user.valid?
nonprofit_with_user_who_already_admin.valid?
nonprofit_with_same_name.valid?
nonprofit_with_same_name_but_different_state.valid?
nonprofit_with_bad_email_and_website.valid?
end
it 'has an error for no name' do it 'has an error for no name' do
expect(nonprofit.errors['name'].first).to match /.*blank.*/ expect(nonprofit.errors['name'].first).to match /.*blank.*/
end end
@ -91,10 +101,25 @@ RSpec.describe Nonprofit, type: :model do
expect(nonprofit_with_same_name.slug).to eq "#{nm_justice.slug}-00" expect(nonprofit_with_same_name.slug).to eq "#{nm_justice.slug}-00"
end end
it 'does nothing to a slug when it tries to save' do it 'does nothing to a slug when a slug was provided' do
expect(nonprofit_with_same_name_but_different_state.errors['slug']).to be_empty expect(nonprofit_with_same_name_but_different_state.errors['slug']).to be_empty
expect(nonprofit_with_same_name_but_different_state.slug).to eq "#{nm_justice.slug}" expect(nonprofit_with_same_name_but_different_state.slug).to eq "#{nm_justice.slug}"
end end
it 'marks email as having errors if they do' do
expect(nonprofit_with_bad_email_and_website.errors['email'].first).to match /.*invalid.*/
end
it 'marks website as having errors if they do' do
expect(nonprofit_with_bad_email_and_website.errors['website'].first).to match /.*invalid.*/
end
it 'marks an nonprofit as invalid when no slug could be created ' do
nonprofit = Nonprofit.new({name: nm_justice.name, city: nm_justice.city, state_code: nm_justice.state_code, slug: nm_justice.slug})
expect_any_instance_of(SlugNonprofitNamingAlgorithm).to receive(:create_copy_name).and_raise(UnableToCreateNameCopyError.new)
nonprofit.valid?
expect(nonprofit.errors['slug'].first).to match /.*could not be created.*/
end
end end
end end
end end

View file

@ -70,5 +70,6 @@ RSpec.configure do |config|
# arbitrary gems may also be filtered via: # arbitrary gems may also be filtered via:
# config.filter_gems_from_backtrace("gem name") # config.filter_gems_from_backtrace("gem name")
config.include Devise::Test::ControllerHelpers, type: :controller config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::IntegrationHelpers, type: :request
config.include RSpec::Rails::RequestExampleGroup, type: :request, file_path: %r{spec/api} config.include RSpec::Rails::RequestExampleGroup, type: :request, file_path: %r{spec/api}
end end