Browse Source

Merge branch 'main' into CLDC-764/PageTitlesErrorPrefix

pull/145/head
Matthew Phelan 3 years ago
parent
commit
8c12ed5da9
  1. 7
      Gemfile
  2. 17
      Gemfile.lock
  3. 6
      app/controllers/bulk_upload_controller.rb
  4. 94
      app/controllers/case_logs_controller.rb
  5. 83
      app/controllers/form_controller.rb
  6. 9
      app/controllers/organisations_controller.rb
  7. 2
      app/controllers/soft_validations_controller.rb
  8. 16
      app/controllers/users_controller.rb
  9. 6
      app/models/bulk_upload.rb
  10. 11
      app/models/case_log.rb
  11. 42
      app/models/constants/case_log.rb
  12. 6
      app/models/constants/organisation.rb
  13. 2
      app/models/organisation.rb
  14. 2
      app/models/validations/household_validations.rb
  15. 2
      config/forms/2021_2022.json
  16. 6
      config/routes.rb
  17. 15
      docs/adr/adr-012-controller-http-return-statuses.md
  18. 172
      spec/controllers/case_logs_controller_spec.rb
  19. 2
      spec/factories/case_log.rb
  20. 2
      spec/fixtures/complete_case_log.json
  21. 24
      spec/models/case_log_spec.rb
  22. 91
      spec/requests/bulk_upload_controller_spec.rb
  23. 200
      spec/requests/case_log_controller_spec.rb
  24. 278
      spec/requests/form_controller_spec.rb
  25. 233
      spec/requests/organisations_controller_spec.rb
  26. 57
      spec/requests/soft_validations_controller_spec.rb
  27. 129
      spec/requests/user_controller_spec.rb

7
Gemfile

@ -15,9 +15,9 @@ gem "puma", "~> 5.0"
gem "webpacker", "~> 5.0" gem "webpacker", "~> 5.0"
# Reduces boot times through caching; required in config/boot.rb # Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", ">= 1.4.4", require: false gem "bootsnap", ">= 1.4.4", require: false
# Gov.UK frontend components # GOV UK frontend components
gem "govuk-components" gem "govuk-components"
# Gov.UK component form builder DSL # GOV UK component form builder DSL
gem "govuk_design_system_formbuilder" gem "govuk_design_system_formbuilder"
# Turbo & Stimulus # Turbo & Stimulus
gem "hotwire-rails" gem "hotwire-rails"
@ -34,8 +34,9 @@ gem "json-schema"
# Authentication # Authentication
# Point at branch until devise is compatible with Turbo, see https://github.com/heartcombo/devise/pull/5340 # Point at branch until devise is compatible with Turbo, see https://github.com/heartcombo/devise/pull/5340
gem "devise", github: "ghiculescu/devise", branch: "error-code-422" gem "devise", github: "ghiculescu/devise", branch: "error-code-422"
gem "turbo-rails", "~> 0.8" # UK postcode parsing and validation
gem "uk_postcode" gem "uk_postcode"
# Use Ruby objects to build reusable markup. A React inspired evolution of the presenter pattern
gem "view_component" gem "view_component"
group :development, :test do group :development, :test do

17
Gemfile.lock

@ -38,7 +38,7 @@ GIT
GIT GIT
remote: https://github.com/rspec/rspec-rails.git remote: https://github.com/rspec/rspec-rails.git
revision: 1fe6c2e8a56f46ae4c2f13ffa0733cce3b717c2d revision: 5f54d780a3d8f21cfe4f424a7d0435be2e279356
branch: main branch: main
specs: specs:
rspec-rails (5.1.0.pre) rspec-rails (5.1.0.pre)
@ -52,7 +52,7 @@ GIT
GIT GIT
remote: https://github.com/rspec/rspec-support.git remote: https://github.com/rspec/rspec-support.git
revision: 9499cb622f9feef43a53f357809f9e656e7cb6de revision: 321dc7227df43cd682c293fa31fa427b94b2ea74
branch: main branch: main
specs: specs:
rspec-support (3.11.0.pre) rspec-support (3.11.0.pre)
@ -178,13 +178,13 @@ GEM
formtastic (4.0.0) formtastic (4.0.0)
actionpack (>= 5.2.0) actionpack (>= 5.2.0)
formtastic_i18n (0.7.0) formtastic_i18n (0.7.0)
globalid (0.6.0) globalid (1.0.0)
activesupport (>= 5.0) activesupport (>= 5.0)
govuk-components (2.1.4) govuk-components (2.1.5)
activemodel (>= 6.0) activemodel (>= 6.0)
railties (>= 6.0) railties (>= 6.0)
view_component (~> 2.39.0) view_component (~> 2.39.0)
govuk_design_system_formbuilder (2.7.6) govuk_design_system_formbuilder (2.8.0)
actionview (>= 6.0) actionview (>= 6.0)
activemodel (>= 6.0) activemodel (>= 6.0)
activesupport (>= 6.0) activesupport (>= 6.0)
@ -249,7 +249,7 @@ GEM
iniparse (~> 1.4) iniparse (~> 1.4)
rexml (~> 3.2) rexml (~> 3.2)
parallel (1.21.0) parallel (1.21.0)
parser (3.0.2.0) parser (3.0.3.1)
ast (~> 2.4.1) ast (~> 2.4.1)
pg (1.2.3) pg (1.2.3)
pry (0.13.1) pry (0.13.1)
@ -304,7 +304,7 @@ GEM
rb-fsevent (0.11.0) rb-fsevent (0.11.0)
rb-inotify (0.10.1) rb-inotify (0.10.1)
ffi (~> 1.0) ffi (~> 1.0)
regexp_parser (2.1.1) regexp_parser (2.2.0)
responders (3.0.1) responders (3.0.1)
actionpack (>= 5.0) actionpack (>= 5.0)
railties (>= 5.0) railties (>= 5.0)
@ -377,7 +377,7 @@ GEM
rails (>= 6.0.0) rails (>= 6.0.0)
tzinfo (2.0.4) tzinfo (2.0.4)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
uk_postcode (2.1.6) uk_postcode (2.1.7)
unicode-display_width (2.1.0) unicode-display_width (2.1.0)
view_component (2.39.0) view_component (2.39.0)
activesupport (>= 5.0.0, < 8.0) activesupport (>= 5.0.0, < 8.0)
@ -441,7 +441,6 @@ DEPENDENCIES
scss_lint-govuk scss_lint-govuk
selenium-webdriver selenium-webdriver
simplecov simplecov
turbo-rails (~> 0.8)
tzinfo-data tzinfo-data
uk_postcode uk_postcode
view_component view_component

6
app/controllers/bulk_upload_controller.rb

@ -1,4 +1,6 @@
class BulkUploadController < ApplicationController class BulkUploadController < ApplicationController
before_action :authenticate_user!
def show def show
@bulk_upload = BulkUpload.new(nil, nil) @bulk_upload = BulkUpload.new(nil, nil)
render "case_logs/bulk_upload" render "case_logs/bulk_upload"
@ -8,7 +10,7 @@ class BulkUploadController < ApplicationController
file = upload_params.tempfile file = upload_params.tempfile
content_type = upload_params.content_type content_type = upload_params.content_type
@bulk_upload = BulkUpload.new(file, content_type) @bulk_upload = BulkUpload.new(file, content_type)
@bulk_upload.process @bulk_upload.process(current_user)
if @bulk_upload.errors.present? if @bulk_upload.errors.present?
render "case_logs/bulk_upload", status: :unprocessable_entity render "case_logs/bulk_upload", status: :unprocessable_entity
else else
@ -16,6 +18,8 @@ class BulkUploadController < ApplicationController
end end
end end
private
def upload_params def upload_params
params.require("bulk_upload")["case_log_bulk_upload"] params.require("bulk_upload")["case_log_bulk_upload"]
end end

94
app/controllers/case_logs_controller.rb

@ -2,6 +2,7 @@ class CaseLogsController < ApplicationController
skip_before_action :verify_authenticity_token, if: :json_api_request? skip_before_action :verify_authenticity_token, if: :json_api_request?
before_action :authenticate, if: :json_api_request? before_action :authenticate, if: :json_api_request?
before_action :authenticate_user!, unless: :json_api_request? before_action :authenticate_user!, unless: :json_api_request?
before_action :find_resource, except: %i[create index edit]
def index def index
@completed_case_logs = current_user.completed_case_logs @completed_case_logs = current_user.completed_case_logs
@ -23,11 +24,11 @@ class CaseLogsController < ApplicationController
end end
def update def update
if (case_log = CaseLog.find_by(id: params[:id])) if @case_log
if case_log.update(api_case_log_params) if @case_log.update(api_case_log_params)
render json: case_log, status: :ok render json: @case_log, status: :ok
else else
render json: { errors: case_log.errors.messages }, status: :unprocessable_entity render json: { errors: @case_log.errors.messages }, status: :unprocessable_entity
end end
else else
render_not_found_json("Case log", params[:id]) render_not_found_json("Case log", params[:id])
@ -39,8 +40,8 @@ class CaseLogsController < ApplicationController
# We don't have a dedicated non-editable show view # We don't have a dedicated non-editable show view
format.html { edit } format.html { edit }
format.json do format.json do
if (case_log = CaseLog.find_by(id: params[:id])) if @case_log
render json: case_log, status: :ok render json: @case_log, status: :ok
else else
render_not_found_json("Case log", params[:id]) render_not_found_json("Case log", params[:id])
end end
@ -58,93 +59,22 @@ class CaseLogsController < ApplicationController
end end
end end
def submit_form
form = FormHandler.instance.get_form("2021_2022")
@case_log = current_user.case_logs.find_by(id: params[:id])
if @case_log
page = form.get_page(params[:case_log][:page])
responses_for_page = responses_for_page(page)
if @case_log.update(responses_for_page) && @case_log.has_no_unresolved_soft_errors?
redirect_path = form.next_page_redirect_path(page, @case_log)
redirect_to(send(redirect_path, @case_log))
else
subsection = form.subsection_for_page(page)
render "form/page", locals: { form: form, page: page, subsection: subsection.label }, status: :unprocessable_entity
end
else
render_not_found_html
end
end
def destroy def destroy
if (case_log = CaseLog.find_by(id: params[:id])) if @case_log
if case_log.discard if @case_log.discard
head :no_content head :no_content
else else
render json: { errors: case_log.errors.messages }, status: :unprocessable_entity render json: { errors: @case_log.errors.messages }, status: :unprocessable_entity
end end
else else
render_not_found_json("Case log", params[:id]) render_not_found_json("Case log", params[:id])
end end
end end
def check_answers
form = FormHandler.instance.get_form("2021_2022")
@case_log = current_user.case_logs.find_by(id: params[:case_log_id])
if @case_log
current_url = request.env["PATH_INFO"]
subsection = form.get_subsection(current_url.split("/")[-2])
render "form/check_answers", locals: { subsection: subsection, form: form }
else
render_not_found_html
end
end
form = FormHandler.instance.get_form("2021_2022")
form.pages.map do |page|
define_method(page.id) do |_errors = {}|
@case_log = current_user.case_logs.find_by(id: params[:case_log_id])
if @case_log
subsection = form.subsection_for_page(page)
render "form/page", locals: { form: form, page: page, subsection: subsection.label }
else
render_not_found_html
end
end
end
private private
API_ACTIONS = %w[create show update destroy].freeze API_ACTIONS = %w[create show update destroy].freeze
def responses_for_page(page)
page.expected_responses.each_with_object({}) do |question, result|
question_params = params["case_log"][question.id]
if question.type == "date"
day = params["case_log"]["#{question.id}(3i)"]
month = params["case_log"]["#{question.id}(2i)"]
year = params["case_log"]["#{question.id}(1i)"]
next unless [day, month, year].any?(&:present?)
result[question.id] = if day.to_i.between?(1, 31) && month.to_i.between?(1, 12) && year.to_i.between?(2000, 2200)
Date.new(year.to_i, month.to_i, day.to_i)
else
Date.new(0, 1, 1)
end
end
next unless question_params
if %w[checkbox validation_override].include?(question.type)
question.answer_options.keys.reject { |x| x.match(/divider/) }.each do |option|
result[option] = question_params.include?(option) ? 1 : 0
end
else
result[question.id] = question_params
end
result
end
end
def json_api_request? def json_api_request?
API_ACTIONS.include?(request["action"]) && request.format.json? API_ACTIONS.include?(request["action"]) && request.format.json?
end end
@ -173,4 +103,8 @@ private
params.require(:case_log).permit(CaseLog.editable_fields) params.require(:case_log).permit(CaseLog.editable_fields)
end end
def find_resource
@case_log = CaseLog.find_by(id: params[:id])
end
end end

83
app/controllers/form_controller.rb

@ -0,0 +1,83 @@
class FormController < ApplicationController
before_action :authenticate_user!
before_action :find_resource, only: [:submit_form]
before_action :find_resource_by_named_id, except: [:submit_form]
def submit_form
form = FormHandler.instance.get_form("2021_2022")
if @case_log
page = form.get_page(params[:case_log][:page])
responses_for_page = responses_for_page(page)
if @case_log.update(responses_for_page) && @case_log.has_no_unresolved_soft_errors?
redirect_path = form.next_page_redirect_path(page, @case_log)
redirect_to(send(redirect_path, @case_log))
else
subsection = form.subsection_for_page(page)
render "form/page", locals: { form: form, page: page, subsection: subsection.label }, status: :unprocessable_entity
end
else
render_not_found_html
end
end
def check_answers
form = FormHandler.instance.get_form("2021_2022")
if @case_log
current_url = request.env["PATH_INFO"]
subsection = form.get_subsection(current_url.split("/")[-2])
render "form/check_answers", locals: { subsection: subsection, form: form }
else
render_not_found_html
end
end
form = FormHandler.instance.get_form("2021_2022")
form.pages.map do |page|
define_method(page.id) do |_errors = {}|
if @case_log
subsection = form.subsection_for_page(page)
render "form/page", locals: { form: form, page: page, subsection: subsection.label }
else
render_not_found_html
end
end
end
private
def responses_for_page(page)
page.expected_responses.each_with_object({}) do |question, result|
question_params = params["case_log"][question.id]
if question.type == "date"
day = params["case_log"]["#{question.id}(3i)"]
month = params["case_log"]["#{question.id}(2i)"]
year = params["case_log"]["#{question.id}(1i)"]
next unless [day, month, year].any?(&:present?)
result[question.id] = if day.to_i.between?(1, 31) && month.to_i.between?(1, 12) && year.to_i.between?(2000, 2200)
Date.new(year.to_i, month.to_i, day.to_i)
else
Date.new(0, 1, 1)
end
end
next unless question_params
if %w[checkbox validation_override].include?(question.type)
question.answer_options.keys.reject { |x| x.match(/divider/) }.each do |option|
result[option] = question_params.include?(option) ? 1 : 0
end
else
result[question.id] = question_params
end
result
end
end
def find_resource
@case_log = current_user.case_logs.find_by(id: params[:id])
end
def find_resource_by_named_id
@case_log = current_user.case_logs.find_by(id: params[:case_log_id])
end
end

9
app/controllers/organisations_controller.rb

@ -1,6 +1,7 @@
class OrganisationsController < ApplicationController class OrganisationsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action :find_organisation before_action :find_resource
before_action :authenticate_scope!
def show def show
redirect_to details_organisation_path(@organisation) redirect_to details_organisation_path(@organisation)
@ -20,7 +21,11 @@ class OrganisationsController < ApplicationController
private private
def find_organisation def authenticate_scope!
head :not_found if current_user.organisation != @organisation
end
def find_resource
@organisation = Organisation.find(params[:id]) @organisation = Organisation.find(params[:id])
end end
end end

2
app/controllers/soft_validations_controller.rb

@ -1,4 +1,6 @@
class SoftValidationsController < ApplicationController class SoftValidationsController < ApplicationController
before_action :authenticate_user!
def show def show
@case_log = CaseLog.find(params[:case_log_id]) @case_log = CaseLog.find(params[:case_log_id])
page_id = request.env["PATH_INFO"].split("/")[-2] page_id = request.env["PATH_INFO"].split("/")[-2]

16
app/controllers/users_controller.rb

@ -2,12 +2,14 @@ class UsersController < ApplicationController
include Devise::Controllers::SignInOut include Devise::Controllers::SignInOut
include Helpers::Email include Helpers::Email
before_action :authenticate_user! before_action :authenticate_user!
before_action :find_resource, except: %i[new create]
before_action :authenticate_scope!, except: %i[new create]
def update def update
if current_user.update(user_params) if @user.update(user_params)
bypass_sign_in current_user bypass_sign_in @user
flash[:notice] = I18n.t("devise.passwords.updated") flash[:notice] = I18n.t("devise.passwords.updated")
redirect_to user_path(current_user) redirect_to user_path(@user)
end end
end end
@ -48,4 +50,12 @@ private
def user_params def user_params
params.require(:user).permit(:email, :name, :password, :role) params.require(:user).permit(:email, :name, :password, :role)
end end
def find_resource
@user = User.find(params[:id])
end
def authenticate_scope!
head :not_found if current_user != @user
end
end end

6
app/models/bulk_upload.rb

@ -15,7 +15,7 @@ class BulkUpload
@content_type = content_type @content_type = content_type
end end
def process def process(current_user)
return unless valid_content_type? return unless valid_content_type?
xlsx = Roo::Spreadsheet.open(@file, extension: :xlsx) xlsx = Roo::Spreadsheet.open(@file, extension: :xlsx)
@ -30,8 +30,8 @@ class BulkUpload
owning_organisation = Organisation.find(row[111]) owning_organisation = Organisation.find(row[111])
managing_organisation = Organisation.find(row[113]) managing_organisation = Organisation.find(row[113])
case_log = CaseLog.create!( case_log = CaseLog.create!(
owning_organisation: owning_organisation, owning_organisation: current_user.organisation,
managing_organisation: managing_organisation, managing_organisation: current_user.organisation,
) )
map_row(row).each do |attr_key, attr_val| map_row(row).each do |attr_key, attr_val|
update = case_log.update(attr_key => attr_val) update = case_log.update(attr_key => attr_val)

11
app/models/case_log.rb

@ -30,7 +30,7 @@ end
class CaseLog < ApplicationRecord class CaseLog < ApplicationRecord
include Discard::Model include Discard::Model
include Validations::SoftValidations include Validations::SoftValidations
include Constants::DbEnums include Constants::CaseLog
include Constants::IncomeRanges include Constants::IncomeRanges
default_scope -> { kept } default_scope -> { kept }
@ -156,15 +156,6 @@ class CaseLog < ApplicationRecord
private private
RENT_TYPE_MAPPING = {
"Social Rent" => "Social Rent",
"Affordable Rent" => "Affordable Rent",
"London Affordable Rent" => "Affordable Rent",
"Rent To Buy" => "Intermediate Rent",
"London Living Rent" => "Intermediate Rent",
"Other Intermediate Rent Product" => "Intermediate Rent",
}.freeze
def update_status! def update_status!
self.status = if all_fields_completed? && errors.empty? self.status = if all_fields_completed? && errors.empty?
"completed" "completed"

42
app/models/constants/db_enums.rb → app/models/constants/case_log.rb

@ -1,4 +1,4 @@
module Constants::DbEnums module Constants::CaseLog
BENEFITCAP = { BENEFITCAP = {
"Yes - benefit cap" => 5, "Yes - benefit cap" => 5,
"Yes - removal of the spare room subsidy" => 4, "Yes - removal of the spare room subsidy" => 4,
@ -672,27 +672,31 @@ module Constants::DbEnums
}.freeze }.freeze
NEEDS_TYPE = { NEEDS_TYPE = {
"General Needs" => 1, "General needs" => 1,
"Supported Housing" => 2, "Supported housing" => 2,
}.freeze }.freeze
ORG_TYPE = { LET_TYPE = {
"LA" => 1, "Social Rent General needs PRP" => 1,
"PRP" => 2, "Social Rent Supported housing PRP" => 2,
"Social Rent General needs LA" => 3,
"Social Rent Supported housing LA" => 4,
"Affordable Rent General needs PRP" => 5,
"Affordable Rent Supported housing PRP" => 6,
"Affordable Rent General needs LA" => 7,
"Affordable Rent Supported housing LA" => 8,
"Intermediate Rent General needs PRP" => 9,
"Intermediate Rent Supported housing PRP" => 10,
"Intermediate Rent General needs LA" => 11,
"Intermediate Rent Supported housing LA" => 12,
}.freeze }.freeze
LET_TYPE = { RENT_TYPE_MAPPING = {
"Social Rent General Needs PRP" => 1, "Social rent" => "Social Rent",
"Social Rent Supported Housing PRP" => 2, "Affordable rent" => "Affordable Rent",
"Social Rent General Needs LA" => 3, "London Affordable rent" => "Affordable Rent",
"Social Rent Supported Housing LA" => 4, "Rent to buy" => "Intermediate Rent",
"Affordable Rent General Needs PRP" => 5, "London living rent" => "Intermediate Rent",
"Affordable Rent Supported Housing PRP" => 6, "Other intermediate rent product" => "Intermediate Rent",
"Affordable Rent General Needs LA" => 7,
"Affordable Rent Supported Housing LA" => 8,
"Intermediate Rent General Needs PRP" => 9,
"Intermediate Rent Supported Housing PRP" => 10,
"Intermediate Rent General Needs LA" => 11,
"Intermediate Rent Supported Housing LA" => 12,
}.freeze }.freeze
end end

6
app/models/constants/organisation.rb

@ -0,0 +1,6 @@
module Constants::Organisation
ORG_TYPE = {
"LA" => 1,
"PRP" => 2,
}.freeze
end

2
app/models/organisation.rb

@ -3,7 +3,7 @@ class Organisation < ApplicationRecord
has_many :owned_case_logs, class_name: "CaseLog", foreign_key: "owning_organisation_id" has_many :owned_case_logs, class_name: "CaseLog", foreign_key: "owning_organisation_id"
has_many :managed_case_logs, class_name: "CaseLog", foreign_key: "managing_organisation_id" has_many :managed_case_logs, class_name: "CaseLog", foreign_key: "managing_organisation_id"
include Constants::DbEnums include Constants::Organisation
enum "Org type": ORG_TYPE, _suffix: true enum "Org type": ORG_TYPE, _suffix: true
def case_logs def case_logs

2
app/models/validations/household_validations.rb

@ -76,7 +76,7 @@ module Validations::HouseholdValidations
def validate_shared_housing_rooms(record) def validate_shared_housing_rooms(record)
unless record.unittype_gn.nil? unless record.unittype_gn.nil?
if record.unittype_gn == "Bed-sit" && record.beds != 1 if record.unittype_gn == "Bed-sit" && record.beds != 1 && record.beds.present?
record.errors.add :unittype_gn, "A bedsit can only have one bedroom" record.errors.add :unittype_gn, "A bedsit can only have one bedroom"
end end

2
config/forms/2021_2022.json

@ -1668,7 +1668,7 @@
"step": 1 "step": 1
} }
}, },
"depends_on": { "needstype": "General Needs" } "depends_on": { "needstype": "General needs" }
}, },
"void_or_renewal_date": { "void_or_renewal_date": {
"header": "", "header": "",

6
config/routes.rb

@ -38,16 +38,16 @@ Rails.application.routes.draw do
end end
member do member do
post "form", to: "case_logs#submit_form" post "form", to: "form#submit_form"
end end
form.pages.map do |page| form.pages.map do |page|
get page.id.to_s.dasherize, to: "case_logs##{page.id}" get page.id.to_s.dasherize, to: "form##{page.id}"
get "#{page.id.to_s.dasherize}/soft-validations", to: "soft_validations#show" if page.has_soft_validations? get "#{page.id.to_s.dasherize}/soft-validations", to: "soft_validations#show" if page.has_soft_validations?
end end
form.subsections.map do |subsection| form.subsections.map do |subsection|
get "#{subsection.id.to_s.dasherize}/check-answers", to: "case_logs#check_answers" get "#{subsection.id.to_s.dasherize}/check-answers", to: "form#check_answers"
end end
end end
end end

15
docs/adr/adr-012-controller-http-return-statuses.md

@ -0,0 +1,15 @@
### ADR - 012: Controller HTTP return statuses
Controllers assess authentication by 3 criteria:
1. Are you signed in at all?
2. Are you signed in and requesting an action that your role/user type has access to?
3. Are you signed in, requesting an action that your role/user type has access to and requesting a resource that your user has access to.
When these aren't met they fail with the following response types:
1. 401: Unauthorized. Redirect to sign-in page.
2. 401: Unauthorized
3. 404: Not found.
This helps make it harder to determine whether a resource exists or not just by enumerating ids.

172
spec/controllers/case_logs_controller_spec.rb

@ -1,172 +0,0 @@
require "rails_helper"
RSpec.describe CaseLogsController, type: :controller do
let(:valid_session) { {} }
let(:user) { FactoryBot.create(:user) }
let(:case_log) do
FactoryBot.create(
:case_log,
owning_organisation: user.organisation,
managing_organisation: user.organisation,
)
end
let(:id) { case_log.id }
before do
sign_in user
end
context "Collection routes" do
describe "GET #index" do
it "returns a success response" do
get :index, params: {}, session: valid_session
expect(response).to be_successful
end
end
describe "Post #create" do
let(:owning_organisation) { FactoryBot.create(:organisation) }
let(:managing_organisation) { owning_organisation }
let(:params) do
{
"owning_organisation_id": owning_organisation.id,
"managing_organisation_id": managing_organisation.id,
}
end
it "creates a new case log record" do
expect {
post :create, params: params, session: valid_session
}.to change(CaseLog, :count).by(1)
end
it "redirects to that case log" do
post :create, params: params, session: valid_session
expect(response.status).to eq(302)
end
end
end
context "Instance routes" do
describe "GET #show" do
it "returns a success response" do
get :show, params: { id: id }
expect(response).to be_successful
end
end
describe "GET #edit" do
it "returns a success response" do
get :edit, params: { id: id }
expect(response).to be_successful
end
end
end
describe "submit_form" do
let(:case_log_form_params) do
{ accessibility_requirements:
%w[ housingneeds_a
housingneeds_b
housingneeds_c],
page: "accessibility_requirements" }
end
let(:new_case_log_form_params) do
{
accessibility_requirements: %w[housingneeds_c],
page: "accessibility_requirements",
}
end
it "sets checked items to true" do
post :submit_form, params: { id: id, case_log: case_log_form_params }
case_log.reload
expect(case_log.housingneeds_a).to eq("Yes")
expect(case_log.housingneeds_b).to eq("Yes")
expect(case_log.housingneeds_c).to eq("Yes")
end
it "sets previously submitted items to false when resubmitted with new values" do
post :submit_form, params: { id: id, case_log: new_case_log_form_params }
case_log.reload
expect(case_log.housingneeds_a).to eq("No")
expect(case_log.housingneeds_b).to eq("No")
expect(case_log.housingneeds_c).to eq("Yes")
end
context "given a page with checkbox and non-checkbox questions" do
let(:tenant_code) { "BZ355" }
let(:case_log_form_params) do
{ accessibility_requirements:
%w[ housingneeds_a
housingneeds_b
housingneeds_c],
tenant_code: tenant_code,
page: "accessibility_requirements" }
end
let(:questions_for_page) do
[
Form::Question.new(
"accessibility_requirements",
{
"type" => "checkbox",
"answer_options" =>
{ "housingneeds_a" => "Fully wheelchair accessible housing",
"housingneeds_b" => "Wheelchair access to essential rooms",
"housingneeds_c" => "Level access housing",
"housingneeds_f" => "Other disability requirements",
"housingneeds_g" => "No disability requirements",
"divider_a" => true,
"housingneeds_h" => "Do not know",
"divider_b" => true,
"accessibility_requirements_prefer_not_to_say" => "Prefer not to say" },
}, nil
),
Form::Question.new("tenant_code", { "type" => "text" }, nil),
]
end
it "updates both question fields" do
allow_any_instance_of(Form::Page).to receive(:expected_responses).and_return(questions_for_page)
post :submit_form, params: { id: id, case_log: case_log_form_params }
case_log.reload
expect(case_log.housingneeds_a).to eq("Yes")
expect(case_log.housingneeds_b).to eq("Yes")
expect(case_log.housingneeds_c).to eq("Yes")
expect(case_log.tenant_code).to eq(tenant_code)
end
end
context "conditional routing" do
before do
allow_any_instance_of(CaseLogValidator).to receive(:validate_pregnancy).and_return(true)
end
let(:case_log_form_conditional_question_yes_params) do
{
preg_occ: "Yes",
page: "conditional_question",
}
end
let(:case_log_form_conditional_question_no_params) do
{
preg_occ: "No",
page: "conditional_question",
}
end
it "routes to the appropriate conditional page based on the question answer of the current page" do
post :submit_form, params: { id: id, case_log: case_log_form_conditional_question_yes_params }
expect(response).to redirect_to("/case-logs/#{id}/conditional-question-yes-page")
post :submit_form, params: { id: id, case_log: case_log_form_conditional_question_no_params }
expect(response).to redirect_to("/case-logs/#{id}/conditional-question-no-page")
end
end
end
end

2
spec/factories/case_log.rb

@ -52,7 +52,7 @@ FactoryBot.define do
startertenancy { "No" } startertenancy { "No" }
tenancylength { 5 } tenancylength { 5 }
tenancy { "Secure (including flexible)" } tenancy { "Secure (including flexible)" }
lettype { "Affordable Rent General Needs LA" } lettype { "Affordable Rent General needs LA" }
landlord { "This landlord" } landlord { "This landlord" }
previous_postcode { "SE2 6RT" } previous_postcode { "SE2 6RT" }
rsnvac { "Tenant abandoned property" } rsnvac { "Tenant abandoned property" }

2
spec/fixtures/complete_case_log.json vendored

@ -127,7 +127,7 @@
"sale_or_letting": "", "sale_or_letting": "",
"rent_type": "Social Rent", "rent_type": "Social Rent",
"intermediate_rent_product_name": "", "intermediate_rent_product_name": "",
"needstype": "General Needs", "needstype": "General needs",
"sale_completion_date": "01/01/2020", "sale_completion_date": "01/01/2020",
"purchaser_code": "", "purchaser_code": "",
"propcode": "123", "propcode": "123",

24
spec/models/case_log_spec.rb

@ -790,6 +790,24 @@ RSpec.describe Form, type: :model do
}.not_to raise_error }.not_to raise_error
end end
end end
context "Validate type of unit" do
it "Cannot be bedsit if no of bedrooms is greater than 1" do
expect {
CaseLog.create!(unittype_gn: "Bed-sit",
beds: 2,
owning_organisation: owning_organisation,
managing_organisation: managing_organisation)
}.to raise_error(ActiveRecord::RecordInvalid)
expect {
CaseLog.create!(unittype_gn: "Bed-sit",
beds: 1,
owning_organisation: owning_organisation,
managing_organisation: managing_organisation)
}.not_to raise_error
end
end
end end
describe "status" do describe "status" do
@ -850,8 +868,8 @@ RSpec.describe Form, type: :model do
# rubocop:enable Style/DateTime # rubocop:enable Style/DateTime
net_income_known: "Prefer not to say", net_income_known: "Prefer not to say",
other_hhmemb: 6, other_hhmemb: 6,
rent_type: "London Living Rent", rent_type: "London living rent",
needstype: "General Needs", needstype: "General needs",
}) })
end end
@ -909,7 +927,7 @@ RSpec.describe Form, type: :model do
case_log.reload case_log.reload
record_from_db = ActiveRecord::Base.connection.execute("select lettype from case_logs where id=#{case_log.id}").to_a[0] record_from_db = ActiveRecord::Base.connection.execute("select lettype from case_logs where id=#{case_log.id}").to_a[0]
expect(case_log.lettype).to eq("Intermediate Rent General Needs PRP") expect(case_log.lettype).to eq("Intermediate Rent General needs PRP")
expect(record_from_db["lettype"]).to eq(9) expect(record_from_db["lettype"]).to eq(9)
end end
end end

91
spec/requests/bulk_upload_controller_spec.rb

@ -2,62 +2,89 @@ require "rails_helper"
RSpec.describe BulkUploadController, type: :request do RSpec.describe BulkUploadController, type: :request do
let(:url) { "/case-logs/bulk-upload" } let(:url) { "/case-logs/bulk-upload" }
let(:organisation) { FactoryBot.create(:organisation) } let(:user) { FactoryBot.create(:user) }
let(:organisation) { user.organisation }
before do before do
allow(Organisation).to receive(:find).with(107_242).and_return(organisation) allow(Organisation).to receive(:find).with(107_242).and_return(organisation)
end end
describe "GET #show" do context "a not signed in user" do
before do describe "GET #show" do
get url, params: {} it "does not let you see the bulk upload page" do
get url, headers: headers, params: {}
expect(response).to redirect_to("/users/sign-in")
end
end end
it "returns a success response" do describe "POST #bulk upload" do
expect(response).to be_successful before do
end @file = fixture_file_upload("2021_22_lettings_bulk_upload.xlsx", "application/vnd.ms-excel")
end
it "returns a page with a file upload form" do it "does not let you submit bulk uploads" do
expect(response.body).to match(/<input id="bulk-upload-case-log-bulk-upload-field" class="govuk-file-upload"/) post url, params: { bulk_upload: { case_log_bulk_upload: @file } }
expect(response.body).to match(/<button type="submit" formnovalidate="formnovalidate" class="govuk-button"/) expect(response).to redirect_to("/users/sign-in")
end
end end
end end
describe "POST #bulk upload" do context "a signed in user" do
subject { post url, params: { bulk_upload: { case_log_bulk_upload: @file } } } before do
sign_in user
end
context "given a valid file based on the upload template" do describe "GET #show" do
before do before do
@file = fixture_file_upload("2021_22_lettings_bulk_upload.xlsx", "application/vnd.ms-excel") get url, params: {}
end end
it "creates case logs for each row in the template" do it "returns a success response" do
expect { subject }.to change(CaseLog, :count).by(9) expect(response).to be_successful
end end
it "redirects to the case log index page" do it "returns a page with a file upload form" do
expect(subject).to redirect_to(case_logs_path) expect(response.body).to match(/<input id="bulk-upload-case-log-bulk-upload-field" class="govuk-file-upload"/)
expect(response.body).to match(/<button type="submit" formnovalidate="formnovalidate" class="govuk-button"/)
end end
end end
context "given an invalid file type" do describe "POST #bulk upload" do
before do subject { post url, params: { bulk_upload: { case_log_bulk_upload: @file } } }
@file = fixture_file_upload("random.txt", "text/plain")
subject context "given a valid file based on the upload template" do
end before do
@file = fixture_file_upload("2021_22_lettings_bulk_upload.xlsx", "application/vnd.ms-excel")
end
it "creates case logs for each row in the template" do
expect { subject }.to change(CaseLog, :count).by(9)
end
it "displays an error message" do it "redirects to the case log index page" do
expect(response.body).to match(/Invalid file type/) expect(subject).to redirect_to(case_logs_path)
end
end end
end
context "given an empty file" do context "given an invalid file type" do
before do before do
@file = fixture_file_upload("2021_22_lettings_bulk_upload_empty.xlsx", "application/vnd.ms-excel") @file = fixture_file_upload("random.txt", "text/plain")
subject subject
end
it "displays an error message" do
expect(response.body).to match(/Invalid file type/)
end
end end
it "displays an error message" do context "given an empty file" do
expect(response.body).to match(/No data found/) before do
@file = fixture_file_upload("2021_22_lettings_bulk_upload_empty.xlsx", "application/vnd.ms-excel")
subject
end
it "displays an error message" do
expect(response.body).to match(/No data found/)
end
end end
end end
end end

200
spec/requests/case_log_controller_spec.rb

@ -180,84 +180,63 @@ RSpec.describe CaseLogsController, type: :request do
allow(FormHandler.instance).to receive(:get_form).and_return(form) allow(FormHandler.instance).to receive(:get_form).and_return(form)
end end
context "case logs that are owned or managed by your organisation" do context "a user that is not signed in" do
before do it "does not let the user get case log tasklist pages they don't have access to" do
sign_in user
get "/case-logs/#{case_log.id}", headers: headers, params: {} get "/case-logs/#{case_log.id}", headers: headers, params: {}
end expect(response).to redirect_to("/users/sign-in")
it "shows the tasklist for case logs you have access to" do
expect(response.body).to match("Case log")
expect(response.body).to match(case_log.id.to_s)
end
it "displays a section status for a case log" do
assert_select ".govuk-tag", text: /Not started/, count: 8
assert_select ".govuk-tag", text: /Completed/, count: 0
assert_select ".govuk-tag", text: /Cannot start yet/, count: 1
end
end
context "case log with a single section complete" do
let(:section_completed_case_log) do
FactoryBot.create(
:case_log,
:conditional_section_complete,
owning_organisation: organisation,
managing_organisation: organisation,
)
end
before do
sign_in user
get "/case-logs/#{section_completed_case_log.id}", headers: headers, params: {}
end
it "displays a section status for a case log" do
assert_select ".govuk-tag", text: /Not started/, count: 7
assert_select ".govuk-tag", text: /Completed/, count: 1
assert_select ".govuk-tag", text: /Cannot start yet/, count: 1
end end
end end
context "case logs that are not owned or managed by your organisation" do context "a signed in user" do
before do context "case logs that are owned or managed by your organisation" do
sign_in user before do
get "/case-logs/#{unauthorized_case_log.id}", headers: headers, params: {} sign_in user
get "/case-logs/#{case_log.id}", headers: headers, params: {}
end
it "shows the tasklist for case logs you have access to" do
expect(response.body).to match("Case log")
expect(response.body).to match(case_log.id.to_s)
end
it "displays a section status for a case log" do
assert_select ".govuk-tag", text: /Not started/, count: 8
assert_select ".govuk-tag", text: /Completed/, count: 0
assert_select ".govuk-tag", text: /Cannot start yet/, count: 1
end
end end
it "does not show the tasklist for case logs you don't have access to" do context "case log with a single section complete" do
expect(response).to have_http_status(:not_found) let(:section_completed_case_log) do
FactoryBot.create(
:case_log,
:conditional_section_complete,
owning_organisation: organisation,
managing_organisation: organisation,
)
end
before do
sign_in user
get "/case-logs/#{section_completed_case_log.id}", headers: headers, params: {}
end
it "displays a section status for a case log" do
assert_select ".govuk-tag", text: /Not started/, count: 7
assert_select ".govuk-tag", text: /Completed/, count: 1
assert_select ".govuk-tag", text: /Cannot start yet/, count: 1
end
end end
end
end
context "form pages" do context "case logs that are not owned or managed by your organisation" do
let(:headers) { { "Accept" => "text/html" } } before do
sign_in user
get "/case-logs/#{unauthorized_case_log.id}", headers: headers, params: {}
end
context "case logs that are not owned or managed by your organisation" do it "does not show the tasklist for case logs you don't have access to" do
before do expect(response).to have_http_status(:not_found)
sign_in user end
get "/case-logs/#{unauthorized_case_log.id}/person-1-age", headers: headers, params: {}
end
it "does not show form pages for case logs you don't have access to" do
expect(response).to have_http_status(:not_found)
end
end
end
context "check answers pages" do
let(:headers) { { "Accept" => "text/html" } }
context "case logs that are not owned or managed by your organisation" do
before do
sign_in user
get "/case-logs/#{unauthorized_case_log.id}/household-characteristics/check-answers", headers: headers, params: {}
end
it "does not show a check answers for case logs you don't have access to" do
expect(response).to have_http_status(:not_found)
end end
end end
end end
@ -414,87 +393,4 @@ RSpec.describe CaseLogsController, type: :request do
end end
end end
end end
describe "Submit Form" do
let(:user) { FactoryBot.create(:user) }
let(:form) { Form.new("spec/fixtures/forms/test_form.json") }
let(:organisation) { user.organisation }
let(:case_log) do
FactoryBot.create(
:case_log,
owning_organisation: organisation,
managing_organisation: organisation,
)
end
let(:page_id) { "person_1_age" }
let(:params) do
{
id: case_log.id,
case_log: {
page: page_id,
age1: answer,
},
}
end
before do
allow(FormHandler.instance).to receive(:get_form).and_return(form)
sign_in user
post "/case-logs/#{case_log.id}/form", params: params
end
context "invalid answers" do
let(:answer) { 2000 }
it "re-renders the same page with errors if validation fails" do
expect(response).to have_http_status(:unprocessable_entity)
end
end
context "valid answers" do
let(:answer) { 20 }
it "re-renders the same page with errors if validation fails" do
expect(response).to have_http_status(:redirect)
end
let(:params) do
{
id: case_log.id,
case_log: {
page: page_id,
age1: answer,
age2: 2000,
},
}
end
it "only updates answers that apply to the page being submitted" do
case_log.reload
expect(case_log.age1).to eq(answer)
expect(case_log.age2).to be nil
end
end
context "case logs that are not owned or managed by your organisation" do
let(:answer) { 25 }
let(:other_organisation) { FactoryBot.create(:organisation) }
let(:unauthorized_case_log) do
FactoryBot.create(
:case_log,
owning_organisation: other_organisation,
managing_organisation: other_organisation,
)
end
before do
sign_in user
post "/case-logs/#{unauthorized_case_log.id}/form", params: params
end
it "does not let you post form answers to case logs you don't have access to" do
expect(response).to have_http_status(:not_found)
end
end
end
end end

278
spec/requests/form_controller_spec.rb

@ -0,0 +1,278 @@
require "rails_helper"
RSpec.describe FormController, type: :request do
let(:user) { FactoryBot.create(:user) }
let(:organisation) { user.organisation }
let(:other_organisation) { FactoryBot.create(:organisation) }
let!(:case_log) do
FactoryBot.create(
:case_log,
owning_organisation: organisation,
managing_organisation: organisation,
)
end
let!(:unauthorized_case_log) do
FactoryBot.create(
:case_log,
owning_organisation: other_organisation,
managing_organisation: other_organisation,
)
end
let(:headers) { { "Accept" => "text/html" } }
context "a not signed in user" do
describe "GET" do
it "does not let you get case logs pages you don't have access to" do
get "/case-logs/#{case_log.id}/person-1-age", headers: headers, params: {}
expect(response).to redirect_to("/users/sign-in")
end
it "does not let you get case log check answer pages you don't have access to" do
get "/case-logs/#{case_log.id}/household-characteristics/check-answers", headers: headers, params: {}
expect(response).to redirect_to("/users/sign-in")
end
end
describe "POST" do
it "does not let you post form answers to case logs you don't have access to" do
post "/case-logs/#{case_log.id}/form", params: {}
expect(response).to redirect_to("/users/sign-in")
end
end
end
context "a signed in user" do
before do
sign_in user
end
describe "GET" do
context "form pages" do
context "case logs that are not owned or managed by your organisation" do
it "does not show form pages for case logs you don't have access to" do
get "/case-logs/#{unauthorized_case_log.id}/person-1-age", headers: headers, params: {}
expect(response).to have_http_status(:not_found)
end
end
end
context "check answers pages" do
context "case logs that are not owned or managed by your organisation" do
it "does not show a check answers for case logs you don't have access to" do
get "/case-logs/#{unauthorized_case_log.id}/household-characteristics/check-answers", headers: headers, params: {}
expect(response).to have_http_status(:not_found)
end
end
end
end
describe "Submit Form" do
context "a form page" do
let(:user) { FactoryBot.create(:user) }
let(:form) { Form.new("spec/fixtures/forms/test_form.json") }
let(:organisation) { user.organisation }
let(:case_log) do
FactoryBot.create(
:case_log,
owning_organisation: organisation,
managing_organisation: organisation,
)
end
let(:page_id) { "person_1_age" }
let(:params) do
{
id: case_log.id,
case_log: {
page: page_id,
age1: answer,
},
}
end
before do
allow(FormHandler.instance).to receive(:get_form).and_return(form)
post "/case-logs/#{case_log.id}/form", params: params
end
context "invalid answers" do
let(:answer) { 2000 }
it "re-renders the same page with errors if validation fails" do
expect(response).to have_http_status(:unprocessable_entity)
end
end
context "valid answers" do
let(:answer) { 20 }
it "re-renders the same page with errors if validation fails" do
expect(response).to have_http_status(:redirect)
end
let(:params) do
{
id: case_log.id,
case_log: {
page: page_id,
age1: answer,
age2: 2000,
},
}
end
it "only updates answers that apply to the page being submitted" do
case_log.reload
expect(case_log.age1).to eq(answer)
expect(case_log.age2).to be nil
end
end
end
context "checkbox questions" do
let(:case_log_form_params) do
{
id: case_log.id,
case_log: {
page: "accessibility_requirements",
accessibility_requirements:
%w[ housingneeds_a
housingneeds_b
housingneeds_c],
},
}
end
let(:new_case_log_form_params) do
{
id: case_log.id,
case_log: {
page: "accessibility_requirements",
accessibility_requirements: %w[housingneeds_c],
},
}
end
it "sets checked items to true" do
post "/case-logs/#{case_log.id}/form", params: case_log_form_params
case_log.reload
expect(case_log.housingneeds_a).to eq("Yes")
expect(case_log.housingneeds_b).to eq("Yes")
expect(case_log.housingneeds_c).to eq("Yes")
end
it "sets previously submitted items to false when resubmitted with new values" do
post "/case-logs/#{case_log.id}/form", params: new_case_log_form_params
case_log.reload
expect(case_log.housingneeds_a).to eq("No")
expect(case_log.housingneeds_b).to eq("No")
expect(case_log.housingneeds_c).to eq("Yes")
end
context "given a page with checkbox and non-checkbox questions" do
let(:tenant_code) { "BZ355" }
let(:case_log_form_params) do
{
id: case_log.id,
case_log: {
page: "accessibility_requirements",
accessibility_requirements:
%w[ housingneeds_a
housingneeds_b
housingneeds_c],
tenant_code: tenant_code,
},
}
end
let(:questions_for_page) do
[
Form::Question.new(
"accessibility_requirements",
{
"type" => "checkbox",
"answer_options" =>
{ "housingneeds_a" => "Fully wheelchair accessible housing",
"housingneeds_b" => "Wheelchair access to essential rooms",
"housingneeds_c" => "Level access housing",
"housingneeds_f" => "Other disability requirements",
"housingneeds_g" => "No disability requirements",
"divider_a" => true,
"housingneeds_h" => "Do not know",
"divider_b" => true,
"accessibility_requirements_prefer_not_to_say" => "Prefer not to say" },
}, nil
),
Form::Question.new("tenant_code", { "type" => "text" }, nil),
]
end
it "updates both question fields" do
allow_any_instance_of(Form::Page).to receive(:expected_responses).and_return(questions_for_page)
post "/case-logs/#{case_log.id}/form", params: case_log_form_params
case_log.reload
expect(case_log.housingneeds_a).to eq("Yes")
expect(case_log.housingneeds_b).to eq("Yes")
expect(case_log.housingneeds_c).to eq("Yes")
expect(case_log.tenant_code).to eq(tenant_code)
end
end
end
context "conditional routing" do
before do
allow_any_instance_of(CaseLogValidator).to receive(:validate_pregnancy).and_return(true)
end
let(:case_log_form_conditional_question_yes_params) do
{
id: case_log.id,
case_log: {
page: "conditional_question",
preg_occ: "Yes",
},
}
end
let(:case_log_form_conditional_question_no_params) do
{
id: case_log.id,
case_log: {
page: "conditional_question",
preg_occ: "No",
},
}
end
it "routes to the appropriate conditional page based on the question answer of the current page" do
post "/case-logs/#{case_log.id}/form", params: case_log_form_conditional_question_yes_params
expect(response).to redirect_to("/case-logs/#{case_log.id}/conditional-question-yes-page")
post "/case-logs/#{case_log.id}/form", params: case_log_form_conditional_question_no_params
expect(response).to redirect_to("/case-logs/#{case_log.id}/conditional-question-no-page")
end
end
context "case logs that are not owned or managed by your organisation" do
let(:answer) { 25 }
let(:other_organisation) { FactoryBot.create(:organisation) }
let(:unauthorized_case_log) do
FactoryBot.create(
:case_log,
owning_organisation: other_organisation,
managing_organisation: other_organisation,
)
end
before do
post "/case-logs/#{unauthorized_case_log.id}/form", params: {}
end
it "does not let you post form answers to case logs you don't have access to" do
expect(response).to have_http_status(:not_found)
end
end
end
end
end

233
spec/requests/organisations_controller_spec.rb

@ -2,110 +2,181 @@ require "rails_helper"
RSpec.describe OrganisationsController, type: :request do RSpec.describe OrganisationsController, type: :request do
let(:organisation) { user.organisation } let(:organisation) { user.organisation }
let(:unauthorised_organisation) { FactoryBot.create(:organisation) }
let(:headers) { { "Accept" => "text/html" } } let(:headers) { { "Accept" => "text/html" } }
let(:page) { Capybara::Node::Simple.new(response.body) } let(:page) { Capybara::Node::Simple.new(response.body) }
let(:user) { FactoryBot.create(:user, :data_coordinator) }
describe "#show" do context "a not signed in user" do
let(:user) { FactoryBot.create(:user, :data_coordinator) } describe "#show" do
it "does not let you see organisation details from org route" do
before do get "/organisations/#{organisation.id}", headers: headers, params: {}
sign_in user expect(response).to redirect_to("/users/sign-in")
get "/organisations/#{organisation.id}", headers: headers, params: {}
end
it "redirects to details" do
expect(response).to have_http_status(:redirect)
end
end
context "As a data coordinator user" do
let(:user) { FactoryBot.create(:user, :data_coordinator) }
context "details tab" do
before do
sign_in user
get "/organisations/#{organisation.id}/details", headers: headers, params: {}
end
it "shows the tab navigation" do
expected_html = "<nav class=\"app-tab-navigation\""
expect(response.body).to include(expected_html)
end end
it "shows a summary list of org details" do it "does not let you see organisation details from details route" do
expected_html = "<dl class=\"govuk-summary-list\"" get "/organisations/#{organisation.id}/details", headers: headers, params: {}
expect(response.body).to include(expected_html) expect(response).to redirect_to("/users/sign-in")
expect(response.body).to include(organisation.name)
end
it "has a hidden header title" do
expected_html = "<h2 class=\"govuk-visually-hidden\"> Details"
expect(response.body).to include(expected_html)
end end
end
context "users tab" do it "does not let you see organisation users" do
before do
sign_in user
get "/organisations/#{organisation.id}/users", headers: headers, params: {} get "/organisations/#{organisation.id}/users", headers: headers, params: {}
end expect(response).to redirect_to("/users/sign-in")
it "shows the tab navigation" do
expected_html = "<nav class=\"app-tab-navigation\""
expect(response.body).to include(expected_html)
end
it "shows a new user button" do
expect(page).to have_link("Invite user")
end
it "shows a table of users" do
expected_html = "<table class=\"govuk-table\""
expect(response.body).to include(expected_html)
expect(response.body).to include(user.email)
end
it "has a hidden header title" do
expected_html = "<h2 class=\"govuk-visually-hidden\"> Users"
expect(response.body).to include(expected_html)
end end
end end
end end
context "As a data provider user" do context "a signed in user" do
let(:user) { FactoryBot.create(:user) } describe "#show" do
context "organisation that the user belongs to" do
context "details tab" do before do
before do sign_in user
sign_in user get "/organisations/#{organisation.id}", headers: headers, params: {}
get "/organisations/#{organisation.id}/details", headers: headers, params: {} end
it "redirects to details" do
expect(response).to have_http_status(:redirect)
end
end end
it "shows the tab navigation" do context "organisation that are not in scope for the user, i.e. that they do not belong to" do
expected_html = "<nav class=\"app-tab-navigation\"" before do
expect(response.body).to include(expected_html) sign_in user
get "/organisations/#{unauthorised_organisation.id}", headers: headers, params: {}
end
it "returns not found 404 from org route" do
expect(response).to have_http_status(:not_found)
end
end end
end
it "shows a summary list of org details" do context "As a data coordinator user" do
expected_html = "<dl class=\"govuk-summary-list\"" context "details tab" do
expect(response.body).to include(expected_html) context "organisation that the user belongs to" do
expect(response.body).to include(organisation.name) before do
sign_in user
get "/organisations/#{organisation.id}/details", headers: headers, params: {}
end
it "shows the tab navigation" do
expected_html = "<nav class=\"app-tab-navigation\""
expect(response.body).to include(expected_html)
end
it "shows a summary list of org details" do
expected_html = "<dl class=\"govuk-summary-list\""
expect(response.body).to include(expected_html)
expect(response.body).to include(organisation.name)
end
it "has a hidden header title" do
expected_html = "<h2 class=\"govuk-visually-hidden\"> Details"
expect(response.body).to include(expected_html)
end
end
context "organisation that are not in scope for the user, i.e. that they do not belong to" do
before do
sign_in user
get "/organisations/#{unauthorised_organisation.id}/details", headers: headers, params: {}
end
it "returns not found 404 from org details route" do
expect(response).to have_http_status(:not_found)
end
end
end end
it "has a hidden header title" do context "users tab" do
expected_html = "<h2 class=\"govuk-visually-hidden\"> Details" context "organisation that the user belongs to" do
expect(response.body).to include(expected_html) before do
sign_in user
get "/organisations/#{organisation.id}/users", headers: headers, params: {}
end
it "shows the tab navigation" do
expected_html = "<nav class=\"app-tab-navigation\""
expect(response.body).to include(expected_html)
end
it "shows a new user button" do
expect(page).to have_link("Invite user")
end
it "shows a table of users" do
expected_html = "<table class=\"govuk-table\""
expect(response.body).to include(expected_html)
expect(response.body).to include(user.email)
end
it "has a hidden header title" do
expected_html = "<h2 class=\"govuk-visually-hidden\"> Users"
expect(response.body).to include(expected_html)
end
end
context "organisation that are not in scope for the user, i.e. that they do not belong to" do
before do
sign_in user
get "/organisations/#{unauthorised_organisation.id}/users", headers: headers, params: {}
end
it "returns not found 404 from users page" do
expect(response).to have_http_status(:not_found)
end
end
end end
end end
context "users tab" do context "As a data provider user" do
before do let(:user) { FactoryBot.create(:user) }
sign_in user
get "/organisations/#{organisation.id}/users", headers: headers, params: {} context "details tab" do
context "organisation that the user belongs to" do
before do
sign_in user
get "/organisations/#{organisation.id}/details", headers: headers, params: {}
end
it "shows the tab navigation" do
expected_html = "<nav class=\"app-tab-navigation\""
expect(response.body).to include(expected_html)
end
it "shows a summary list of org details" do
expected_html = "<dl class=\"govuk-summary-list\""
expect(response.body).to include(expected_html)
expect(response.body).to include(organisation.name)
end
it "has a hidden header title" do
expected_html = "<h2 class=\"govuk-visually-hidden\"> Details"
expect(response.body).to include(expected_html)
end
end
context "organisation that are not in scope for the user, i.e. that they do not belong to" do
before do
sign_in user
get "/organisations/#{unauthorised_organisation.id}/details", headers: headers, params: {}
end
it "returns not found 404" do
expect(response).to have_http_status(:not_found)
end
end
end end
it "should return unauthorised 401" do context "users tab" do
expect(response).to have_http_status(:unauthorized) before do
sign_in user
get "/organisations/#{organisation.id}/users", headers: headers, params: {}
end
it "should return unauthorized 401" do
expect(response).to have_http_status(:unauthorized)
end
end end
end end
end end

57
spec/requests/soft_validations_controller_spec.rb

@ -3,36 +3,51 @@ require "rails_helper"
RSpec.describe SoftValidationsController, type: :request do RSpec.describe SoftValidationsController, type: :request do
let(:params) { { case_log_id: case_log.id } } let(:params) { { case_log_id: case_log.id } }
let(:url) { "/case-logs/#{case_log.id}/net-income/soft-validations" } let(:url) { "/case-logs/#{case_log.id}/net-income/soft-validations" }
let(:user) { FactoryBot.create(:user) }
before do context "a not signed in user" do
get url, params: {} let(:case_log) { FactoryBot.create(:case_log, :in_progress) }
end
describe "GET #show" do
context "Soft validation overide required" do
let(:case_log) { FactoryBot.create(:case_log, :soft_validations_triggered) }
it "returns a success response" do describe "GET #show" do
expect(response).to be_successful it "redirects to the sign in page" do
get url, headers: headers, params: {}
expect(response).to redirect_to("/users/sign-in")
end end
end
end
it "returns a json with the soft validation fields" do context "a signed in user" do
json_response = JSON.parse(response.body) before do
expect(json_response["show"]).to eq(true) sign_in user
expect(json_response["label"]).to match(/Are you sure this is correct?/) get url, params: {}
end
end end
context "Soft validation overide not required" do describe "GET #show" do
let(:case_log) { FactoryBot.create(:case_log, :in_progress) } context "Soft validation overide required" do
let(:case_log) { FactoryBot.create(:case_log, :soft_validations_triggered) }
it "returns a success response" do
expect(response).to be_successful
end
it "returns a success response" do it "returns a json with the soft validation fields" do
expect(response).to be_successful json_response = JSON.parse(response.body)
expect(json_response["show"]).to eq(true)
expect(json_response["label"]).to match(/Are you sure this is correct?/)
end
end end
it "returns a json with the soft validation fields" do context "Soft validation overide not required" do
json_response = JSON.parse(response.body) let(:case_log) { FactoryBot.create(:case_log, :in_progress) }
expect(json_response["show"]).to eq(false)
it "returns a success response" do
expect(response).to be_successful
end
it "returns a json with the soft validation fields" do
json_response = JSON.parse(response.body)
expect(json_response["show"]).to eq(false)
end
end end
end end
end end

129
spec/requests/user_controller_spec.rb

@ -3,39 +3,138 @@ require_relative "../support/devise"
RSpec.describe UsersController, type: :request do RSpec.describe UsersController, type: :request do
let(:user) { FactoryBot.create(:user) } let(:user) { FactoryBot.create(:user) }
let(:unauthorised_user) { FactoryBot.create(:user) }
let(:headers) { { "Accept" => "text/html" } } let(:headers) { { "Accept" => "text/html" } }
let(:page) { Capybara::Node::Simple.new(response.body) } let(:page) { Capybara::Node::Simple.new(response.body) }
let(:new_value) { "new test name" }
let(:params) { { id: user.id, user: { name: new_value } } }
context "a not signed in user" do
describe "#show" do
it "does not let you see user details" do
get "/users/#{user.id}", headers: headers, params: {}
expect(response).to redirect_to("/users/sign-in")
end
end
describe "#edit" do
it "does not let you edit user details" do
get "/users/#{user.id}/edit", headers: headers, params: {}
expect(response).to redirect_to("/users/sign-in")
end
end
describe "#password" do
it "does not let you edit user passwords" do
get "/users/#{user.id}/password/edit", headers: headers, params: {}
expect(response).to redirect_to("/users/sign-in")
end
end
describe "#patch" do
it "does not let you update user details" do
patch "/case-logs/#{user.id}", params: {}
expect(response).to redirect_to("/users/sign-in")
end
end
end
describe "#show" do describe "#show" do
before do context "current user is user" do
sign_in user before do
get "/users/#{user.id}", headers: headers, params: {} sign_in user
get "/users/#{user.id}", headers: headers, params: {}
end
it "show the user details" do
expect(page).to have_content("Your account")
end
end end
it "show the user details" do context "current user is another user" do
expect(page).to have_content("Your account") before do
sign_in user
get "/users/#{unauthorised_user.id}", headers: headers, params: {}
end
it "returns not found 404" do
expect(response).to have_http_status(:not_found)
end
end end
end end
describe "#edit" do describe "#edit" do
before do context "current user is user" do
sign_in user before do
get "/users/#{user.id}/edit", headers: headers, params: {} sign_in user
get "/users/#{user.id}/edit", headers: headers, params: {}
end
it "show the edit personal details page" do
expect(page).to have_content("Change your personal details")
end
end end
it "show the edit personal details page" do context "current user is another user" do
expect(page).to have_content("Change your personal details") before do
sign_in user
get "/users/#{unauthorised_user.id}/edit", headers: headers, params: {}
end
it "returns not found 404" do
expect(response).to have_http_status(:not_found)
end
end end
end end
describe "#edit_password" do describe "#edit_password" do
before do context "current user is user" do
sign_in user before do
get "/users/#{user.id}/password/edit", headers: headers, params: {} sign_in user
get "/users/#{user.id}/password/edit", headers: headers, params: {}
end
it "show the edit password page" do
expect(page).to have_content("Change your password")
end
end
context "current user is another user" do
before do
sign_in user
get "/users/#{unauthorised_user.id}/edit", headers: headers, params: {}
end
it "returns not found 404" do
expect(response).to have_http_status(:not_found)
end
end end
end
describe "#update" do
context "current user is user" do
before do
sign_in user
patch "/users/#{user.id}", headers: headers, params: params
end
it "updates the user" do
user.reload
expect(user.name).to eq(new_value)
end
end
context "current user is another user" do
let(:params) { { id: unauthorised_user.id, user: { name: new_value } } }
before do
sign_in user
patch "/users/#{unauthorised_user.id}", headers: headers, params: params
end
it "show the edit password page" do it "returns not found 404" do
expect(page).to have_content("Change your password") expect(response).to have_http_status(:not_found)
end
end end
end end
end end

Loading…
Cancel
Save