require " rails_helper "
RSpec . describe FormController , type : :request do
let ( :page ) { Capybara :: Node :: Simple . new ( response . body ) }
let ( :user ) { FactoryBot . create ( :user ) }
let ( :organisation ) { user . organisation }
let ( :other_organisation ) { FactoryBot . create ( :organisation ) }
let! ( :lettings_log ) do
FactoryBot . create (
:lettings_log ,
owning_organisation : organisation ,
managing_organisation : organisation ,
)
end
let! ( :unauthorized_lettings_log ) do
FactoryBot . create (
:lettings_log ,
owning_organisation : other_organisation ,
managing_organisation : other_organisation ,
)
end
let ( :setup_complete_lettings_log ) do
FactoryBot . create (
:lettings_log ,
:about_completed ,
status : 1 ,
startdate : Time . zone . local ( 2021 , 10 , 10 ) ,
owning_organisation : organisation ,
managing_organisation : organisation ,
)
end
let ( :completed_lettings_log ) do
FactoryBot . create (
:lettings_log ,
:completed ,
owning_organisation : organisation ,
managing_organisation : organisation ,
)
end
let ( :headers ) { { " Accept " = > " text/html " } }
context " when a user is not signed in " do
describe " GET " do
it " does not let you get lettings logs pages you don't have access to " do
get " /logs/ #{ lettings_log . id } /person-1-age " , headers : headers , params : { }
expect ( response ) . to redirect_to ( " /account/sign-in " )
end
it " does not let you get lettings log check answer pages you don't have access to " do
get " /logs/ #{ lettings_log . id } /household-characteristics/check-answers " , headers : headers , params : { }
expect ( response ) . to redirect_to ( " /account/sign-in " )
end
end
describe " POST " do
it " does not let you post form answers to lettings logs you don't have access to " do
post " /logs/ #{ lettings_log . id } /form " , params : { }
expect ( response ) . to redirect_to ( " /account/sign-in " )
end
end
end
context " when a user is signed in " do
before do
allow ( user ) . to receive ( :need_two_factor_authentication? ) . and_return ( false )
sign_in user
end
describe " GET " do
context " with form pages " do
context " when forms exist for multiple years " do
let ( :lettings_log_year_1 ) { FactoryBot . create ( :lettings_log , startdate : Time . zone . local ( 2021 , 5 , 1 ) , owning_organisation : organisation , created_by : user ) }
let ( :lettings_log_year_2 ) { FactoryBot . create ( :lettings_log , :about_completed , startdate : Time . zone . local ( 2022 , 5 , 1 ) , owning_organisation : organisation , created_by : user ) }
it " displays the correct question details for each lettings log based on form year " do
get " /logs/ #{ lettings_log_year_1 . id } /tenant-code-test " , headers : headers , params : { }
expect ( response . body ) . to include ( " What is the tenant code? " )
get " /logs/ #{ lettings_log_year_2 . id } /tenant-code-test " , headers : headers , params : { }
expect ( response . body ) . to match ( " Different question header text for this year - 2023 " )
end
end
context " when lettings logs are not owned or managed by your organisation " do
it " does not show form pages for lettings logs you don't have access to " do
get " /logs/ #{ unauthorized_lettings_log . id } /person-1-age " , headers : headers , params : { }
expect ( response ) . to have_http_status ( :not_found )
end
end
context " with a form page that has custom guidance " do
it " displays the correct partial " do
get " /logs/ #{ lettings_log . id } /net-income " , headers : headers , params : { }
expect ( response . body ) . to match ( " What counts as income? " )
end
end
context " when viewing the setup section schemes page " do
context " when the user is support " do
let ( :user ) { FactoryBot . create ( :user , :support ) }
context " when organisation and user have not been selected yet " do
let ( :lettings_log ) do
FactoryBot . create (
:lettings_log ,
owning_organisation : nil ,
managing_organisation : nil ,
created_by : nil ,
needstype : 2 ,
)
end
before do
locations = FactoryBot . create_list ( :location , 5 )
locations . each { | location | location . scheme . update! ( arrangement_type : " The same organisation that owns the housing stock " , managing_organisation_id : location . scheme . owning_organisation_id ) }
end
it " returns an unfiltered list of schemes " do
get " /logs/ #{ lettings_log . id } /scheme " , headers : headers , params : { }
expect ( response . body . scan ( " <option value= " ) . count ) . to eq ( 6 )
end
end
end
end
end
context " when displaying check answers pages " do
context " when lettings logs are not owned or managed by your organisation " do
it " does not show a check answers for lettings logs you don't have access to " do
get " /logs/ #{ unauthorized_lettings_log . id } /household-characteristics/check-answers " , headers : headers , params : { }
expect ( response ) . to have_http_status ( :not_found )
end
end
context " when no other sections are enabled " do
let ( :lettings_log_2022 ) do
FactoryBot . create (
:lettings_log ,
startdate : Time . zone . local ( 2022 , 12 , 1 ) ,
owning_organisation : organisation ,
managing_organisation : organisation ,
)
end
let ( :headers ) { { " Accept " = > " text/html " } }
before do
Timecop . freeze ( Time . zone . local ( 2022 , 12 , 1 ) )
get " /logs/ #{ lettings_log_2022 . id } /setup/check-answers " , headers : headers , params : { }
end
after do
Timecop . unfreeze
end
it " does not show Save and go to next incomplete section button " do
expect ( page ) . not_to have_content ( " Save and go to next incomplete section " )
end
end
end
context " with a question in a section that isn't enabled yet " do
it " routes back to the tasklist page " do
get " /logs/ #{ lettings_log . id } /declaration " , headers : headers , params : { }
expect ( response ) . to redirect_to ( " /logs/ #{ lettings_log . id } " )
end
end
context " with a question that isn't enabled yet " do
it " routes back to the tasklist page " do
get " /logs/ #{ lettings_log . id } /conditional-question-no-second-page " , headers : headers , params : { }
expect ( response ) . to redirect_to ( " /logs/ #{ lettings_log . id } " )
end
end
context " when visiting the review page " do
it " renders the review page for the lettings log " do
get " /logs/ #{ setup_complete_lettings_log . id } /review " , headers : headers , params : { }
expect ( response . body ) . to match ( " Review lettings log " )
end
end
context " when viewing a user dependent page " do
context " when the dependency is met " do
let ( :user ) { FactoryBot . create ( :user , :support ) }
it " routes to the page " do
get " /logs/ #{ lettings_log . id } /organisation "
expect ( response ) . to have_http_status ( :ok )
end
end
context " when the dependency is not met " do
it " redirects to the tasklist page " do
get " /logs/ #{ lettings_log . id } /organisation "
expect ( response ) . to redirect_to ( " /logs/ #{ lettings_log . id } " )
end
end
end
end
describe " Submit Form " do
context " with a form page " do
let ( :user ) { FactoryBot . create ( :user ) }
let ( :organisation ) { user . organisation }
let ( :lettings_log ) do
FactoryBot . create (
:lettings_log ,
owning_organisation : organisation ,
managing_organisation : organisation ,
)
end
let ( :page_id ) { " person_1_age " }
let ( :params ) do
{
id : lettings_log . id ,
lettings_log : {
page : page_id ,
age1 : answer ,
} ,
}
end
let ( :valid_params ) do
{
id : lettings_log . id ,
lettings_log : {
page : page_id ,
age1 : valid_answer ,
} ,
}
end
context " with invalid answers " do
let ( :page ) { Capybara :: Node :: Simple . new ( response . body ) }
let ( :answer ) { 2000 }
let ( :valid_answer ) { 20 }
before do
allow ( Rails . logger ) . to receive ( :info )
end
it " re-renders the same page with errors if validation fails " do
post " /logs/ #{ lettings_log . id } /form " , params : params
expect ( response ) . to redirect_to ( " /logs/ #{ lettings_log . id } / #{ page_id . dasherize } " )
follow_redirect!
expect ( page ) . to have_content ( " There is a problem " )
end
it " resets errors when fixed " do
post " /logs/ #{ lettings_log . id } /form " , params : params
post " /logs/ #{ lettings_log . id } /form " , params : valid_params
get " /logs/ #{ lettings_log . id } / #{ page_id . dasherize } "
expect ( page ) . not_to have_content ( " There is a problem " )
end
it " logs that validation was triggered " do
expect ( Rails . logger ) . to receive ( :info ) . with ( " User triggered validation(s) on: age1 " ) . once
post " /logs/ #{ lettings_log . id } /form " , params : params
end
context " when the number of days is too high for the month " do
let ( :page_id ) { " tenancy_start_date " }
let ( :params ) do
{
id : lettings_log . id ,
lettings_log : {
page : page_id ,
" startdate(3i) " = > 31 ,
" startdate(2i) " = > 6 ,
" startdate(1i) " = > 2022 ,
} ,
}
end
it " validates the date correctly " do
post " /logs/ #{ lettings_log . id } /form " , params : params
follow_redirect!
expect ( page ) . to have_content ( " There is a problem " )
end
end
end
context " with valid answers " do
let ( :answer ) { 20 }
let ( :params ) do
{
id : lettings_log . id ,
lettings_log : {
page : page_id ,
age1 : answer ,
age2 : 2000 ,
} ,
}
end
before do
post " /logs/ #{ lettings_log . id } /form " , params :
end
it " re-renders the same page with errors if validation fails " do
expect ( response ) . to have_http_status ( :redirect )
end
it " only updates answers that apply to the page being submitted " do
lettings_log . reload
expect ( lettings_log . age1 ) . to eq ( answer )
expect ( lettings_log . age2 ) . to be nil
end
it " tracks who updated the record " do
lettings_log . reload
whodunnit_actor = lettings_log . versions . last . actor
expect ( whodunnit_actor ) . to be_a ( User )
expect ( whodunnit_actor . id ) . to eq ( user . id )
end
end
context " when the question has a conditional question " do
context " and the conditional question is not enabled " do
context " but is applicable because it has an inferred check answers display value " do
let ( :page_id ) { " property_postcode " }
let ( :valid_params ) do
{
id : lettings_log . id ,
lettings_log : {
page : page_id ,
postcode_known : " 0 " ,
postcode_full : " " ,
} ,
}
end
before do
lettings_log . update! ( postcode_known : 1 , postcode_full : " NW1 8RR " )
post " /logs/ #{ lettings_log . id } /form " , params : valid_params
end
it " does not require you to answer that question " do
expect ( response ) . to redirect_to ( " /logs/ #{ lettings_log . id } /do-you-know-the-local-authority " )
end
end
end
end
end
context " with checkbox questions " do
let ( :lettings_log_form_params ) do
{
id : lettings_log . id ,
lettings_log : {
page : " accessibility_requirements " ,
accessibility_requirements :
%w[ housingneeds_b ] ,
} ,
}
end
let ( :new_lettings_log_form_params ) do
{
id : lettings_log . id ,
lettings_log : {
page : " accessibility_requirements " ,
accessibility_requirements : %w[ housingneeds_c ] ,
} ,
}
end
it " sets checked items to true " do
post " /logs/ #{ lettings_log . id } /form " , params : lettings_log_form_params
lettings_log . reload
expect ( lettings_log . housingneeds_b ) . to eq ( 1 )
end
it " sets previously submitted items to false when resubmitted with new values " do
post " /logs/ #{ lettings_log . id } /form " , params : new_lettings_log_form_params
lettings_log . reload
expect ( lettings_log . housingneeds_b ) . to eq ( 0 )
expect ( lettings_log . housingneeds_c ) . to eq ( 1 )
end
context " with a page having checkbox and non-checkbox questions " do
let ( :tenant_code ) { " BZ355 " }
let ( :lettings_log_form_params ) do
{
id : lettings_log . id ,
lettings_log : {
page : " accessibility_requirements " ,
accessibility_requirements :
%w[ housingneeds_a
housingneeds_f ] ,
tenancycode : 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 " = > " Don’t know " } ,
} , nil
) ,
Form :: Question . new ( " tenancycode " , { " type " = > " text " } , nil ) ,
]
end
let ( :page ) { lettings_log . form . get_page ( " accessibility_requirements " ) }
it " updates both question fields " do
allow ( page ) . to receive ( :questions ) . and_return ( questions_for_page )
post " /logs/ #{ lettings_log . id } /form " , params : lettings_log_form_params
lettings_log . reload
expect ( lettings_log . housingneeds_a ) . to eq ( 1 )
expect ( lettings_log . housingneeds_f ) . to eq ( 1 )
expect ( lettings_log . tenancycode ) . to eq ( tenant_code )
end
end
end
context " with conditional routing " do
let ( :validator ) { lettings_log . _validators [ nil ] . first }
let ( :lettings_log_form_conditional_question_yes_params ) do
{
id : lettings_log . id ,
lettings_log : {
page : " conditional_question " ,
preg_occ : 1 ,
} ,
}
end
let ( :lettings_log_form_conditional_question_no_params ) do
{
id : lettings_log . id ,
lettings_log : {
page : " conditional_question " ,
preg_occ : 2 ,
} ,
}
end
let ( :lettings_log_form_conditional_question_wchair_yes_params ) do
{
id : lettings_log . id ,
lettings_log : {
page : " property_wheelchair_accessible " ,
wchair : 1 ,
} ,
}
end
before do
allow ( validator ) . to receive ( :validate_pregnancy ) . and_return ( true )
end
it " routes to the appropriate conditional page based on the question answer of the current page " do
post " /logs/ #{ lettings_log . id } /form " , params : lettings_log_form_conditional_question_yes_params
expect ( response ) . to redirect_to ( " /logs/ #{ lettings_log . id } /conditional-question-yes-page " )
post " /logs/ #{ lettings_log . id } /form " , params : lettings_log_form_conditional_question_no_params
expect ( response ) . to redirect_to ( " /logs/ #{ lettings_log . id } /conditional-question-no-page " )
end
it " routes to the page if at least one of the condition sets is met " do
post " /logs/ #{ lettings_log . id } /form " , params : lettings_log_form_conditional_question_wchair_yes_params
post " /logs/ #{ lettings_log . id } /form " , params : lettings_log_form_conditional_question_no_params
expect ( response ) . to redirect_to ( " /logs/ #{ lettings_log . id } /conditional-question-yes-page " )
end
end
context " when coming from check answers page " do
context " and navigating to an interruption screen " do
let ( :interrupt_params ) do
{
id : completed_lettings_log . id ,
lettings_log : {
page : " net_income_value_check " ,
net_income_value_check : value ,
} ,
}
end
let ( :referrer ) { " /logs/ #{ completed_lettings_log . id } /net-income-value-check?referrer=check_answers " }
before do
completed_lettings_log . update! ( ecstat1 : 1 , earnings : 130 , hhmemb : 1 ) # we're not routing to that page, so it gets cleared?§
allow ( completed_lettings_log ) . to receive ( :net_income_soft_validation_triggered? ) . and_return ( true )
post " /logs/ #{ completed_lettings_log . id } /form " , params : interrupt_params , headers : headers . merge ( { " HTTP_REFERER " = > referrer } )
end
context " when yes is answered " do
let ( :value ) { 0 }
it " redirects back to check answers if 'yes' is selected " do
expect ( response ) . to redirect_to ( " /logs/ #{ completed_lettings_log . id } /income-and-benefits/check-answers " )
end
end
context " when no is answered " do
let ( :value ) { 1 }
it " redirects to the previous question if 'no' is selected " do
expect ( response ) . to redirect_to ( " /logs/ #{ completed_lettings_log . id } /net-income?referrer=check_answers " )
end
end
end
end
context " with lettings logs that are not owned or managed by your organisation " do
let ( :answer ) { 25 }
let ( :other_organisation ) { FactoryBot . create ( :organisation ) }
let ( :unauthorized_lettings_log ) do
FactoryBot . create (
:lettings_log ,
owning_organisation : other_organisation ,
managing_organisation : other_organisation ,
)
end
before do
post " /logs/ #{ unauthorized_lettings_log . id } /form " , params : { }
end
it " does not let you post form answers to lettings logs you don't have access to " do
expect ( response ) . to have_http_status ( :not_found )
end
end
end
end
end